Skip to content

Commit

Permalink
Add traefik
Browse files Browse the repository at this point in the history
  • Loading branch information
sanders41 committed Dec 27, 2024
1 parent febffe7 commit f2ef25a
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 8 deletions.
5 changes: 4 additions & 1 deletion backend/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pathlib import Path
from typing import Annotated, Any, Final, Literal, Self

from dotenv import find_dotenv, load_dotenv
from pydantic import (
AnyUrl,
BeforeValidator,
Expand All @@ -13,6 +14,8 @@
)
from pydantic_settings import BaseSettings, SettingsConfigDict

load_dotenv(find_dotenv(".env"))


def _parse_cors(v: Any) -> list[str] | str:
if isinstance(v, str) and not v.startswith("["):
Expand All @@ -23,7 +26,7 @@ def _parse_cors(v: Any) -> list[str] | str:


class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
model_config = SettingsConfigDict(env_file_encoding="utf-8", extra="ignore")

API_V1_PREFIX: str = "/api/v1"
TITLE: Final = "SCAN"
Expand Down
86 changes: 86 additions & 0 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
services:
proxy:
image: traefik:3
volumes:
- /var/run/docker.sock:/var/run/docker.sock
ports:
- "80:80"
- "8090:8080"
# Duplicate the command from docker-compose.yml to add --api.insecure=true
command:
# Enable Docker in Traefik, so that it reads labels from Docker services
- --providers.docker
# Add a constraint to only use services with the label for this stack
- --providers.docker.constraints=Label(`traefik.constraint-label`, `traefik-public`)
# 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
# Enable the access log, with HTTP requests
- --accesslog
# Enable the Traefik log, for configurations and errors
- --log
# Enable debug logging for local development
- --log.level=DEBUG
# Enable the Dashboard and API
- --api
# Enable the Dashboard and API in insecure mode for local development
- --api.insecure=true
labels:
# Enable Traefik for this service, to make it available in the public network
- traefik.enable=true
- traefik.constraint-label=traefik-public
networks:
- traefik-public
- default

backend:
image: backend:dev
restart: no
ports:
- "8000:8000"
networks:
- traefik-public
- default
build:
context: ./backend
container_name: backend
depends_on:
- db
- valkey
env_file:
- .env
environment:
- POSTGRES_HOST=db

labels:
- traefik.enable=true
- traefik.docker.network=traefik-public

# HTTP entry point and rule
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=Host(`api.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.entrypoints=http

# Remove reference to HTTPS and its middlewares
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.middlewares=

# Clear HTTPS-specific labels
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.rule=
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.entrypoints=
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls.certresolver=
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.middlewares=

db:
restart: "no"
ports:
- "5432:5432"

valkey:
restart: "no"
ports:
- 6379:6379

networks:
traefik-public:
# For local dev, don't expect an external Traefik network
external: false
77 changes: 77 additions & 0 deletions docker-compose.traefik.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
services:
traefik:
image: traefik: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
# Use the traefik-public network (declared below)
- traefik.docker.network=traefik-public
# Define the port inside of the Docker service to use
- traefik.http.services.traefik-dashboard.loadbalancer.server.port=8080
# Make Traefik use this domain (from an environment variable) in HTTP
- traefik.http.routers.traefik-dashboard-http.entrypoints=http
- traefik.http.routers.traefik-dashboard-http.rule=Host(`traefik.${DOMAIN?Variable not set}`)
# traefik-https the actual router using HTTPS
- traefik.http.routers.traefik-dashboard-https.entrypoints=https
- traefik.http.routers.traefik-dashboard-https.rule=Host(`traefik.${DOMAIN?Variable not set}`)
- 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=${USERNAME?Variable not set}:${HASHED_PASSWORD?Variable 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
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=${EMAIL?Variable not set}
# 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
# 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

volumes:
# Create a volume to store the certificates, even if the container is recreated
traefik-public-certificates:

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
46 changes: 39 additions & 7 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,62 @@
services:
backend:
image: backend:dev
restart: always
networks:
- traefik-public
- default
build:
context: ./backend
container_name: backend
depends_on:
- db
- valkey
ports:
- "8000:8000"
env_file:
- backend/.env
- .env
environment:
- POSTGRES_HOST=db
- VALKEY_HOST=valkey
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public

- traefik.http.services.${STACK_NAME?Variable not set}-backend.loadbalancer.server.port=8000

- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=Host(`api.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.entrypoints=http

- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.rule=Host(`api.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.entrypoints=https
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls=true
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls.certresolver=le

# Enable redirection for HTTP and HTTPS
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.middlewares=https-redirect

db:
image: postgres:17-alpine
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"]
interval: 10s
retries: 5
start_period: 30s
timeout: 10s
expose:
- 5432
ports:
- 5432:5432
environment:
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "test_password"
POSTGRES_DB: "scan"
POSTGRES_USER: postgres
POSTGRES_PASSWORD: test_password
POSTGRES_DB: scan
volumes:
- db-data:/var/lib/postgresql/data

valkey:
image: valkey/valkey:8-alpine
restart: always
expose:
- 6379
ports:
Expand All @@ -38,4 +67,7 @@ volumes:
db-data:

networks:
scan-network:
traefik-public:
name: traefik-public
# Allow setting it to false for testing
external: true
1 change: 1 addition & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
uv sync --frozen --all-extras

@backend-server:
docker compose down backend && \
cd backend && \
uv run uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Expand Down

0 comments on commit f2ef25a

Please sign in to comment.