From b8cae21f5233017256147953e461973ae79df80a Mon Sep 17 00:00:00 2001 From: 3wc <3wc@doesthisthing.work> Date: Tue, 10 Jun 2025 11:40:14 +0100 Subject: [PATCH] Almost-working V2 --- .env.sample | 3 + compose.yml | 305 ++++++++++++++++++++++++++++++---------------------- nginx.conf | 101 ++++++++++++++++- 3 files changed, 276 insertions(+), 133 deletions(-) diff --git a/.env.sample b/.env.sample index 2112904..2c2424d 100644 --- a/.env.sample +++ b/.env.sample @@ -6,3 +6,6 @@ DOMAIN=lasuite-docs.example.com #EXTRA_DOMAINS=', `www.lasuite-docs.example.com`' LETS_ENCRYPT_ENV=production + +# FIXME: Move to docker secret +OIDC_RP_CLIENT_SECRET=example diff --git a/compose.yml b/compose.yml index 0f422b9..cbff96d 100644 --- a/compose.yml +++ b/compose.yml @@ -4,6 +4,7 @@ x-common-env: &common-env DJANGO_ALLOWED_HOSTS: "*" DJANGO_SECRET_KEY: ThisIsAnExampleKeyForDevPurposeOnly DJANGO_SETTINGS_MODULE: impress.settings + # FIXME: Move to docker secret DJANGO_SUPERUSER_PASSWORD: admin # Logging # Set to DEBUG level for dev only @@ -15,29 +16,30 @@ x-common-env: &common-env # Mail DJANGO_EMAIL_BRAND_NAME: "La Suite Numérique" DJANGO_EMAIL_HOST: "mailcatcher" - DJANGO_EMAIL_LOGO_IMG: "http://localhost:3000/assets/logo-suite-numerique.png" + DJANGO_EMAIL_LOGO_IMG: "http://$DOMAIN/assets/logo-suite-numerique.png" DJANGO_EMAIL_PORT: 1025 # Backend url - IMPRESS_BASE_URL: "http://localhost:8072" + IMPRESS_BASE_URL: "https://${DOMAIN}" # Media STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage AWS_S3_ENDPOINT_URL: http://minio:9000 AWS_S3_ACCESS_KEY_ID: impress + # FIXME: Move to docker secret AWS_S3_SECRET_ACCESS_KEY: password - MEDIA_BASE_URL: http://localhost:8083 + MEDIA_BASE_URL: https://${DOMAIN} # OIDC - OIDC_OP_JWKS_ENDPOINT: http://nginx:8083/realms/impress/protocol/openid-connect/certs - OIDC_OP_AUTHORIZATION_ENDPOINT: http://localhost:8083/realms/impress/protocol/openid-connect/auth - OIDC_OP_TOKEN_ENDPOINT: http://nginx:8083/realms/impress/protocol/openid-connect/token - OIDC_OP_USER_ENDPOINT: http://nginx:8083/realms/impress/protocol/openid-connect/userinfo + OIDC_OP_JWKS_ENDPOINT: https://auth.${DOMAIN}/realms/impress/protocol/openid-connect/certs + OIDC_OP_AUTHORIZATION_ENDPOINT: https://auth.${DOMAIN}/realms/impress/protocol/openid-connect/auth + OIDC_OP_TOKEN_ENDPOINT: https://auth.${DOMAIN}/realms/impress/protocol/openid-connect/token + OIDC_OP_USER_ENDPOINT: https://auth.${DOMAIN}/realms/impress/protocol/openid-connect/userinfo OIDC_RP_CLIENT_ID: impress - OIDC_RP_CLIENT_SECRET: ThisIsAnExampleKeyForDevPurposeOnly + OIDC_RP_CLIENT_SECRET: OIDC_RP_SIGN_ALGO: RS256 OIDC_RP_SCOPES: "openid email" - LOGIN_REDIRECT_URL: http://localhost:3000 - LOGIN_REDIRECT_URL_FAILURE: http://localhost:3000 - LOGOUT_REDIRECT_URL: http://localhost:3000 - OIDC_REDIRECT_ALLOWED_HOSTS: '["http://localhost:8083", "http://localhost:3000"]' + LOGIN_REDIRECT_URL: https://${DOMAIN} + LOGIN_REDIRECT_URL_FAILURE: https://${DOMAIN} + LOGOUT_REDIRECT_URL: https://${DOMAIN} + OIDC_REDIRECT_ALLOWED_HOSTS: '["https://auth.${DOMAIN}", "https://${DOMAIN}"]' OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}" # AI AI_FEATURE_ENABLED: "false" @@ -45,171 +47,214 @@ x-common-env: &common-env AI_API_KEY: password AI_MODEL: llama # Collaboration - COLLABORATION_API_URL: http://y-provider:4444/collaboration/api/ - COLLABORATION_BACKEND_BASE_URL: http://app-dev:8000 - COLLABORATION_SERVER_ORIGIN: http://localhost:3000 + COLLABORATION_API_URL: https://$DOMAIN/collaboration/api/ + COLLABORATION_BACKEND_BASE_URL: http://app:8000 + COLLABORATION_SERVER_ORIGIN: https://$DOMAIN COLLABORATION_SERVER_SECRET: my-secret - COLLABORATION_WS_URL: ws://localhost:4444/collaboration/ws/ + COLLABORATION_WS_URL: wss://${DOMAIN}/collaboration/ws/ x-postgres-env: &postgres-env # Postgresql db container configuration - POSTGRES_DB: impress - POSTGRES_USER: dinum - POSTGRES_PASSWORD: pass + POSTGRES_DB: docs + POSTGRES_USER: docs + # FIXME: Move to docker secret + POSTGRES_PASSWORD: password # App database configuration DB_HOST: db - DB_NAME: impress - DB_USER: dinum - DB_PASSWORD: pass + DB_NAME: docs + DB_USER: docs + # FIXME: Move to docker secret + DB_PASSWORD: password DB_PORT: 5432 +x-yprovider-env: &yprovider-env + COLLABORATION_LOGGING: "true" + Y_PROVIDER_API_KEY: foobar + COLLABORATION_API_URL: https://impress.127.0.0.1.nip.io/collaboration/api/ + COLLABORATION_SERVER_ORIGIN: https://impress.127.0.0.1.nip.io + COLLABORATION_SERVER_SECRET: barbar + +x-minio-env: &minio-env + MINIO_ROOT_USER: user + # FIXME: Move to docker secret + MINIO_ROOT_PASSWORD: password + +x-keycloak-env: &kc-keycloak-env + KC_BOOTSTRAP_ADMIN_USERNAME: admin + # FIXME: Move to docker secret + KC_BOOTSTRAP_ADMIN_PASSWORD: admin + KC_DB: postgres + KC_DB_URL_HOST: kc_postgresql + KC_DB_SCHEMA: public + PROXY_ADDRESS_FORWARDING: 'true' + KC_HOSTNAME: https://auth.${DOMAIN} + KC_HTTP_ENABLED: "true" + # KC_HTTPS_CERTIFICATE_FILE: /etc/ssl/certs/docs.crt + # KC_HTTPS_CERTIFICATE_KEY_FILE: /etc/ssl/private/docs.key` + +x-kc-postgres-env: &kc-postgres-env + # Postgresql db container configuration + POSTGRES_DB: keycloak + POSTGRES_USER: keycloak + # FIXME: Move to docker secret + POSTGRES_PASSWORD: keycloak + # Keycloak database configuration + KC_DB_URL_DATABASE: keycloak + KC_DB_USERNAME: keycloak + # FIXME: Move to docker secret + KC_DB_PASSWORD: keycloak + services: app: - user: ${DOCKER_USER:-1000} - image: git.coopcloud.tech/coop-cloud-chaos-patchs/docs-backend:v3.3.0 - environment: *common-env + image: lasuite/impress-frontend:v3.3.0 + networks: + - backend deploy: labels: - "traefik.enable=false" - networks: - - backend + - "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT:-120}" + - "coop-cloud.${STACK_NAME}.version=0.0.0+v3.3.0" - web: - image: nginx:1.25 - ports: - - "8083:8083" - configs: - - source: nginx_conf - target: /etc/nginx/conf.d/default.conf + backend: + image: lasuite/impress-backend:v3.3.0 networks: - - backend - deploy: - labels: - # - "traefik.enable=true" - # - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=8083" - # - "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})" - # - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" - # - "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}" - # ## Redirect from EXTRA_DOMAINS to DOMAIN - # #- "traefik.http.routers.${STACK_NAME}.middlewares=${STACK_NAME}-redirect" - # ## Redirect HTTP to HTTPS - # # - "traefik.http.middlewares.${STACK_NAME}-redirect.redirectscheme.scheme=https" - # # - "traefik.http.middlewares.${STACK_NAME}-redirect.redirectscheme.permanent=true" - # ## When you're ready for release, run "abra recipe sync " to set this - - "coop-cloud.${STACK_NAME}.version=" - # ## Enable backups: https://docs.coopcloud.tech/maintainers/handbook/#how-do-i-configure-backuprestore - # # - "backupbot.backup=true" - # # - "backupbot.backup.path=/some/path" + - backend + environment: + <<: [*common-env, *postgres-env, *yprovider-env] + DJANGO_CONFIGURATION: Production healthcheck: - test: ["CMD", "curl", "-f", "http://localhost"] - interval: 30s - timeout: 10s - retries: 10 - start_period: 1m + test: ["CMD", "python", "manage.py", "check"] + interval: 15s + timeout: 30s + retries: 20 + start_period: 10s + + # backend-migration: + # image: lasuite/impress-backend:v3.3.0 + # networks: + # - backend + # command: ["python", "manage.py", "migrate", "--noinput"] + # environment: + # <<: [*common-env, *postgres-env, *yprovider-env] + # DJANGO_CONFIGURATION: Production + + celery: + image: lasuite/impress-backend:v3.3.0 + networks: + - backend + command: ["celery", "-A", "impress.celery_app", "worker", "-l", "INFO"] + environment: + <<: [*common-env, *postgres-env, *yprovider-env] + DJANGO_CONFIGURATION: Production + + y-provider: + image: lasuite/impress-y-provider:v3.3.0 + networks: + - backend + environment: *yprovider-env db: image: postgres:16 + networks: + - backend healthcheck: - test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"] + test: ["CMD", "pg_isready", "-q", "-U", "docs", "-d", "docs"] interval: 1s timeout: 2s retries: 300 - environment: *postgres-env - ports: - - "15432:5432" - networks: - - backend + environment: + <<: *postgres-env + PGDATA: var/lib/postgresql/data/pgdata + volumes: + - postgres:/var/lib/postgresql/data/pgdata redis: image: redis:5 networks: - - backend + - backend - mailcatcher: - image: sj26/mailcatcher:latest - ports: - - "1081:1080" + # minio-bootstrap: + # image: minio/mc + # environment: *minio-env + # networks: + # - backend + # entrypoint: > + # sh -c " + # /usr/bin/mc alias set docs http://minio:9000 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD} && \ + # /usr/bin/mc mb --ignore-existing docs/docs-media-storage && \ + # /usr/bin/mc version enable docs/docs-media-storage && \ + # exit 0;" minio: - # user: ${DOCKER_USER:-1000} image: minio/minio - environment: - - MINIO_ROOT_USER=impress - - MINIO_ROOT_PASSWORD=password - ports: - - '9000:9000' - - '9001:9001' + environment: *minio-env healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 1s timeout: 20s retries: 300 entrypoint: "" - command: minio server --console-address :9001 /data + networks: + - backend + command: minio server /data volumes: - minio:/data - networks: - - proxy - - backend - createbuckets: - image: minio/mc - entrypoint: > - sh -c " - /usr/bin/mc alias set impress http://minio:9000 impress password && \ - /usr/bin/mc mb impress/impress-media-storage && \ - /usr/bin/mc version enable impress/impress-media-storage && \ - exit 0;" + web: + image: nginx:1.27 + configs: + - source: nginx_conf + target: /etc/nginx/conf.d/default.conf networks: - - backend - - celery: - user: ${DOCKER_USER:-1000} - image: impress:backend-production - command: ["celery", "-A", "impress.celery_app", "worker", "-l", "INFO"] - environment: - <<: [*common-env, *postgres-env] - depends_on: - - app - networks: - - backend - - frontend: - user: "${DOCKER_USER:-1000}" - image: git.coopcloud.tech/coop-cloud-chaos-patchs/docs-frontend:v3.3.0 + proxy: + backend: + # volumes: + # - certs:/etc/nginx/ssl:ro deploy: labels: - "traefik.enable=true" - - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=3000" + - "traefik.docker.network=proxy" + - "traefik.http.routers.${STACK_NAME}.tls=true" + - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=8083" - "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})" - - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" - "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}" - networks: - - proxy + - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" - # crowdin: - # image: crowdin/cli:3.16.0 - # volumes: - # - ".:/app" - # env_file: - # - env.d/development/crowdin - # user: "${DOCKER_USER:-1000}" - # working_dir: /app - # - # node: - # image: node:22 - # user: "${DOCKER_USER:-1000}" - # environment: - # HOME: /tmp - # volumes: - # - ".:/app" - - y-provider: - user: ${DOCKER_USER:-1000} - image: git.coopcloud.tech/coop-cloud-chaos-patchs/docs-yprovider:v3.3.0 - environment: *common-env + # FIXME: remove + kc_postgresql: + image: postgres:16 networks: - backend + healthcheck: + test: ["CMD", "pg_isready", "-q", "-U", "keycloak", "-d", "keycloak"] + interval: 1s + timeout: 2s + retries: 300 + environment: + <<: *kc-postgres-env + PGDATA: var/lib/postgresql/data/pgdata + volumes: + - postgres_keycloak:/var/lib/postgresql/data/pgdata + + keycloak: + image: quay.io/keycloak/keycloak:26.1.0 + command: ["start"] + networks: + - proxy + - backend + environment: + <<: [*kc-keycloak-env, *kc-postgres-env] + # volumes: + # - certs:/etc/ssl/certs:ro + deploy: + labels: + - "traefik.enable=true" + - "traefik.docker.network=proxy" + - "traefik.http.routers.${STACK_NAME}-keycloak.tls=true" + - "traefik.http.services.${STACK_NAME}-keycloak.loadbalancer.server.port=8080" + - "traefik.http.routers.${STACK_NAME}-keycloak.rule=Host(`auth.${DOMAIN}`)" + - "traefik.http.routers.${STACK_NAME}-keycloak.tls.certresolver=${LETS_ENCRYPT_ENV}" + - "traefik.http.routers.${STACK_NAME}-keycloak.entrypoints=web-secure" networks: proxy: @@ -217,7 +262,11 @@ networks: backend: volumes: + postgres: minio: + # FIXME: remove this + postgres_keycloak: + # certs: configs: nginx_conf: diff --git a/nginx.conf b/nginx.conf index 55e78e0..3f800a4 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,7 +1,99 @@ +upstream docs_backend { + server backend:8000 fail_timeout=0; +} + +upstream docs_frontend { + server app:8080 fail_timeout=0; +} + server { listen 8083; server_name localhost; - charset utf-8; + + # Disables server version feedback on pages and in headers + server_tokens off; + + location @proxy_to_docs_backend { + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_redirect off; + proxy_pass http://docs_backend; + } + + location @proxy_to_docs_frontend { + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_redirect off; + proxy_pass http://docs_frontend; + } + + location / { + try_files $uri @proxy_to_docs_frontend; + } + + location /api { + try_files $uri @proxy_to_docs_backend; + } + + location /admin { + try_files $uri @proxy_to_docs_backend; + } + + # Proxy auth for collaboration server + location /collaboration/ws/ { + # Collaboration Auth request configuration + auth_request /collaboration-auth; + proxy_set_header X-Forwarded-Proto https; + auth_request_set $authHeader $upstream_http_authorization; + auth_request_set $canEdit $upstream_http_x_can_edit; + auth_request_set $userId $upstream_http_x_user_id; + + # Pass specific headers from the auth response + proxy_set_header Authorization $authHeader; + proxy_set_header X-Can-Edit $canEdit; + proxy_set_header X-User-Id $userId; + + # Ensure WebSocket upgrade + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + + # Collaboration server + proxy_pass http://y-provider:4444; + + # Set appropriate timeout for WebSocket + proxy_read_timeout 86400; + proxy_send_timeout 86400; + + # Preserve original host and additional headers + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Origin $http_origin; + proxy_set_header Host $host; + } + + location /collaboration-auth { + proxy_pass http://docs_backend/api/v1.0/documents/collaboration-auth/; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Original-URL $request_uri; + + # Prevent the body from being passed + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + proxy_set_header X-Original-Method $request_method; + } + + location /collaboration/api/ { + # Collaboration server + proxy_pass http://y-provider:4444; + proxy_set_header Host $host; + } # Proxy auth for media location /media/ { @@ -17,14 +109,13 @@ server { proxy_set_header X-Amz-Content-SHA256 $authContentSha256; # Get resource from Minio - proxy_pass http://minio:9000/impress-media-storage/; + proxy_pass http://minio:9000/docs-media-storage/; proxy_set_header Host minio:9000; - - add_header Content-Security-Policy "default-src 'none'" always; } location /media-auth { - proxy_pass http://app:8000/api/v1.0/documents/media-auth/; + proxy_pass http://docs_backend/api/v1.0/documents/media-auth/; + proxy_set_header X-Forwarded-Proto https; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;