secure https connection: Traefik Reverse Proxy + Let's Encrypt
Ready-made Docker containers are available for almost all known web systems, or they can be created relatively easily or existing containers can be adapted. As Docker containers, the web services can be installed and operated very easily. Anyone publishing a web service over the Internet should definitely offer an encrypted connection (SSL) for this today. To control access to one or more containers, a reverse proxy with free Let's Encrypt certificates can be used for SSL offloading, see also: own web server - how does the Internet actually work? To provide web services from the home network over the internet maybe Cloudflare offers a simpler alternative to this setup.
Aim of this article
Running one or more Docker web services (websites) including HTTPS encryption on a server.The web services can be published via their properties (Docker container labels) and controlled via their own web interface.
Effort
Reading time: approx. 16 MinutesPrerequisite
A server published on the Internet with Docker and a registered web domainFrom NGINX Proxy to Traefik
I originally used "NGINX Proxy Automation" by Evert Ramos to run multiple Docker-based websites, see: nginx-LetsEncrypt Reverse Proxy in Practice . The project works wonderfully, but has some limitations compared to the alternative reverse proxy: Traefik. With Traefik it feels even easier and thanks to the web dashboard clearer to run multiple websites on one server. Numerous middleware also offer additional functions.
Schematic representation
The Traefik Docker container takes care of issuing, managing and using SSL certificates and redirects web requests to the respective web services, which in turn are also deployed as Docker containers.
Traefik takes care of
-
-
- access to one or more Docker web services
- the certificate management for HTTPS encryption
-
Shown here schematically, using the pages www.libe.net and www.script-example.com:
Software | Traefik |
---|---|
GitHub | https://github.com/traefik/traefik |
current version | 2.10.6 |
found | 2023-11-28 |
Installation: server, domain (DNS), Docker.
Docker Basics
Docker allows applications to be launched by command in a so-called container.A container is an isolated environment independent of the operating system (OS):
When a container is first launched, Docker independently loads all the necessary sources
from the internet.
Docker can be installed on Windows, macOS or an Linux Distribution
For those who have already installed Docker and entered the appropriate A-records in the domain management, you need a folder with the following text file and 2 simple commands.
As an example, I create the text file in the following folder: /var/web/traefik. On Linux the folder can be created with mkdir /var/web/traefik.
In the folder, as a template, a text file named docker-compose.yml can be created with the following content.
docker-compose.yml
services:
traefik:
image: "traefik:v2.8"
container_name: "traefik"
command:
#- "--log.level=DEBUG"
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=admin@domain.tld"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
expose:
# traefik dashboard port
- 8080
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.domain.tld`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=myresolver"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=traefik-basic-auth"
- "traefik.http.middlewares.traefik-basic-auth.basicauth.users=admin:??????"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
restart: "always"
networks:
default:
name: webproxy
external: true
The example uses bind mounts and not volumes, see: Docker Data Storage: Docker Volumes vs. Host Folders..
Customizing the docker-compose.yml file
The docker-compose-yml template uses a certificate not only for the published web service containers, but also for the Traefik dashboard, which means that access to the dashboard is also encrypted. To prevent the dashboard from being accessed by just anyone, a basic authentication with an admin user has been stored.
Before the actual start the file must be adapted of course a little:
- traefik.domain.tld should be created with an own domain for the traefik dashboard,
- acme.email with a mail address and
- basicauth.users should be replaced with its own username and a corresponding md5 password.
Instead of traefik.domain.tld, a subdomain of an existing domain can be used to access the dashboard. As an example, in the DNS zone management for the domain libe.net, an A record for a subdomain traefik.libe.net could be created on the IP address of the web server.
Of course, in the docker-compose.yml file for this example, traefik.libe.net must also be used instead of traefik.domain.tld.
The mail address is used by Let's Encrypt to send certain information or warnings: For example, if a certificate is about to expire. Don't worry, Traefik takes care of certificate renewal, accordingly emails with information about certificate expiration should be taken seriously.
The password for authentication cannot be entered in plain text and therefore must be generated in advance via a command as an MD5 hash, and for use in docker-compose simple $ must be replaced with $$, see: doc.traefik.io/traefik/middlewares/http/basicauth/
On Linux, the following command can be used for this:
echo $(htpasswd -nB admin) | sed -e s/\\$/\\$\\$/g
root@Webserver:~# echo $(htpasswd -nB admin) | sed -e s/\\$/\\$\\$/g
New password:
Re-type new password:
admin:$$2y$$05$$7liwlteyGcPyCr2oXc4Do.G/wWxjwWLYpTWg6vvQ4pU7PLAS4ysMm
Instead of admin, another username can be used here.
After customizing the file, we can start the Traefik container. Subsequently, started Docker containers with the stored labels for its web service are processed and published by Traefik during operation.
Start the Traefik container
As network for Traefik and for the later created web services I use a custom network named “webproxy”, which I create before starting Traefik (docker-compose up):
cd /FolderContainingDockerComposeFile4Traefik
docker network create webproxy
docker-compose up -d
If everything works correctly, the Traefik dashboard can be accessed via the specified domain and after entering the specified user:
Create and host websites or services
If another Docker container is launched with the network webproxy and appropriate labels for Traefik, it can be accessed via Traefik.
If you want to launch multiple web services, you need to make sure that different labels are used in the respective configurations:
z. E.g. web service 1:
labels:
- "traefik.enable=true"
- "traefik.http.routers.webservice1.rule=Host(`service1.domain.tld`)"
- "traefik.http.routers.webservice1.entrypoints=web"
- "traefik.http.routers.webservice1.entrypoints=websecure"
...
and for another Docker container with another service:
labels:
- "traefik.enable=true"
- "traefik.http.routers.webservice2.rule=Host(`service2.domain.tld`)"
- "traefik.http.routers.webservice2.entrypoints=web"
- "traefik.http.routers.webservice2.entrypoints=websecure"
...
"web" as entrypoint allows unencrypted access to the service and "websecure" encrypted access via HTTPS.

See also: own web server - how does the internet actually work?
Authentication
If you want to add simple basic authentication for a container, you can do so by adding the Basic Authentication middleware. (same as used in die the Traefik dashboard Configuration)
(Basic-Authentication: Before the dashboard can be accessed, the stored username and password must be entered).
The following line creates a middleware named: webserver-basic-auth, defining the username and password:
- "traefik.http.middlewares.webserver-basic-auth.basicauth.users=admin:md5Password".
The password can be converted to an md5 hash with a Linux command, as described earlier: echo $(htpasswd -nB admin) | sed -e s/\$/\$\$/g
To make the router, here named "webserver" use the created middleware, I added the following line:
- "traefik.http.routers.webserver.middlewares=webserver-basic-auth".
labels:
- "traefik.enable=true"
- "traefik.http.routers.webserver.rule=Host(`domain.tld`)"
- "traefik.http.routers.webserver.entrypoints=web"
- "traefik.http.routers.webserver.entrypoints=websecure"
- "traefik.http.routers.webserver.tls.certresolver=myresolver"
- "traefik.http.middlewares.webserver-basic-auth.basicauth.users=admin:md5Password"
- "traefik.http.routers.webserver.middlewares=webserver-basic-auth"
Alternatively to Basic authentication, an external login provider can also be used. As an example, the use of Google as a login provider, i.e. using a Google account to log in to your own web services, see: Traefik Google Authentication.
Additional SAN (Subject Alternative Names)
So that a web certificate can be issued for several subdomains, so-called SAN can be used:
labels:
- "traefik.enable=true"
- "traefik.http.routers.webservice.rule=Host(`domain.tld`,`www.domain.tld`,`dev.domain.tld`,`dev2.domain.tld)"
- "traefik.http.routers.webservice.entrypoints=web"
- "traefik.http.routers.webservice.entrypoints=websecure"
- "traefik.http.routers.webservice.tls.certresolver=myresolver"
Redirects
For redirecting subdomains to another subdomain, regex expressions can be used.
Redirect various subdomains and/or non-WWW to WWW
The following example redirects all subdomains and the root domain (non-WWW) to a URL with WWW:
domain.tld, dev.domain.tld, and dev2.domain.tld are redirected to www.domain.tld. To ensure that the certificate includes all domain names, they must be specified in the host rule:
labels:
- "traefik.enable=true"
- "traefik.http.routers.webservice.rule=Host(`domain.tld`,`dev.domain.tld`,`dev2.domain.tld`,`www.domain.tld`)"
- "traefik.http.routers.webservice.entrypoints=web"
- "traefik.http.routers.webservice.entrypoints=websecure"
- "traefik.http.routers.webservice.tls.certresolver=myresolver"
- "traefik.http.routers.webservice.middlewares=redirect_???2www"
- "traefik.http.middlewares.redirect_???2www.redirectregex.regex=^https://(dev.|dev2.)?domain.tld(.*)"
- "traefik.http.middlewares.redirect_???2www.redirectregex.replacement=https://www.domain.tld$${2}"
- "traefik.http.middlewares.redirect_???2www.redirectregex.permanent=true"
Various subdomains and/or WWW on non-WWW
labels:
- "traefik.enable=true"
- "traefik.http.routers.webservice.rule=Host(`domain.tld`,`dev.domain.tld`,`dev2.domain.tld`,`www.domain.tld`)"
- "traefik.http.routers.webservice.entrypoints=web"
- "traefik.http.routers.webservice.entrypoints=websecure"
- "traefik.http.routers.webservice.tls.certresolver=myresolver"
- "traefik.http.routers.webservice.middlewares=redirect_www2none"
- "traefik.http.middlewares.redirect_www2none.redirectregex.regex=^https://(www.|dev.|dev2.)domain.tld(.*)"
- "traefik.http.middlewares.redirect_www2none.redirectregex.replacement=https://domain.tld$${2}"
- "traefik.http.middlewares.redirect_www2none.redirectregex.permanent=true"
Redirect HTTP to HTTPS (not globally, only for the respective container)
labels:
- "traefik.enable=true"
- "traefik.http.routers.webservice.rule=Host(`domain.tld`,`dev.domain.tld`,`dev2.domain.tld`,`www.domain.tld`)"
- "traefik.http.routers.webservice.entrypoints=web"
- "traefik.http.routers.webservice.entrypoints=websecure"
- "traefik.http.routers.webservice.tls.certresolver=myresolver"
- "traefik.http.routers.webservice_http.rule=Host(`domain.tld`,`www.domain.tld`,`dev.domain.tld`)"
- "traefik.http.routers.webservice_http.entrypoints=web"
- "traefik.http.routers.webservice_http.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
FAQ
What is a reverse proxy?
A reverse proxy accepts web requests and forwards them to underlying web services. To ensure that the requests are forwarded to the correct web service, most reverse proxies use the host header (=domain name). A reverse proxy can provide additional functions for better protection, optimized traffic or additional authentication.
What is a reverse proxy used for?
A reverse proxy is mainly used for web access to one or more web servers upstream. Besides distributing the requests to several web services, a reverse proxy is often used for a so-called SSL offloading. The reverse proxy takes care of providing the web services via HTTPS and, in addition to encrypting and decrypting the data traffic, it also handles certificate management.
What is the difference between a reverse proxy and a load balancer?
The job of a load balancer is primarily to distribute the load between different servers or devices. A reverse proxy can perform other functions besides load balancing, such as SSL offloading or caching, and is primarily used for web servers (HTTP). A load balancer, on the other hand, can also be used for other protocols.
Webservices, Examples
Here is a list of web services that I have tested so far:
- Nextcloud , see : Nextcloud Server Docker | Setup + https: Let's Encrypt [ssl]
- Docker Mailserver, see : Running Docker Mailserver yourself | a field report
- Home Assistant, see : All about Home Assistant: Setup + Integration + Operation
- Gitea, see : Lean and fast GIT server, similar to GitHub (Docker)
- GitLab, see : Self-hosting GIT repositories: launch GitLab as a Docker container
- webhookd, see : Docker WebHook Daemon: simple hook server for bash scripts
- Laravel, see : my docker web server setup for laravel - config in detail
- Bitwarden, see : Running Bitwarden in Docker - Setup step by step
- WordPress, see : WordPress in Docker incl. HTTPS Let's Encrypt setup
- Portainer, see : Docker Container GUI graphical web interface with Portainer
- Matomo, see : Visitor statistics: Matomo, Google Analytic replacement self-hosting
- Uptime Kuma, see : Monitor websites with Uptime Kuma

{{percentage}} % positive

THANK YOU for your review!
Top articles in this section
If you are looking for a NAS (Network Attached Storage) for home use, you cannot avoid the manufacturers Synology and QNAP. Both manufacturers deliver small NAS complete solutions with the option to synchronize data locally or via the Internet, and both do not exactly charge little money for the hardware used.
Zigbee2MQTT is an open source Zigbee bridge which can be easily integrated into existing smart home solutions thanks to the MQTT network protocol. As an example, Zigbee2MQTT combined with MQTT broker Mosquitto and Home Assistant can collect, display, record and control data from Zigbee devices. The setup described here uses Docker as a base. Manufacturer's website: https://www.zigbee2mqtt.io
The well-known Signal Messenger can besides the app also be used via command line or from other systems. The signal-cli-rest-api, which is available in the form of a Docker container, offers a simple option for this. For the API to work, it has to be coupled via the Signal app beforehand.