Your First Deploy: From Dockerfile to Live URL
Lesson 4 of 10: neo deploy builds, ships, health-checks, and switches traffic — the old version stays up the whole time.
What you need first
A project with a Dockerfile that EXPOSEs a port. That's the whole prerequisite — no .neo.yml required yet (that's next lesson).
Deploy it
cd my-app
neo deploy
or set a domain in the same step:
neo deploy . --domain app.example.com
What happens, in order
Neo builds the image from your Dockerfile, ships it to the server, and starts it as a new container alongside whatever's already running — it doesn't touch the old one yet. Once the new container passes a health check, Caddy's routing switches to it, and only then does the old container get removed. If the health check never passes, the old version just keeps serving traffic and the new one gets torn down — a bad deploy doesn't take the site offline, it just fails to replace what was already working.
This pattern is called blue-green deployment. That's really all you need to know for now — the mechanics (container naming, exactly what "healthy" means, how a scaled app handles it) are covered in Zero-Downtime Deploys Explained: How Neo's Blue-Green Switch Works.
No domain yet? Get HTTPS anyway
You don't need to own a domain to test with real HTTPS:
neo domain my-app --temp
This gives you a working https://my-app.<server-ip>.sslip.io URL immediately — sslip.io resolves any subdomain containing an IP back to that IP, so Caddy can issue a real certificate for it without any DNS setup on your end. Good for confirming a deploy works before you've pointed a real domain anywhere.
Beyond this lesson
If your project uses docker-compose.yml instead of a bare Dockerfile, Neo auto-detects the app service, environment variables, and port from it — see Deploying Your First App with Neo for that full walkthrough.
Try it yourself — Neo is free, with every feature unlocked.
Get started free