I have more info on this.
It only happens when I move my app to an AWS instance (new IP address, same url). At first I assumed it was due to a reverse DNS lookup not working, because of incomplete DNS propagation, but it persisted for more than 48 hours.
This morning, I moved it back to the original server it was on, and all worked fine again.
Is it possible that DNS results for reverse lookups are cached, and checked to prevent ARP poisoning attacks, or similar? That would make sense.
If so, is there a way around this?