Deploying a container is not the same as running one on your laptop. Knowing how to deploy a docker container in 2026 means getting an image off your machine, onto a host you do not babysit, and keeping it alive when it crashes at 3 a.m. This guide walks the honest path — build, push, pull, run, and watch — plus the parts most vendor tutorials quietly skip.
What changed in 2026
- Managed platforms swallowed the middle. Cloud Run, ECS, Fly, Railway, and Render now handle most small-to-mid deployments. You hand them an image; they handle TLS, scaling, and restarts.
- Non-root is the default. Modern runtimes warn or block root containers, and most managed platforms refuse them outright.
- Compose v2 is just the CLI.
docker compose (no hyphen) ships inside Docker itself and remains the pragmatic default for single-host deploys.
- Multi-arch is a real trap. Apple Silicon laptops build
arm64 by default, but plenty of cloud hosts run amd64. Build for the target or you get a cryptic exec format error on first boot.
Step 1: Build and push — never build on prod
Your production host should pull a finished image, not compile one. Building on prod means installing build tools, burning CPU, and risking a half-built image serving traffic. Build in CI or locally, tag it for a registry, and push.
# Build for the host's architecture, not your laptop's
docker build --platform linux/amd64 -t registry.example.com/app:1.4.2 .
docker push registry.example.com/app:1.4.2
Tag with a real version or the git SHA. The latest tag is convenient and lies to you — two hosts can pull latest an hour apart and run different code.
Step 2: Pick where it actually runs
The target dictates everything else. Be honest about how much ops work you want to own.
| Target |
Best for |
You manage |
Watch out for |
| Single VPS + Compose |
Side projects, one service |
OS patching, TLS, backups |
No auto-scaling; one host = one failure point |
| Managed platform (Cloud Run, Fly, Render) |
Most web apps and APIs |
Almost nothing |
Cold starts, egress and per-request costs |
| Orchestrator (Kubernetes, ECS) |
Many services, real scale |
A lot |
Steep learning curve; easy to over-build |
If you are one person shipping one app, a VPS or a managed platform is almost always the right call. Reaching for Kubernetes on day one is the most common self-inflicted wound in this space.
Step 3: Run it with the flags that matter
A production docker run needs more than the image name. The four that earn their keep:
docker run -d \
--name app \
--restart unless-stopped \
-p 127.0.0.1:8080:8080 \
--env-file /etc/app/prod.env \
--memory 512m \
registry.example.com/app:1.4.2
--restart unless-stopped brings the container back after a crash or reboot. Binding to 127.0.0.1 keeps the port private so a reverse proxy (Caddy, Nginx, Traefik) handles TLS. --env-file keeps secrets out of your shell history. --memory caps a leaky process before it takes the whole box down.
For anything with more than one container, use Compose so the config lives in version control:
services:
app:
image: registry.example.com/app:1.4.2
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
env_file: /etc/app/prod.env
mem_limit: 512m
Then docker compose pull && docker compose up -d is your entire deploy. That two-command flow is repeatable and forgettable-proof — the opposite of a hand-typed docker run.
Step 4: Health checks, restarts, and clean shutdown
A restart policy only helps if Docker knows the container is unhealthy. Add a health check so a hung process gets recycled instead of silently serving errors.
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
Two more things people miss: use the exec form (CMD ["node", "server.js"], not a shell string) so your app actually receives SIGTERM and can drain connections; and roll deploys by starting the new container before stopping the old one, so there is no gap where nothing answers.
What to skip
- Mounting the Docker socket into a container unless you fully trust it — it is effectively root on the host.
- The
latest tag in production. Pin a version so rollbacks are one command.
- Building images on the production server. Build elsewhere, pull the artifact.
- A raw
docker run as your deploy process. Put it in Compose or a script you commit.
FAQ
Do I need Kubernetes to deploy one container?
No. A single VPS with Compose, or a managed platform, handles one container cleanly. Kubernetes earns its complexity only once you have many services and real scaling needs.
How do I roll back a bad deploy?
Pull and run the previous image tag — this is exactly why you pin versions instead of using latest. With Compose, change the tag and re-run up -d.
Where do secrets go?
In an env file the runtime reads, a platform secrets manager, or Docker/Compose secrets — never baked into the image, where docker history can expose them.
Why does my image fail to start on the server but work locally?
Almost always an architecture mismatch. Rebuild with --platform linux/amd64 (or the host's arch) and push a multi-arch image if you deploy to both.
Where to go next
If you are picking a stack to containerize, Astro vs Next.js in 2026 compares the two most common web frameworks. Once your container is public, API rate limiting in 2026 covers protecting it from abuse, and ACID transactions explained is worth reading before you point that container at a database in production.