I use Traefik using several different files for services and middlewares.
The dynamic
directory is where all the routes are stored and configured for Traefik to 'see'. To create it, run:
mkdir dynamic
In order to use SSL with Traefik, it needs to know where the SSL certificates are. If you generated them, using the generate.sh
script then they are already in the right directory. What's needed next is to tell Traefik which direction to look. There's already an example configuration in the example-dynamic
directory so you can just quickly copy it with:
cp example-dynamic/tls-certificates.yml ./dynamic
Although the Traefik container has been configured and set up, you won't be able to view the dashboard until it has a corresponding configuration file within the dynamic
directory.
There is already an example file in the example-dynamic/services
directory. To copy it, run:
cp example-dynamic/services/traefik-service.yml dynamic/
Once it is up and running, you can visit tk.local.test
(or whatever domain you decided on) to visit the dashboard. If you want to change the subdomain, simply make an edit to the traefik-service.yml
file.
Services are either docker containers or projects you have running on different ports on your local machine. Just like the traefik-service.yml
you can create a file for each service in the dynamic
directory.
For docker projects, you can use example-dynamic/services/container-service.yml
as a template.
For locally running services, that might be using a process manager such as PM2, you can use example-dynamic/services/http-service.yml
as a template.
Middlewares help filter traffic through Traefik (see what I did there? 😏)
There are several different middlewares you can make use of with Traefik (check their docs), but I will only mention the few I find most useful, for my usage. To enable middlewares, they must be in the dynamic
directory.
Then, in the middlewares
array in a service router configuration, you can list it with its middleware name and append @file
to it as the middleware configuration is contained in a file e.g. redirecthttp@file
.
This makes use of the example-dynamic/middlewares/middleware-redirect-http.yml
file. To enable it's usage you will have to copy it to the dynamic
directory like so:
cp example-dynamic/middlewares/middleware-redirect-http.yml dynamic/
This middleware makes use of example-dynamic/middlewares/middleware-path-strips.yml
to help with directing a domain with the suffix path to a particular service.
In the middleware configuration file, there is a prefixes
array which is compared against the router service rule. For example, this would be a configuration for a container service:
http:
routers:
# earlier configurations omitted for brevity
serviceName-fwd:
rule: Host(`{{env "DOMAIN_NAME"}}`) && Path(`/serviceName`)
entryPoints:
- websecure
middlewares:
- pathstrip@file
tls: {}
service: serviceName-{{env "COMPOSE_PROJECT_NAME"}}@docker
This makes use of the basic-auth
middleware whose configuration can be found in the example-dynamic/middlewares/middleware-basic-auth.yml
. To enable it's usage:
cp example-dynamic/middlewares/middleware-basic-auth.yml dynamic/
This particular middleware requires a users array in the user:password
format using the htpasswd
command.
On Ubuntu, it can be installed using the following command.
sudo apt-get install apache2-utils
On Arch Linux, it can be installed using the following commands:
sudo pacman -S apache
sudo cp /usr/bin/htpasswd /usr/local/bin/htpasswd
sudo pacman -Rncs apache
To create user:password
pair, it's possible to use this command:
echo $(htpasswd -nb $USERNAME $PASSWORD)
# user:$apr1$XreceAun$aWg8Y/AUo0CJDeFixyRuT0
Or using a Docker container:
docker run --rm httpd:2.4-alpine htpasswd -nbB $USERNAME $PASSWORD | cut -d ":" -f 2
Note: In a Kubernetes secret the string (e.g. generated by htpasswd
) must be base64-encoded first. To create an encoded user:password
pair, the following command can be used:
htpasswd -nb user password | openssl base64
# dXNlcjokYXByMSRUbGd6ZjZObCRpNDcuSUhFZ3QyMkIuU3o3enE4bGYuCgo=
Unrelated but, you can generate random strings by running the command:
openssl rand -base64 12
# +iemAiIxER8u1/CG8DuSl98WdM/T6l+uaw==
Note: To prevent the output of your secure strings to the terminal, you can make use of the xclip
package and have the results copied to your clipboard. This will only work on your local machine though. For example:
openssl rand -base64 35 | xclip -selection clipboard
SSH reverse tunneling is what I use to expose a locally running service on a domain/server that is exposed to the internet. It works pretty much the same way as services such as ngrok.
For example, if I want to expose a service running on port 443
on my local machine on port 8000
on a server listening to the domain local.domain.com
I would run the following command on my local machine:
ssh -R 8000:127.0.0.1:443 local.domain.com -v
The general command to run is:
ssh -R $REMOTE_PORT:127.0.0.1:$LOCAL_PORT $REMOTE_URL_OR_IP_ADDRESS -v
If you are using Traefik on the server as well, you could easily use the example-dynamic/services/http-service.yml
as a template. You would have to change the $PORT_NUMBER_OF_SERVICE
variable to the value of the $REMOTE_PORT
variable in the command above. Additionally, on the local machine, you would have to change the domain you are listening to on this machine to be the same as the one on the public server.
For example, this is what it would look like on your server config, if you had the domain https://local.domain.com
being listened to by a service on your local machine:
http:
routers:
local:
entryPoints:
- web
# Must listen to the same domain on your local machine service
rule: Host(`local.domain.com`)
middlewares:
- redirecthttp@file
service: local
local-secure:
entryPoints:
- websecure
tls: {}
service: local
services:
local:
loadBalancer:
servers:
- url: http://192.168.1.1:8000
On your local machine you would have a configuration something like this (container service):
http:
routers:
serviceName-reverse:
rule: Host(`local.{{env "TUNNEL_URL"}}`) # TUNNEL_URL = domain.com
entryPoints:
- websecure
middlewares:
- pathstrip@file
service: serviceName-{{env "COMPOSE_PROJECT_NAME"}}@docker