Hi there,
i am currently migrating my old raspi server and want to use containerization on my Pi4 replacement.
It was quite a learning curve to rebuild the services as docker containers, but I am quite satisfied with the outcome so far.
The next piece of the puzzle for me would be, to utilize lets encrypt certificates and a reverse proxy for my setup.
That was when I learned about traefik and it's abilities.
But where there is light, there is also shadow... As I was researching configuration examples I came across this POST mentioning that exposing the docker socket to a container is risky from security standpoint.
The last comment in the discussion mentioned that with traefik_v2 the issue could be avoided with the file provider, thus creating a static configuration for traefik.
I am not planning on relying on the dynamic configuration, even though it would be nice to have. A static configuration would be ok with me, as I do not intend to alter the services/configuration much and I would value the increased security more.
My question is, what would a secure, reliable traefik reverse proxy configuration for docker containers look like? All examples I found during research were either using older traefik versions or exposing the docker socket to traefik...
My main points which I would like to achieve are:
- Already solved: Acquiring let's encrypt certs for the dedyn domain I am using via dns01 challenge.
- I would like to have a central entrance to multiple services behind the traefik proxy (ideally only making the central entrance point known to the internet like gatekeeper.mydomain.example.com) but also have the possibility to call a service directly like
nc.gatekeeper.mydomain.example.com
orgatekeeper.mydomain.example.com/nc
would that be possible? - http redirection, e.g. when called via a http entrypoint it should be redirected to the https version with a valid cert
- a solution that also works with docker-swarm. Currently I leverage the passing of external secrets to the docker containers via the docker-swarm agent and would like to keep it this way.
I came up with a little test configuration after combining some tutorials, but it is not a satisfying solution yet.
For an example, lets say I have three docker containers. A nextcloud image, a database and a adminer instance and of course the traefik container.
I want traefik to be the reverse proxy for these containers, only exposing traefik to the big bad internet and keeping the applications safe. How would I be doing this without involving the docker socket?
Test configuration so far:
docker-compose.yaml
services:
traefik:
image: traefik:v2.0.4
container_name: traefik
ports:
- "80:80"
- "443:443"
- "8080:8080"
environment:
- TZ=Europe/Berlin
- EXEC_PATH=/etc/traefik/domain_dns
- DOMAIN_TOKEN=d42d9cd98f00b204e9345998ecf8427e
- DOMAIN_NAME=mydomain.example.com
volumes:
- ./traefik.yml:/etc/traefik/traefik.yml
- ./dynamic_conf.yml:/etc/traefik/dynamic_conf.yml
- ./acme.json:/acme.json
- ./domain_dns:/etc/traefik/domain_dns
nextcloud:
image: nextcloud:stable-apache
volumes:
- "./nc/data:/var/www/html/data"
- "./nc/custom_apps:/var/www/html/custom_apps"
- "./nc/config:/var/www/html/config"
environment:
- MYSQL_HOST=db
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=somepassword
ports:
- 127.0.0.1:8084:80
db:
image: linuxserver/mariadb:arm32v7-110.4.10mariabionic-ls42
restart: always
volumes:
- "./db:/config"
env_file:
- "db.env"
adminer:
image: adminer:4.7.4-standalone
restart: always
ports:
- 127.0.0.1:8085:8080
traefik.yml
level: DEBUG
serversTransport:
insecureSkipVerify: true
entryPoints:
web:
address: ":80"
web-secure:
address: ":443"
api:
insecure: true
dashboard: true
providers:
file:
filename: "/etc/traefik/dynamic_conf.yml"
watch: true
certificatesResolvers:
sample:
acme:
email: admin@mydomain.example.com
storage: acme.json
dnsChallenge:
provider: exec
delayBeforeCheck: 0
dynamic_conf.yml
http:
routers:
router0:
entyPoints:
- web
service: nextcloud
rule: "Host(`raspberrypi.mydomain.example.com`) && Path(`/nc`)"
middlewares:
- redirect
router1:
entyPoints:
- web-secure
service: nextcloud
rule: "Host(`raspberrypi.mydomain.example.com`) && Path(`/nc`)"
middlewares:
- ncHeader
- nc-replacepath
tls:
certResolver: sample
router2:
entyPoints:
- web
service: adminer
rule: "Host(`raspberrypi.mydomain.example.com`) && Path(`/ad`)"
middlewares:
- redirect
router3:
entyPoints:
- web-secure
service: adminer
rule: "Host(`raspberrypi.mydomain.example.com`) && Path(`/ad`)"
middlewares:
- adHeader
- ad-replacepath
tls:
certResolver: sample
services:
nextcloud:
loadBalancer:
#prevents the triggering of the "safe domains" feature of apache
passHostHeader: false
servers:
- url: "http://127.0.0.1:8084/"
adminer:
loadBalancer:
servers:
- url: "http://127.0.0.1:8085/"
middlewares:
nc-replacepath:
replacePath:
path: ""
ncHeader:
headers:
customRequestHeaders:
X-Replaced-Path: "/nc"
ad-replacepath:
replacePath:
path: ""
adHeader:
headers:
customRequestHeaders:
X-Replaced-Path: "/ad"
redirect:
redirectScheme:
scheme: https
Regards Stephan