Skip to content

Instantly share code, notes, and snippets.

@waja
Last active July 22, 2024 06:22
Show Gist options
  • Save waja/37202007b10837a7fc2e6eacacd9b335 to your computer and use it in GitHub Desktop.
Save waja/37202007b10837a7fc2e6eacacd9b335 to your computer and use it in GitHub Desktop.
Deploy Traefik as Frontend Proxy for Docker
#!/bin/bash
DOCKER_BASE="${DOCKER_BASE:-/srv/docker}"
TRAEFIK_DIR="${TRAEFIK_DIR:-traefik}"
mkdir -p ${DOCKER_BASE}/${TRAEFIK_DIR}/container.conf
touch ${DOCKER_BASE}/${TRAEFIK_DIR}/container.conf/.env
ln -s container.conf/.env ${DOCKER_BASE}/${TRAEFIK_DIR}/
cat > ${DOCKER_BASE}/${TRAEFIK_DIR}/container.conf/docker-compose.yml <<EOF
# Inspired by https://containo.us/blog/traefik-2-0-docker-101-fc2893944b9d/
services:
traefik:
image: traefik:3.1
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- "--log.level=INFO"
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --api=true
- --certificatesresolvers.default.acme.caserver=\${LEAPI:-https://acme-v02.api.letsencrypt.org/directory}
- --certificatesresolvers.default.acme.email=\${LEMAIL:-ssladmin@test.org}
- --certificatesresolvers.default.acme.storage=/etc/traefik/acme.json
- --certificatesresolvers.default.acme.tlschallenge=true
- --providers.file.filename=/etc/traefik/traefik_providers.yaml
- --providers.file.watch=true
logging:
options:
max-size: "100M"
max-file: "10"
networks:
- system_traefik
environment:
- LC_ALL=C.UTF-8
- TZ=Europe/Berlin
labels:
# Enable Traefik for it's own backend
- traefik.enable=true
# Dashboard
- traefik.http.routers.traefik.rule=Host(\`traefik.test.org\`)
- traefik.http.routers.traefik.entrypoints=websecure
- traefik.http.routers.traefik.tls=true
- traefik.http.routers.traefik.tls.certresolver=default
- traefik.http.routers.traefik.service=api@internal
# Basic auth for dashboard
- traefik.http.routers.traefik.middlewares=authtraefik@docker,default-security-headers@file
# middleware authtraefik
- traefik.http.middlewares.authtraefik.basicauth.users=\${DASHBOARD_USERS:-admin:\$\$apr1\$\$AAbCdQpX\$\$ajelS9mMisKRG.lqcY/uXU/} # user/password
ports:
- "80:80"
- "443:443"
restart: always
volumes:
- "./config/:/etc/traefik/"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
system_traefik:
external: true
EOF
ln -s container.conf/docker-compose.yml ${DOCKER_BASE}/${TRAEFIK_DIR}/
cat > ${DOCKER_BASE}/${TRAEFIK_DIR}/container.conf/production.yml <<EOF
services:
traefik:
labels:
# Allow watchtower to update this image
- com.centurylinklabs.watchtower.enable=true
# See https://docs.traefik.io/migration/v1-to-v2/#strip-and-rewrite-path-prefixes
- traefik.http.routers.traefik.rule=Host(\`$(hostname -f)\`) && (PathPrefix(\`/traefik\`) || HeaderRegexp(\`Referer\`, \`.*/traefik/.*\`))
# Redefine middleware for router 'traefik' as we add more middlewares
- traefik.http.routers.traefik.middlewares=authtraefik@docker,traefik-dashboard-stripprefix@file,default-security-headers@file
EOF
cat > ${DOCKER_BASE}/${TRAEFIK_DIR}/container.conf/traefik.service <<EOF
[Unit]
Description=Traefik Proxy Service
After=network.target docker.service
Requires=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
Environment="WORK_DIR=/srv/docker/traefik/"
WorkingDirectory=/srv/docker/traefik/
ExecStartPre=/bin/bash -c "/usr/bin/docker network inspect system_traefik &>/dev/null || /usr/bin/docker network create --driver bridge system_traefik"
ExecStartPre=-/usr/local/bin/docker-compose -f "\${WORK_DIR}/docker-compose.yml" -f "\${WORK_DIR}/container.conf/production.yml" down
ExecStart=/usr/local/bin/docker-compose -f "\${WORK_DIR}/docker-compose.yml" -f "\${WORK_DIR}/container.conf/production.yml" up -d
ExecStop=/usr/local/bin/docker-compose -f "\${WORK_DIR}/docker-compose.yml" -f "\${WORK_DIR}/container.conf/production.yml" down
[Install]
WantedBy=docker.service
EOF
ln -s ${DOCKER_BASE}/${TRAEFIK_DIR}/container.conf/traefik.service /etc/systemd/system/
mkdir -p ${DOCKER_BASE}/${TRAEFIK_DIR}/config
cat > ${DOCKER_BASE}/${TRAEFIK_DIR}/config/traefik_providers.yaml <<EOF
---
tls:
options:
default:
minVersion: VersionTLS12
sniStrict: true
cipherSuites:
# TLS 1.2 cipher suites.
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
# IE 11 and Safari < 9 + iOS <9, OSX < 10.11
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
# TLS 1.3 cipher suites.
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
# TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator that the client is doing version fallback. See RFC 7507.
- TLS_FALLBACK_SCSV
curvePreferences:
- CurveP521
- CurveP384
http:
middlewares:
redirect-web-to-websecure:
redirectScheme:
scheme: https
permanent: true
default-security-headers:
headers:
accessControlAllowMethods:
- GET
- POST
- DELETE
- OPTIONS
accessControlAllowOriginList: ["<origin>"]
accessControlMaxAge: 100
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
# frameDeny: true
# sslRedirect: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 315360000
# contentSecurityPolicy: "default-src 'self' 'unsafe-inline';script-src 'self' 'unsafe-inline' 'unsafe-eval';img-src 'self' data:;font-src 'self' data:;connect-src 'self' ws: wss:"
# customRequestHeaders:
# X-Frame-Options: "SAMEORIGIN"
# customFrameOptionsValue: "SAMEORIGIN"
referrerPolicy: "same-origin"
permissionsPolicy: "vibrate=(self)"
traefik-dashboard-stripprefix:
stripPrefix:
prefixes:
- "/traefik"
services:
redirect-dummy:
loadBalancer:
servers:
- url: ""
routers:
# global redirect to https
# per domain see https://doc.traefik.io/traefik/migration/v1-to-v2/#http-to-https-redirection-is-now-configured-on-routers
web-to-websecure:
rule: "hostregexp(`.+`)"
service: "redirect-dummy@file"
entryPoints:
- "web"
middlewares:
- redirect-web-to-websecure@file
EOF
systemctl daemon-reload && systemctl enable traefik && systemctl start traefik
#!/bin/bash
sed -i '/^WorkingDirectory/a ExecStartPre=/bin/bash -c "/usr/bin/docker network inspect system_traefik &>/dev/null || /usr/bin/docker network create --driver bridge system_traefik"' /srv/docker/traefik/container.conf/traefik.service && systemctl daemon-reload
sed -i '/image: traefik/a\ networks:\n - system_traefik' /srv/docker/traefik/container.conf/docker-compose.yml
sed -i s/traefik_default/system_traefik/g /srv/docker/*/container.conf/*.yml
sed -i s/traefik_default/system_traefik/g /srv/docker/portainer/data/compose/*/docker-compose.yml
#!/bin/bash
BASEPATH="/srv/docker/traefik2/"
export TRAEFIK_DIR="traefik2"
# Download deployment script
wget -q https://gist.githubusercontent.com/waja/37202007b10837a7fc2e6eacacd9b335/raw/deploy_traefik.sh \
-O /tmp/deploy_traefik.sh && \
# Remove auto start of the traefik daemon
sed '/^systemctl/d' -i /tmp/deploy_traefik.sh && \
sed -i '/etc\/systemd\/system\/$/d' /tmp/deploy_traefik.sh && \
# Run deployment
bash /tmp/deploy_traefik.sh
# Migrate settings from old toml config
ADMIN_CRED="$(grep users ${BASEPATH}/../traefik/config/traefik.toml | cut -d \" -f2)"
EMAIL="$(grep email ${BASEPATH}/../traefik/config/traefik.toml | cut -d \" -f2)"
echo "LEMAIL=${EMAIL}" > ${BASEPATH}/.env
echo "#LEAPI=https://acme-staging-v02.api.letsencrypt.org/directory" >> ${BASEPATH}/.env
echo "DASHBOARD_USERS=${ADMIN_CRED}" >> ${BASEPATH}/.env
# Migrate old acme store to the new once
wget -q https://github.com/traefik/traefik-migration-tool/releases/download/v0.13.1/traefik-migration-tool_v0.13.1_linux_amd64.tar.gz -P /tmp
tar -xf /tmp/traefik-migration-tool_v0.13.1_linux_amd64.tar.gz -C /tmp
/tmp/traefik-migration-tool acme -i /srv/docker/traefik/config/acme.json -o /srv/docker/traefik2/config/acme-new.json
echo -e "You might want to the following:\nmv traefik traefik1 && mv traefik2 traefik && systemctl daemon-reload\ncd /srv/docker/traefik\ndocker-compose -f docker-compose.yml -f container.conf/production.yml pull\nsystemctl restart traefik && docker-compose -f docker-compose.yml -f container.conf/production.yml logs -f"
#!/bin/bash
BASEPATH="/srv/docker/traefik/"
sed -i "s/^ sslRedirect: true/# sslRedirect: true/" ${BASEPATH}/config/traefik_providers.yaml && \
sed -i "s/^ featurePolicy: \"vibrate 'self'\"/ permissionsPolicy: \"vibrate=\(self\)\"/" ${BASEPATH}/config/traefik_providers.yaml && \
sed -i "s/image: traefik:2.4/image: traefik:2.5/" ${BASEPATH}/container.conf/docker-compose.yml && \
cd ${BASEPATH} && \
docker-compose -f docker-compose.yml -f container.conf/production.yml pull && \
systemctl restart traefik && docker-compose -f docker-compose.yml -f container.conf/production.yml logs -f
#!/bin/bash
BASEPATH="/srv/docker/traefik/"
cp -a ${BASEPATH} /tmp/ && \
sed -i 's/^ rule:.*/ rule: "hostregexp(`.+`)"/' ${BASEPATH}/config/traefik_providers.yaml && \
sed -i "s/image: traefik:2.*/image: traefik:3.0/" ${BASEPATH}/container.conf/docker-compose.yml && \
echo "Changes made:" && \
( diff -Nuri --no-dereference /tmp/traefik/ ${BASEPATH} || true ) && \
cd ${BASEPATH} && \
docker-compose -f docker-compose.yml -f container.conf/production.yml pull && \
systemctl restart traefik && docker-compose -f docker-compose.yml -f container.conf/production.yml logs -f
#!/bin/bash
sed -i '/\[entryPoints.https.tls\]/a \ minVersion = "VersionTLS11"' /srv/docker/traefik/config/traefik.toml && systemctl restart traefik
#!/bin/bash
sed -i s/VersionTLS11/VersionTLS12/ /srv/docker/traefik/config/traefik.toml && systemctl restart traefik
#!/bin/bash
if [ $(ip -6 route | grep -c ^default) -eq 0 ]; then exit; fi
apt install socat || exit
cat > /etc/systemd/system/socat\@.service <<EOF
[Unit]
Description=ipv6 to ipv4 port forwarding
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/socat TCP6-LISTEN:%i,ipv6only=1,reuseaddr,fork TCP4:127.0.0.1:%i
[Install]
WantedBy=docker.service
EOF
systemctl daemon-reload
for PROTO in http https; do
systemctl enable socat@${PROTO}.service
systemctl start socat@${PROTO}.service
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment