Docker Compose deployment: ports, data and recovery
Deploy a web application with Docker Compose: private port binding, persistent storage, release checks, and a recovery plan.

Docker Compose puts an application's runtime settings into a versioned file. It does not automatically solve backups, private networking, or release recovery. This guide shows a small deployment layout for an existing web application on a Linux server, with an HTTPS proxy running on the host.
You need Docker Engine and the Compose plugin installed using the official Ubuntu installation guide. You also need a tested application image and a server account allowed to run Docker. Docker access is privileged; do not give it to every user by default.
Define what the application needs
Before creating a Compose file, identify the container's listening port, writable directories, required environment variables, and health endpoint. Check the image's documentation. In this example, the application listens on port 3000 and stores persistent files under /app/data; adapt both to your actual application.
Create compose.yaml in your deployment directory:
services:
web:
image: ${APP_IMAGE:?Set APP_IMAGE in .env}
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
env_file:
- app.env
volumes:
- app-data:/app/data
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
volumes:
app-data:
Set APP_IMAGE in .env to your registry's release image, preferably pinned to an immutable digest. Create app.env with the environment variables documented by your application. Do not commit either file when it contains credentials. Limit file access with chmod 600 .env app.env.
Keep the application port private
The 127.0.0.1 binding makes the published port available on the host's loopback interface. The host reverse proxy can reach it, while remote visitors use the proxy's public HTTPS endpoint. If your reverse proxy runs inside Docker instead, use a shared Docker network and the service name; its own localhost will not reach this host binding.
Docker's documentation warns that published container ports can bypass UFW rules. Do not assume an application is private just because a firewall rule appears restrictive. Review the binding and test access from another machine.
Validate and start the release
Run these commands from the directory containing your Compose file:
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 web
curl -I http://127.0.0.1:3000
A successful HTTP response confirms connectivity, not complete application health. Test the actual login, database access, and one key workflow. A redirect may be expected; repeated server errors are not. Avoid sharing logs until you have checked them for sensitive information.
Plan recovery before an update
Keep the previous image digest and release configuration. Before upgrading, back up persistent data using the application's supported method. Filesystem copies of a running database may be inconsistent; use its native backup tooling or a documented shutdown procedure.
If a release fails, restoring the previous image may help, but a database migration can make that image incompatible. Document whether data rollback is required before pressing ahead. Do not use docker compose down -v as routine cleanup: it removes named volumes.
The Compose quickstart explains the core workflow. Continue with Caddy HTTPS setup, or ask about software delivery when your deployment needs a managed release process.
