# Setting up Docs Created: [[2025_08_28]] 19:10 Tags: #selfhost #Docker #Software I had trouble setting up the [La Suite Docs](https://github.com/suitenumerique/docs) project, so I figured that it would be nice to share my setup for this. ![[la_suite_docs_screenshot.png]] Here are some pre-requisites: - Docker Compose - Existing OIDC infra (I use [[Pocket-ID]] which is fantastically simple) - Emailing system (I use Fastmail) - Domain name that you can attach sub-domains to - Reverse proxy (I use caddy and have a Caddyfile below) The system was built for the French Government, so it obviously is set up in production with a much more complicated Kubernetes setup (which you can read more about [how they set it up here](https://github.com/suitenumerique/docs/tree/main/docs/installation)). For self-hosting, this may be cumbersome for people like me, who prefer to do this as a hobby rather than as a 2nd job. Here is how the setup works: ![[Setting up Docs 2025_08_28-22.21.excalidraw.svg]] Here is the whole compose file: ```yaml services: # DB postgresql: image: postgres:16 container_name: docs_postgres restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -d ${POSTGRES_DB} -U ${POSTGRES_USER}"] interval: 1s timeout: 2s retries: 300 env_file: - stack.env environment: - PGDATA=/var/lib/postgresql/data/pgdata volumes: - docs_db:/var/lib/postgresql/data/pgdata # RESP compatible server redis: container_name: docs_redis image: valkey/valkey:latest restart: unless-stopped # Docs backend backend: image: lasuite/impress-backend:latest container_name: docs_backend user: ${DOCKER_USER:-1000} restart: unless-stopped environment: - DJANGO_CONFIGURATION=Production env_file: - stack.env healthcheck: test: ["CMD", "python", "manage.py", "check"] interval: 15s timeout: 30s retries: 20 start_period: 10s depends_on: postgresql: condition: service_healthy restart: true redis: condition: service_started # Docs realtime collab y-provider: image: lasuite/impress-y-provider:latest container_name: docs_collab user: ${DOCKER_USER:-1000} restart: unless-stopped env_file: - stack.env # Docs frontend app frontend: image: lasuite/impress-frontend:latest container_name: docs_frontend restart: unless-stopped user: "101" entrypoint: - /docker-entrypoint.sh command: ["nginx", "-g", "daemon off;"] env_file: - stack.env volumes: - frontend-nginx:/etc/nginx/templates/docs.conf.template depends_on: backend: condition: service_healthy # S3 compatible storage minio: image: minio/minio container_name: docs_minio restart: unless-stopped env_file: - stack.env healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 1s timeout: 20s retries: 300 entrypoint: "" command: minio server /data volumes: - media-storage:/data # uses the minio CLI to automatically create the required buckets so there is less need to set things up manually createbuckets: image: "minio/mc" depends_on: - minio env_file: - stack.env entrypoint: > /bin/sh -c " sleep 5; mc alias set minio http://minio:9000 docs_minio_user Fxi3Tf8s45oGt6ofWEzqg0UPbbJpiqRrQBhCv; mc mb minio/docs-media-storage; " volumes: media-storage: frontend-nginx: docs_db: ``` With these env vars (obfuscated for my setup of course): I spent a lot of time compiling this full list from their docs which assumes multiple files and interpolation of env vars. ```sh BUCKET_NAME=docs-media-storage COLLABORATION_WS_URL=wss://example.com/collaboration/ws/ DJANGO_ALLOWED_HOSTS=docs.example.com DJANGO_SECRET_KEY=<random> DJANGO_SETTINGS_MODULE=impress.settings DJANGO_CONFIGURATION=Production LOGGING_LEVEL_HANDLERS_CONSOLE=ERROR LOGGING_LEVEL_LOGGERS_ROOT=INFO LOGGING_LEVEL_LOGGERS_APP=INFO PYTHONPATH=/app DJANGO_EMAIL_HOST=mail.example.com DJANGO_EMAIL_HOST_USER=email-user DJANGO_EMAIL_HOST_PASSWORD=email-password DJANGO_EMAIL_PORT=587 [email protected] DJANGO_EMAIL_USE_SSL=false # A flag to enable or disable SSL for email sending. DJANGO_EMAIL_BRAND_NAME="Your Brand here" DJANGO_EMAIL_LOGO_IMG="URL to logo here" AWS_S3_ENDPOINT_URL=http://minio:9000 AWS_S3_ACCESS_KEY_ID=docs_minio_user AWS_S3_SECRET_ACCESS_KEY=<random> AWS_STORAGE_BUCKET_NAME=docs-media-storage MEDIA_BASE_URL=https://docs.example.com OIDC_OP_JWKS_ENDPOINT=https://auth.example.com/.well-known/jwks.json OIDC_OP_AUTHORIZATION_ENDPOINT=https://auth.example.com/authorize OIDC_OP_TOKEN_ENDPOINT=https://auth.example.com/api/oidc/token OIDC_OP_USER_ENDPOINT=https://auth.example.com/api/oidc/userinfo OIDC_OP_LOGOUT_ENDPOINT=https://auth.example.com/api/oidc/end-session OIDC_RP_CLIENT_ID=<client-id> OIDC_RP_CLIENT_SECRET=<client-secret> OIDC_RP_SIGN_ALGO=RS256 OIDC_RP_SCOPES="openid email" LOGIN_REDIRECT_URL=https://docs.example.com LOGIN_REDIRECT_URL_FAILURE=https://docs.example.com LOGOUT_REDIRECT_URL=https://docs.example.com OIDC_REDIRECT_ALLOWED_HOSTS=["https://docs.example.com"] DB_HOST=docs_postgres DB_NAME=docs DB_USER=docs DB_PASSWORD=<random> DB_PORT=5432 POSTGRES_DB=docs POSTGRES_USER=docs POSTGRES_PASSWORD=<random> Y_PROVIDER_API_BASE_URL=http://docs_collab:4444/api/ Y_PROVIDER_API_KEY=<random> COLLABORATION_SERVER_SECRET=<random> COLLABORATION_SERVER_ORIGIN=https://docs.example.com COLLABORATION_API_URL=https://docs.example.com/collaboration/api/ COLLABORATION_BACKEND_BASE_URL=https://docs.example.com COLLABORATION_LOGGING=true MINIO_ROOT_USER=docs_minio_user MINIO_ROOT_PASSWORD=<random> REDIS_URL=redis://docs_redis:6379/1 DJANGO_CELERY_BROKER_URL=redis://docs_redis:6379/0 ``` And, here is the Caddyfile (for just this service): ```ini docs.example.com { # Handle WebSocket connections for collaboration @websocket { header Connection *Upgrade* header Upgrade websocket } # Proxy to backend for API endpoints reverse_proxy /api/* docs_backend:8000 # Proxy to backend for admin endpoints reverse_proxy /admin/* docs_backend:8000 # Proxy to backend for static files reverse_proxy /static/* docs_backend:8000 # Proxy to backend for media files reverse_proxy /media/* docs_backend:8000 # WebSocket collaboration server reverse_proxy /collaboration/ws/* docs_collab:4444 # WebSocket collaboration server reverse_proxy @websocket docs_collab:4444 { header_up Host {host} header_up X-Forwarded-Proto https header_up Origin {http.request.header.Origin} } # Collaboration API endpoints reverse_proxy /collaboration/api/* docs_collab:4444 # Proxy to frontend for most requests reverse_proxy docs_frontend:3000 } ``` Once we have the application running in docker, we need to bootstrap the DB (not sure why this isn't done automatically). So, exec into the container and run ```sh python manage.py migrate ``` After that, we need to create a super user (again, not sure why this isn't done automatically): ```sh python manage.py createsuperuser --email <admin email> --password <admin password> ``` ## References - [Their docs for setting up with docker-compose](https://github.com/suitenumerique/docs/blob/main/docs/installation/compose.md) - [Their env var doc](https://github.com/suitenumerique/docs/blob/main/docs/env.md)