Updated: 28 September 2026 · Applies to: Ubuntu 24.04, Debian 12, AlmaLinux 9 and Rocky Linux 9

With the nginx-proxy and acme-companion containers, each new container gets its own domain and a free Let's Encrypt certificate automatically.

Install Docker Engine (official repository)

Ubuntu 24.04 / Debian 12:

apt install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
apt update
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

On Debian, use https://download.docker.com/linux/debian in both the key URL and URIs.

AlmaLinux 9 / Rocky Linux 9:

dnf install dnf-plugins-core
dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker

Test with docker run hello-world. Compose is available as docker compose.

compose.yaml

services:
  proxy:
    image: nginxproxy/nginx-proxy
    ports: ["80:80", "443:443"]
    volumes:
      - certs:/etc/nginx/certs
      - html:/usr/share/nginx/html
      - /var/run/docker.sock:/tmp/docker.sock:ro
  acme:
    image: nginxproxy/acme-companion
    environment:
      DEFAULT_EMAIL: you@example.com
    volumes_from: [proxy]
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - acme:/etc/acme.sh
  site1:
    image: nginx
    environment:
      VIRTUAL_HOST: site1.example.com
      ACME_HOST: site1.example.com
volumes: {certs: {}, html: {}, acme: {}}

Start with docker compose up -d. Add more sites as services with their own VIRTUAL_HOST and ACME_HOST (older examples call it LETSENCRYPT_HOST). Each domain must point to the server.

How it works

nginx-proxy watches Docker. When a container starts with VIRTUAL_HOST, it adds an Nginx site for that domain and forwards traffic to the container. acme-companion sees ACME_HOST, requests a Let's Encrypt certificate, and renews it automatically.

Add another site

docker run -d --name site2 --network <project>_default \
  -e VIRTUAL_HOST=site2.example.com -e ACME_HOST=site2.example.com nginx

The container must be on the same Docker network as the proxy (docker network ls shows the Compose network name). If the app listens on a port other than 80, add VIRTUAL_PORT (for example VIRTUAL_PORT=3000).

Common problems

  • No certificate: the domain must point to this server and port 80 must be reachable from the internet. Check docker compose logs acme.
  • 502 Bad Gateway: the app container is not running, is on another network, or needs VIRTUAL_PORT.

Related services

KVM VPS hosting

NVMe SSD and full root access, with Free Basic Managed Support.

Unmanaged dedicated servers

full root access and free IPMI KVM, with Free Basic Managed Support.

Managed dedicated servers

our engineers look after the server for you, from $135 a month.

Was this answer helpful?

Still stuck? Open a ticket