Back to Blog
DevOps

How to Set Up Traefik and Portainer on Ubuntu with Docker Compose

29 April 2020 7 min read DevOps
How to Set Up Traefik and Portainer on Ubuntu with Docker Compose
DevOps

Updated June 2026 — commands and versions refreshed for current releases. Ubuntu 18.04 reached end of life, so this guide targets Ubuntu 24.04 LTS, and the config is updated for Traefik v3 and current Portainer CE.

Overview

This tutorial explains how to set up Traefik (a reverse proxy and load balancer) alongside Portainer (a Docker management tool) using Docker Compose. The original article used Ubuntu 18.04, which is now end of life; these steps target Ubuntu 24.04 LTS. The setup lets you host multiple applications on a single server with automatic traffic routing, Let's Encrypt SSL, and container management.

Key Components

How to Set Up Traefik and Portainer on Ubuntu with Docker Compose

Traefik provides dynamic routing, load balancing, automatic Let's Encrypt SSL certificate management, and a dashboard for monitoring entrypoints and services.

Portainer is a powerful, open-source management toolset that lets you build, manage, and maintain Docker environments from a web UI.

Prerequisites

  • Docker and Docker Compose installed
  • DNS entries pointing your subdomains (for example traefik.example.com and portainer.example.com) to your server's IP
  • The directory structure below created

Install Docker

The legacy apt-key method is deprecated. Install Docker Engine and the Compose plugin using Docker's current keyring-based repository:

$ sudo apt-get update
$ sudo apt-get install ca-certificates curl gnupg
$ sudo install -m 0755 -d /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ sudo chmod a+r /etc/apt/keyrings/docker.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
$ sudo docker run hello-world
$ sudo usermod -aG docker ${USER}
$ sudo reboot

Docker Compose is now bundled as a plugin, so the command is docker compose (with a space). The standalone docker-compose binary download from the original article is no longer needed.

Directory Structure

Create a working directory for the core stack:

/home/ubuntu/docker/core/
├── docker-compose.yml
├── traefik-data/
│   ├── acme.json
│   └── traefik.yml
└── portainer-data/
mkdir -p /home/ubuntu/docker/core/traefik-data
mkdir -p /home/ubuntu/docker/core/portainer-data
touch /home/ubuntu/docker/core/traefik-data/acme.json
chmod 600 /home/ubuntu/docker/core/traefik-data/acme.json
touch /home/ubuntu/docker/core/traefik-data/traefik.yml

Traefik Static Configuration (traefik.yml)

This is the v3 static config. The provider and ACME blocks are largely the same as v2, but note Traefik v3 renamed the entrypoint-redirect mechanism and tightened a few label names.

api:
  dashboard: true

entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

certificatesResolvers:
  http:
    acme:
      email: [email protected]
      storage: acme.json
      httpChallenge:
        entryPoint: http

Replace the email address with your own so Let's Encrypt can send expiry notices.

Generate a Secure Dashboard Password

$ sudo apt install apache2-utils
$ echo $(htpasswd -nb <username> <password>) | sed -e s/\$/\$\$/g

Replace <username> and <password> with your credentials, then paste the escaped result into the basicauth label below.

Create the Docker Network

docker network create traefik-proxy

Docker Compose File

The top-level version: key is obsolete in modern Compose and can be omitted. Traefik is pinned to v3 and Portainer to the current Community Edition image.

services:
  traefik:
    image: traefik:v3.4
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - traefik-proxy
    ports:
      - 80:80
      - 443:443
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik-data/traefik.yml:/traefik.yml:ro
      - ./traefik-data/acme.json:/acme.json
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=username:password"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=http"
      - "traefik.http.routers.traefik-secure.service=api@internal"

  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - traefik-proxy
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./portainer-data:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.entrypoints=http"
      - "traefik.http.routers.portainer.rule=Host(`portainer.example.com`)"
      - "traefik.http.middlewares.portainer-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.portainer.middlewares=portainer-https-redirect"
      - "traefik.http.routers.portainer-secure.entrypoints=https"
      - "traefik.http.routers.portainer-secure.rule=Host(`portainer.example.com`)"
      - "traefik.http.routers.portainer-secure.tls=true"
      - "traefik.http.routers.portainer-secure.tls.certresolver=http"
      - "traefik.http.routers.portainer-secure.service=portainer"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"
      - "traefik.docker.network=traefik-proxy"

networks:
  traefik-proxy:
    external: true

Note the original image was portainer/portainer; the current image is portainer/portainer-ce. Update the domain names and credentials to match your environment.

Deploy the Services

docker compose up -d

Once the containers are healthy, access the services at:

  • https://traefik.example.com — the Traefik dashboard (behind basic auth)
  • https://portainer.example.com — the Portainer UI (set your admin password on first visit)

Useful Commands

docker compose up           # run in the foreground to watch logs on first run
docker compose logs         # check logs
docker compose ps           # view container status

You now have an auto-SSL reverse proxy fronting a Docker management UI, ready to route any additional service you add to the traefik-proxy network.

Indivar Software Solutions

SAP Business One consulting and custom software development since 2009. Offices in India, New Zealand, and the USA.

Related Articles

More on DevOps

Need Help with SAP Business One?

Whether you need implementation support, custom add-ons, or strategic ERP advice, our team is ready to help. over 17 years of SAP B1 experience across India, New Zealand, and the USA.