At home, I've got a NAS, a Raspberry PI running on Octopi, a server running on Debian, etc. In short, a galaxy of smart devices serving websites and apps, but nonetheless, none of them are easily accessible from outside my place and even less, from a secured connection.
Making this charming little world accessible from the unique public IP adress in my possesion leads me to use a reverse proxy system.
But what actually is a reverse proxy ? Quoting Wikipedia,
[...] A reverse proxy is a type of proxy server that retrieves resources on behalf of a client from one or more servers. These resources are then returned to the client, appearing as if they originated from the reverse proxy server itself. Unlike a forward proxy, which is an intermediary for its associated clients to contact any server, a reverse proxy is an intermediary for its associated servers to be contacted by any client. In other words, a proxy is associated with the client(s), while a reverse proxy is associated with the server(s); a reverse proxy is usually an internal-facing proxy used as a 'front-end' to control and protect access to a server on a private network.
There are loads of reverse proxy on the market, but today's focus will be on Traefik which allows:
- HTTP and TCP request forwarding
- Automatic service discovery (featuring Docker for instance)
- Secured connections via Let's Encrypt certificates
Of course to make it work you will need a domain name (wilson.net in my case), and to make sure the different DNS Zones are pointing to your server.
You could also emulate a domain name through your local
/etc/hosts file, but in such case the generation of a SSL certificate won't be possible.
Okay, let's set everything up together now :)
First, you'll need to setup Traefik on a webserver accessible from the internet.
In my case, that server will be 192.168.0.1: it is where ports 80 (HTTP) and 443 (HTTPS) of my internet router (freebox) are forwarded to.
It is just as well to install Traefik's binary file, compile it from source, or, just like we'll be doing in this blog post, deploy it with a Docker image.
docker-compose to avoid typing the same command again and again and also enhance it with new configuration elements as this tutorial goes along.
Let's create our first file
If, for any reason, our server must restart, the
restart: always instruction will allow our reverse-proxy service to restart automatically, on its own.
ports section, we expose the ports of the reverse proxy service to the outside.
volume section, we share files and/or directories with our service.
/srv/traefik.toml file with our container is all well and good, but maybe we should create it, right?
We are then going to create Traefik's main configuration file
/srv/traefik.toml which declares, at least, the 2 endpoints mentionned earlier:
Next, we can start our reverse-proxy service from our
/srv directory using the following command:
Of course, we'll have a pretty 404 response if we visit our server's page for the moment, but take it a proof that our server is here and can't wait to serve us content.
Configuring the dashboard
We just saw that our reverse-proxy is running but has nothing to display for the moment. We'll now plug the dashboard, allowing us to know if our services, endpoints and routing rules are correctly applyied by Traefik.
First, we'll add an
[api] section to enable the dashboard and the API. Also, adding a
[providers.docker] section will enable Docker provider and watch for its labels.
Traefik needs to know Docker's socket path in order to activate its provider.
Our main Traefik configuration file
/srv/traefik.toml should now be similar to:
We'll have to generate a password for dashboard access and prevent anonymous access.
For that, we must use
htpasswd and as we don't want to install it inside our ravishing machine, we'll use an Apache Docker image in order to hash our password.
In that exemple, wilson is my login, schizo is my password.
The ouput from our last command is
Now that we have our hashed password, we'll add a
basicauth middleware which will be in charge of securing access to the page by asking for a password with the
Define the (http) endpoint with
Declare we want to use the api service provided by the internal provider
Finally, we now have to adapt the
/srv/docker-compose.yaml file to something similar to that:
I'd like to highlight that I had to double the
$ symbols in order to escape the
$ symbols as it tries to reference a variable.
It is important to stay consistent with names inside routers and middlewares.
Here, the name of my rule is
api. You could use any name if you like considering that it's not already used for another service and that the name stays the same everywhere.
We can now ask our service to apply our modifications running the following command again from the
Here's what I see when I browse the URL defined in my routing rule above:
Reverse proxy of a website accessible from local network
Connected to my network, there's my NAS I'd like to reach from outside.
We'll need to declare it to with the
file provider as, unlike Docker, it can't be automatically discovered.
Therefore, we'll create the
/srv/services.toml file as below:
192.168.0.11 is my NAS IP here and it awaits HTTP requests on port 5000
I'll declare this file provider in
/srv/traefik.toml in order to load this service file:
As you may see, the container will search for our service file under
/etc/traefik but yet, we will keep it under
We will declare these routing rules in
/srv/docker-compose.yaml as docker labels:
You probably understood this already but, the service name is always in the form of [service name]@[provider.
rule allows me to define which route let me reach my service. Here, I only match on the domain name which must be
Once again, let's not forget to apply our changes with docker-compose:
Voilà, here's what I get now when I reach my NAS using th hostname declared above.
Generating SSL certificate
Thanks to Let's Encrypt, we can very easily generate SSL certificates that will be automatically renewed for free.
No more excuses now refraining to embrace HTTP2 and securing the data of your users.
In order to generate certificates signed by Let's Encrypt, I need to create a
/srv/acme.json file and make it accessible for Traefik to store its aforesaid certificates.
Next, add this file insde the volume section
/srv/acme.json:/acme.json of your
/srv/traefik.toml, I declare a certificatesResolver allowing me to get certificates.
Which would give me a
/srv/traefik.toml file similar to:
Beware, your email adress is mandatory.
/srv/docker-compose.yaml we still need to add labels for generating the SSL certificate of my NAS, that would give:
entrypoints indicates that I want a HTTPS access, else HTTP.
tls, that I want to use a SSL certificate.
tls.certresolver what certresolver I should use.
And let's not forget again to ask docker-compose to apply our new configuration:
Once done, I have an access to my NAS, secured by HTTPS :D
And that I can, of course, see inside my Traefik dashboard:
Reverse proxy for services running in Docker containers
Now that we know how to write different routing rules for a service and how to generate SSL certificates, doing such for a Docker service should be a breeze.
After reading DOMOTIZE YOUR WORKSPACE (lang. French) article, I wanted to setup Home Assistant at home.
Home Assistant can be set up with a Docker container, so we will add the extra lines inside
/srv/docker-compose.yml which should now look like this:
traefik.enable=true enables the reverse proxy for the service and then make it accessible from the internet.
traefik.http.routers.home.entrypoints=https,http activates https endpoint, then http endpoint otherwise.
traefik.http.routers.home.tls=true indicates that I wish for a SSL certificate.
traefik.http.routers.home.tls.certresolver=wilson indicates I want to use the wilson certresolver to generate my certificate.
traefik.http.services.home.loadbalancer.server.port=8123 indicates that the service port I want to expose is 8123.
Once last time, don't forget to ask docker-compose to apply our new configuration:
We can now use Home Assistant and do so directly through https ;)
I hope that you enjoyed this article and that you'll be delighted to play with Traefik.
See ya /o/