Introduction
As of this writing, I've been using this setup on a single server to host n8n, pure html sites (you'd be surprised how much you can do with just html), Wordpress, Odoo, Plausible, and JS apps. Traefik makes it easy to forward traffic to the mentioned backend services using a simple onetime setup that I will cover bellow.
Traefik VS Nginx
You might wonder, how does Ngxin compare with Traefik, here are the main differences between both:
- Traefik setup is much simpler than Nginx, especially for containers.
- Traefik comes built in with SSL certificate generation/renewal mechanism, you do not need any additiona setup and configuration like Nginx with Certbot.
- Traefik is a reverse proxy/router only, while Nginx works as a web server as well, therefor Traefik cannot server files like Nginx does, therefor if you need to server files, you'd need a web server with the Traefik setup.
Prerequisites
- Docker + Docker Compose installed
- A domain with a DNS record pointing at this server's public IP
- Ports 80 and 443 free and reachable from the internet (needed for the Let's Encrypt HTTP challenge)
Directory and Docker Compose Setup
This example is suitable for an Ubuntu setup, create the appropriate directory for your docker projects and clone the github repo:
sudo mkdir /opt/docker
sudo chown <your user>:<your user> /opt/docker
cd /opt/docker
git clone https://github.com/opensourcehustle/traefik.git
Setup
1. Create the external network (other stacks will join this to be routed by Traefik):
docker network create traefik-network
2. Copy the env template and fill it in:
cp .env.example .env
Fill in:
| Variable | What it is |
|---|---|
| DOMAIN | Hostname for the Traefik dashboard, e.g. traefik.yourdomain.com |
| TZ | Server timezone, e.g. Europe/London |
| TRAEFIK_AUTH | Dashboard login — see step 3 |
| TRAEFIK_ALLOWED_IPS | CIDR ranges allowed to reach the dashboard |
3. Generate a dashboard password hash:
sudo apt install apache2-utils # provides htpasswd, if not already installed htpasswd -nB admin
Paste the full output (e.g. admin:$2y$05$...) into TRAEFIK_AUTH in .env. Double any currency signs, otherwise it is considered a variable, in the admin:$2y$05$... eg, it should be updated to admin:$$2y$$05$$...
4. Set your Let's Encrypt email:
Open traefik.yml and replace CHANGE_ME@yourdomain.com under certificatesResolvers.letsencrypt.acme.email with your real address. (This one lives in traefik.yml rather than .env — Traefik's static config file isn't env-substituted the way the compose labels are.)
5. Create acme.json with the right permissions:
Let's Encrypt refuses to store certs in a file with overly permissive access.
touch acme.json chmod 600 acme.json
6. Start it:
docker compose up -d docker compose logs -f traefik
Once it's up, visit https://<DOMAIN> — you should get a cert automatically and be prompted for the dashboard login.
Adding another service behind this proxy
Any container joined to traefik-network with the right labels gets picked up automatically. Example:
services: myapp: image: myapp:latest networks: - traefik-network labels: - "traefik.enable=true" - "traefik.http.routers.myapp.rule=Host(`myapp.yourdomain.com`)" - "traefik.http.routers.myapp.entrypoints=websecure" - "traefik.http.routers.myapp.tls.certresolver=letsencrypt" networks: traefik-network: external: true
For services that aren't Docker containers on this host, use the file provider instead — see config/dynamic-example.yml.dis
Serving Static Files Example
Lets serve regular HTML files using Traefik+Nginx. Make sure you have your domain pointing to your Traefik server.
Lets start by creating the appropriate directory:
mkdir /opt/docker/html-example && cd /opt/docker/html-example
Now lets create our compose file:
nano compose.yml
Add the following directives to it:
services:
nginx:
image: nginx:alpine
container_name: html-nginx
restart: unless-stopped
volumes:
- ./html:/usr/share/nginx/html:ro
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.yourdomain.rule=Host(`yourdomain.com`)"
- "traefik.http.routers.yourdomain.entrypoints=websecure"
- "traefik.http.routers.yourdomain.tls.certresolver=letsencrypt"
- "traefik.http.services.yourdomain.loadbalancer.server.port=80"
networks:
traefik-network:
external: true
Replace "yourdomain" with your actual domain.
Now start the container and Traefik will handle everything:
sudo docker compose up -d
This should create the default nginx directories, now lets add our own html to the html directory:
cd html
Now lets download a ready template from tooplate.com:
sudo wget https://www.tooplate.com/zip-templates/2165_neon_carbon.zip
Lets install unzip and unzip the directory:
sudo apt install unzip && sudo unzip 2165_neon_carbon.zip
Now lets move the files and delete unnecessary directories:
sudo mv 2165_neon_carbon/* .
sudo rm 2165_neon_carbon.zip
sudo rm -rf 2165_neon_carbon
Lets also add our nginx configuration as well:
cd ../nginx
sudo nano default.conf
Add the following directives to it:
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
error_page 404 /404.html;
location = /404.html {
internal;
}
location / {
try_files $uri $uri/ =404;
}
}Lets down and up the nginx container:
sudo docker compose down
sudo docker compose up -d
Now visit your site, it should be accessible over https and serving our fancy html files.