This one catches so many people because the app works perfectly with curl from inside the container. A quick tell is running ss -ltnp inside the container: if the listener shows 127.0.0.1 instead of 0.0.0.0 or ::, you have found it. Worth noting too that some dev servers like Vite default to localhost and need the host flag set explicitly.