In my FastAPI app I've mounted the static
directory to serve static files as follows:
app.mount('/static', StaticFiles(directory='static'), name='static')
The FastAPI app runs from inside a Docker container defined as follows:
fhback:
container_name: fhback
build:
context: ./back
dockerfile: Dockerfile
restart: unless-stopped
expose:
- 8000
command: "gunicorn --workers 6 --timeout 60 --bind 0.0.0.0:8000 -k uvicorn.workers.UvicornWorker main:app"
volumes:
- ./back:/app
labels:
- traefik.enable=true
- traefik.http.routers.fhback.rule=Host(`example.com`) && PathPrefix(`/api`)
- traefik.http.routers.fhback.entrypoints=https
- traefik.http.routers.fhback.tls.certresolver=le
- traefik.http.middlewares.firehouse-compress.compress=true
- traefik.http.middlewares.fhback-stripprefix.stripprefix.prefixes=/api
- traefik.http.routers.fhback.middlewares=firehouse-compress,fhback-stripprefix
With these Traefik labels, I can access my Swagger with https://example.com/api/docs
and also call API endpoints from the front end with https://example.com/api/...
(externally) or http://fhouse:8000/api/...
(locally, from Docker).
But I never can access my static files in the static
dir! When I do http://fhouse:8000/api/static/any-file.txt
from any Docker container within the Docker network, it works fine. But when I try https://example.com/api/static/any-file.txt
, I get connection error. I realize I must do something with the Traefik config... Any ideas?
There is also another service running in the same Docker bundle defined as follows:
fhfront:
container_name: fhfront
build:
context: ./front
dockerfile: Dockerfile
restart: unless-stopped
expose:
- 8090
environment:
- NODE_ENV=development
volumes:
- ./front:/app
- /app/node_modules
labels:
- traefik.enable=true
- traefik.http.routers.fhfront.rule=Host(`example.com`,`www.example.com`)
- traefik.http.routers.fhfront.entrypoints=https
- traefik.http.routers.fhfront.tls.certresolver=le
- traefik.http.middlewares.firehouse-compress.compress=true
- traefik.http.routers.fhfront.middlewares=firehouse-compress
This service is the frontend (website) which seems to mask all requests to example.com/static
or example.com/api/static
. How can I explicitly exclude the static
route from example.com
in the fhfront
container? So that it gets picked up by fhback
and serve static files?
├── back
│ ├── Dockerfile
│ ├── main.py
│ ├── requirements.txt
│ └── static
│ └── test.html
└── docker-compose.yml
Both Traefik and the API are set up as services.
🗎 docker-compose.yml
version: "3"
services:
traefik:
container_name: traefik
image: traefik:v2.5
command:
- "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
fhback:
container_name: fhback
build:
context: ./back
dockerfile: Dockerfile
restart: unless-stopped
volumes:
- ./back:/app
labels:
- traefik.enable=true
- traefik.http.routers.fhback.rule=Host(`example.com`) && PathPrefix(`/`)
- traefik.http.services.fhback.loadbalancer.server.port=8000
- traefik.http.middlewares.firehouse-compress.compress=true
- traefik.http.routers.fhback.middlewares=firehouse-compress,fhback-stripprefix
- traefik.http.middlewares.testheader.headers.customresponseheaders.X-Test-Header=TraefikProxy
- traefik.http.routers.fhback.middlewares=testheader
depends_on:
- traefik
networks:
default:
external:
name: traefik
🗎 back/Dockerfile
FROM python:3.11.4-slim
COPY requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt
WORKDIR /app
COPY . /app
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
The static file is being baked straight into the image. You can use a volume mount to share static files from the host though.
🗎 back/main.py
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount('/static', StaticFiles(directory='static'), name='static')
@app.get("/")
async def root():
return {"message": "Hello World"}
🗎 requirements.txt
fastapi==0.109.2
uvicorn==0.27.1
To test:
curl -v --resolve example.com:80:127.0.0.1 http://example.com/static/test.html
I added a response header via the Traefik labels in docker-compose.yml
. If you look at the output below you'll see that header, confirming that the response came via Traefik. You can also see it in the logs in the top panel of the screenshot.