DEPLOY, WITHOUT THE GUESSWORK

How to Deploy a Docker App to a VPS (From Image to HTTPS)

Deploy any Docker image to a VPS with HTTPS, persistent volumes, and a repeatable workflow. The foundation for everything else.

How to Deploy a Docker App to a VPS (From Image to HTTPS)

You are going to deploy a Docker container to a VPS with HTTPS and a reverse proxy:

This is the foundation. Once you understand this pattern, deploying any Docker image becomes the same three commands.

What you will have at the end

Step 1: Install Docker on your VPS

SSH into your server and run:

sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker

Verify the installation:

docker --version
docker compose version

Step 2: Create the app directory structure

mkdir -p ~/apps/myapp
cd ~/apps/myapp

Each app gets its own directory. This keeps configs isolated and makes debugging straightforward.

Step 3: Create a docker-compose.yml with Traefik

Create docker-compose.yml:

services:
  traefik:
    image: traefik:v2.11
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --certificatesresolvers.letsencrypt.acme.tlschallenge=true
      - [email protected]
      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - letsencrypt:/letsencrypt
    restart: unless-stopped

  app:
    image: nginx:alpine  # Replace with your image
    restart: unless-stopped
    labels:
      - traefik.enable=true
      - traefik.http.routers.app.rule=Host(`your-domain.com`)
      - traefik.http.routers.app.entrypoints=websecure
      - traefik.http.routers.app.tls=true
      - traefik.http.routers.app.tls.certresolver=letsencrypt
      - traefik.http.services.app.loadbalancer.server.port=80

volumes:
  letsencrypt:

Replace:

Step 4: Add environment variables and volumes

For apps that need configuration, create a .env file:

# .env
DATABASE_URL=postgres://user:pass@db:5432/myapp
SECRET_KEY=your-secret-key-here
NODE_ENV=production

Update your compose file to use it:

  app:
    image: your-image:latest
    env_file:
      - .env
    volumes:
      - ./data:/app/data  # Persist data outside container
    restart: unless-stopped
    labels:
      # ... traefik labels

Step 5: Deploy your application

docker compose up -d

Check that everything is running:

docker compose ps
docker compose logs -f app

Visit https://your-domain.com - you should see your app with a valid SSL certificate.

Step 6: Update workflow

Your update loop is simple:

docker compose pull        # Get latest image
docker compose up -d       # Recreate with new image
docker image prune -f      # Clean old images

For images you build locally:

docker compose up -d --build

Troubleshooting

SSL certificate not issued

The most common issues:

docker logs $(docker ps --filter name=traefik -q) 2>&1 | grep -i acme

Container keeps restarting

Check the logs for the actual error:

docker compose logs app --tail 50

Common causes:

502 Bad Gateway

This means Traefik cannot reach your app:

Permission denied on volumes

Docker runs as root by default. If your app runs as a non-root user:

sudo chown -R 1000:1000 ./data

Or specify the user in your compose file:

  app:
    image: your-image
    user: "1000:1000"

Internal links (recommended next reads)


Related in the StoicSoft network

If you work in AI-assisted coding, shared terminal sessions, or agent-driven shell workflows like the ones above, 1devtool is the StoicSoft network's tool for safer AI-assisted terminal work — shared sessions with auditing, preflight policy, and tiered model routing built in.

From across the StoicSoft network

Hand-curated reads on the same topic from sister sites in the StoicSoft family.