portainer + traefik + docker in a nutshell
My blog (french) : (down for now)
This repository contains everything needed to prepare a scalable linux server ready to manage many web applications in a secured environnement. It uses Portainer to manage services and traefik to route traffic to the right container. It's a very simple and easy to use solution for small projects and personal use. It's also a good way to learn how to use docker and docker-compose.
Please note that this solution is for single server like a VPS or a personal server at home. It relies only on docker and not orchestrators.
- A linux server (I am using a VPS at Scaleway with Ubuntu 22.04 LTS)
- A domain name
With traefik and portainer, you will be able to:
- Reverse proxy exposing only 443 (https)
- Simple configuration, clean, lightweight, forgetable
- Able to manage many domain names and/or subdomains
- Automagically creating validated certificates (with Let's Encrypt)
- Docker administration from a friendly web interface
Traefik is the front wired to the backs. It can automagically discover your docker containers and expose them to the frontend opened port. It can manage your certificates for every domains flawlessly and without any manual intervention. And if it was not enough, it can load balance your backends if you have many for the same service. So it's future proof if you need a little scaling.
Yup, Traefik is just magic and it uses almost no ressources. Fantastic !
You don't want to manage your containers using command-line (no you don't !). Portainer can do everything dirty for you by letting you manage everything docker related on your server using a web UI. The last time you will use a command line is for installing this server.
You need a linux machine with any distribution. For examples here, I am using apt
so you'll need a debian-based distro (I'm using Ubuntu). Of course, you must be root or have sudo access to it. I am using a Scaleway DEV1-L but you can get a testing server for 0,07€/month.
Scaleway are using root user by default. So, next commands in this readme suppose you are root. If not, you can use sudo su -
.
Update packages to their lastest versions
apt update && apt dist-upgrade -y
Even if it's not mandatory, there is no service running on your server right now so it's a good time to reboot it. After a potentially big update, anything could happen and it's preferable to see now if your server reboot properly.
shutdown -r now
It's that easy!
curl -sSL https://get.docker.com/ | sh
You should install docker compose as it's what I will use to configure portainer and traefik containers. Just use apt because we don't mind using the lastest version available.
apt install docker-compose
We are going to use a single network called traefik
where all containers that are handling HTTP traffic (using Traefik) will reside in. This will let you run containers on the same virtual network and let traefik now which of your containers have to be publicly available.
docker network create traefik
Next, download this repository and create a folder named letsencrypt
where traefik will store your certificates.
apt install -y git
git clone https://github.com/rlcx/portaefik.git
cd portaefik
mkdir letsencrypt
Edit docker-compose.yml
and change lines domain = "domain.tld"
and [email protected]
. Please use a domain you own and where you can use a wildcard *.yourdomain.tld
A entry or a A entry for every subdomain you want to redirect to your edge router. For long term usage, it's preferable to create an entry for every subdomain and not using a wildcard because traefik will receive the request for anything.yourdomain.tld and will return a HTTPS/404 without any certificate (of course, it will not create a certificate for anything.yourdomain.tld).
So ! That configuration tells traefik to:
- Accept HTTPS/443
- Watch docker api on /var/run/docker.sock for containers to route to frontend
- Use network called "traefik" for containers (so it will not route containers you don't want to route)
- Create a certificate on host rules using Let's Encrypt
Create a folder /data/portaefik/portainer-data
where portainer will store its data.
Create a file users.u
to secure your traefik dashboard. Put user and password in it. To do it, you will need htpasswd.
apt install -y apache2-utils
htpasswd -nb username password
Alternatively, you can generate a password/hash on htaccesstools.com.
Paste the resulting ouput user:hash
into the file.
Start the containers using the following command:
docker-compose up -d
On your nameserver hosting service, add a wildcard A entry pointing to your server's public ip. Like A *.domain.tld 1.2.3.4 14400
. Preferably, you can create a A entry for portainer.domain.tld
and traefik.domain.tld
. Now, when you try to access to https://portainer.domain.tld
, everything should be ok. You can check that the certificate is issued by Let's Encrypt by clicking on the lock icon in your browser.
If you are not sure about what you are doing, you can make some tests with Let's Encrypt staging environment. Just uncomment the lines - "--certificatesresolvers.letsencryptresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
and - "--log.level=DEBUG"
in docker-compose.yml
and start the containers using docker-compse up
(without -d).
After checking that the certificates are properly generated, don't forget to delete acme.json
in the letsencrypt
folder before restarting in production environment.
Take no time to create an admin password for portainer. Use a very strong password. You can also create a new admin user and delete the one called "admin" for increased security.
You are also able to access to https://traefik.domain.tld. Again, please use a strong password and avoid users like admin
, root
or any other common usernames.
So, the only opened port traefik is handling are 80 and 443. It's recommended to deny access to any other ports. When you want to create a new webapp, you have to first write a docker-compose file and send it to portainer (in Stacks menu). Alternatively, you can use the App Templates menu or start new containers manually. The choice is yours :)
The important things to remember are:
- For traefik to route your server, you must connect it to the network called
traefik
. - Even if on the traefik network, you can enable or disable the route by adding the label
traefik.enable=false
(or true) to the container - Do not expose the port on your host ! If your docker-compose use the
port
section, remove it and route it to traefik instead. - Use the label
traefik.http.routers.[servicename].rule=Host
to route a subdomain to your container - Use the label
traefik.http.services.[servicename].loadbalancer.server.port
to route the container port to the frontend rule
Here is a docker-compose.yml to deploy a simple whoami:
version: "3"
services:
whoami:
image: traefik/whoami
ports:
- "80:80"
restart: unless-stopped
This simple compose file expose your server port 80 to the port 80 of the container traefik/whoami
. Your objective is to remove it and just let traefik expose it itself. Bonus, traefik will handle https instead of http and will create a certificate for you flawlessly.
So you have to modify it like this :
version: "3"
services:
whoami:
image: traefik/whoami
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.services.whoami.loadbalancer.server.port=80" # facultative (traefik will use the first exposed port by default)
- "traefik.http.routers.whoami.rule=Host(`whoami.domain.tld`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=letsencryptresolver"
restart: unless-stopped
networks:
traefik:
external:
name: traefik
The container is not exposing is port to host anymore. Instead, you use labels to handle it. The frontend rule tell traefik on which url to route that container's port. Easy =)
ping.yourdomain.tld => your_server:443 => traefik => container:80
Don't forget to route your subdomain to your server ip on your nameserver hosting service. When you are ready, click on Deploy the stack. This is where the magic starts. Go to https://ping.yourdomain.tld : it should work using https with a valid certificate.
With portainer, you can then go back to your stacks and edit the docker-compose.yml
file. Portainer let you also manage your stack, stopping, killing, restarting any containers with a single click.