As a personal project, I developed a little python web app, and launched it to a few friends and family. It immediately became clear that the static files was slowing everything down. I probably could have fixed this problem through use of async, and I'll probably go back and do that anyway, but I wanted to understand more about how to use traefik effectively. I tried and failed several times to add an nginx service to it, and when I looked around for examples of how other people did it, I couldn't find a single example. I wanted to share a docker-compose.yml file that worked for me, in the hopes that it will set someone else on the right path.
docker-compose.yml
:
services:
traefik:
# Use the latest v2.3.x Traefik image available
image: traefik:v2.3
ports:
# Listen on port 80, default for HTTP, necessary to redirect to HTTPS
- 80:80
# Listen on port 443, default for HTTPS
- 443:443
restart: always
labels:
# Enable Traefik for this service, to make it available in the public network
- traefik.enable=true
# Define the port inside of the Docker service to use
- traefik.http.services.traefik-dashboard.loadbalancer.server.port=8080
# Make Traefik use this domain in HTTP
- traefik.http.routers.traefik-dashboard-http.entrypoints=http
- traefik.http.routers.traefik-dashboard-http.rule=Host(`traefik.your-hostname-here`)
# Use the traefik-public network (declared below)
- traefik.docker.network=traefik-public
# traefik-https the actual router using HTTPS
- traefik.http.routers.traefik-dashboard-https.entrypoints=https
- traefik.http.routers.traefik-dashboard-https.rule=Host(`traefik.your-hostname-here`)
- traefik.http.routers.traefik-dashboard-https.tls=true
# Use the "le" (Let's Encrypt) resolver created below
- traefik.http.routers.traefik-dashboard-https.tls.certresolver=le
# Use the special Traefik service api@internal with the web UI/Dashboard
- traefik.http.routers.traefik-dashboard-https.service=api@internal
# https-redirect middleware to redirect HTTP to HTTPS
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
# traefik-http set up only to use the middleware to redirect to https
- traefik.http.routers.traefik-dashboard-http.middlewares=https-redirect
# admin-auth middleware with HTTP Basic auth
# Using the environment variables USERNAME and HASHED_PASSWORD
- traefik.http.middlewares.admin-auth.basicauth.users=${BASIC_USERNAME?Variable not set}:${BASIC_HASHED_PASSWORD?Variable not set}
- traefik.http.middlewares.member-auth.basicauth.usersfile=${USERFILE?User File is not set}
# Enable HTTP Basic auth, using the middleware created above
- traefik.http.routers.traefik-dashboard-https.middlewares=admin-auth
volumes:
# Add Docker as a mounted volume, so that Traefik can read the labels of other services
- /var/run/docker.sock:/var/run/docker.sock:ro
# Mount the volume to store the certificates
- traefik-public-certificates:/certificates
- ./auth:/auth
# Write access log out to a file.
- /var/run/log/traefik/access.log:/tmp/access.log
command:
# Enable Docker in Traefik, so that it reads labels from Docker services
- --providers.docker
# Do not expose all Docker services, only the ones explicitly exposed
- --providers.docker.exposedbydefault=false
# Create an entrypoint "http" listening on port 80
- --entrypoints.http.address=:80
# Create an entrypoint "https" listening on port 443
- --entrypoints.https.address=:443
# Create the certificate resolver "le" for Let's Encrypt, uses the environment variable EMAIL
- --certificatesresolvers.le.acme.email=your@email.here
# Store the Let's Encrypt certificates in the mounted volume
- --certificatesresolvers.le.acme.storage=/certificates/acme.json
# Use the TLS Challenge for Let's Encrypt
- --certificatesresolvers.le.acme.tlschallenge=true
# Enable the access log, with HTTP requests
- --accesslog
- --accesslog.filepath=/tmp/access.log
# Enable the Traefik log, for configurations and errors
- --log
# Enable the Dashboard and API
- --api
networks:
# Use the public network created to be shared between Traefik and
# any other service that needs to be publicly available with HTTPS
- traefik-public
static-files:
image: nginx
volumes:
# We listen on three directories
- ./static:/usr/share/nginx/html/static:ro
- ./videos:/usr/share/nginx/html/videos:ro
- ./screencaps:/usr/share/nginx/html/screencaps:ro
- ./default.conf:/etc/nginx/conf.d/default.conf
container_name: static-files
restart: unless-stopped
networks:
- traefik-public
labels:
# Match on the hostname and the path
- traefik.enable=true
# listen to just the three paths we will server
- traefik.http.routers.static-files.rule=Host(`your-hostname-here`) && PathPrefix(`/static/`, `/videos/`, `/screencaps/`)
- traefik.http.routers.static-files.tls=true
- traefik.http.routers.static-files.tls.certresolver=le
- traefik.http.services.statif-files.loadbalancer.server.port=80
- traefik.docker.network=traefik-public
# tell Traefik which middlewares we want to use on this container
- traefik.http.middlewares.static-files.compress=true
- traefik.http.routers.static-files.middlewares=https-redirect
# - traefik.http.routers.nginx.middlewares=gzip
main:
build: ./
environment:
# some initial build processes were taking too long, and were timing out before completion
- TIMEOUT=360
restart: always
labels:
# Enable Traefik for this specific "backend" service
- traefik.enable=true
# Define the port inside of the Docker service to use
- traefik.http.services.app.loadbalancer.server.port=80
# Make Traefik use this domain in HTTP
- traefik.http.routers.app-http.entrypoints=http
- traefik.http.routers.app-http.rule=Host(`your-hostname-here`)
# Use the traefik-public network (declared below)
- traefik.docker.network=traefik-public
# Make Traefik use this domain in HTTPS
- traefik.http.routers.app-https.entrypoints=https
- traefik.http.routers.app-https.rule=Host(`your-hostname-here`)
- traefik.http.routers.app-https.tls=true
# Use the "le" (Let's Encrypt) resolver
- traefik.http.routers.app-https.tls.certresolver=le
# https-redirect middleware to redirect HTTP to HTTPS
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
# Middleware to redirect HTTP to HTTPS
- traefik.http.routers.app-http.middlewares=https-redirect
- traefik.http.routers.app-https.middlewares=member-auth
networks:
# Use the public network created to be shared between Traefik and
# any other service that needs to be publicly available with HTTPS
- traefik-public
volumes:
- ./database:/app/database
- ./static:/app/static
- ./templates:/app/templates
- ./videos:/app/videos
- ./screencaps:/app/screencaps
volumes:
# Create a volume to store the certificates, there is a constraint to make sure
# Traefik is always deployed to the same Docker node with the same volume containing
# the HTTPS certificates
traefik-public-certificates:
database:
static:
templates:
videos:
screencaps:
auth:
networks:
# Use the previously created public network "traefik-public", shared with other
# services that need to be publicly available via this Traefik
traefik-public:
external: true
default.conf
:
listen 80;
server_name _;
client_max_body_size 200M;
set $cache_uri $request_uri;
location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { log_not_found off; access_log off; }
ignore_invalid_headers on;
add_header Access-Control-Allow_Origin *;
location /static {
autoindex on;
root /usr/share/nginx/html/;
}
location /videos {
autoindex on;
root /usr/share/nginx/html/;
}
location /screencaps {
autoindex on;
root /usr/share/nginx/html/;
}
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}
Some necessary things are being copied into the main container in a Dockerfile, but that is not relevant here except the first line of it
FROM tiangolo/uvicorn-gunicorn-fastapi:latest
. I could then run docker-compose up -d
to get it going in daemon mode, and then I ran docker-compose scale static-files=3
to have docker spin up 3 nginx containers for traefil to load balance between.
Add new comment