Files
dezky/infrastructure/docker-compose/docker-compose.yml
T
Ronni Baslund df18128617 feat(audit): OCIS file-tail ingest worker (Phase 2 chunk 3)
Tails OCIS's JSON-Lines audit log on a shared Docker volume and forwards
mutations into AuditService. Final piece of Phase 2 — the /audit page now
unifies platform-api, authentik, and ocis events on one timeline.

services/platform-api/src/ingest/ocis.ingest.ts:
  - 5s polling loop (fs.watch is unreliable across Docker bind mounts on
    macOS). Stat → detect inode change or truncation → resume from byte
    position OR start over.
  - Cursor in IngestCursor stores lastEventId = "<inode>:<bytePosition>".
    Restarts resume cleanly; on overlap the (source, externalId) unique
    index dedups silently.
  - Lines collected first, then processed sequentially after the read
    stream closes. Earlier draft fired recordOne() from inside the
    readline 'line' callback which would have resolved the stream
    before all writes finished — same class of race we hit in the
    Authentik worker, fixed before commit.
  - Tenant inference: spaceName (set during provisioning to the slug)
    first, then User.authentikSubjectId → tenantIds → Tenant.slug.
  - Mutations only: OCIS_ALLOWLIST in action-map.ts whitelists 24 event
    types (User/Group/Space/Share/Link/File mutations). FileDownloaded,
    UserSignedIn, and the rest of the high-volume read traffic gets
    skipped — keeps the timeline scannable.

services/platform-api/src/ingest/action-map.ts:
  - mapOcisAction() + OCIS_ALLOWLIST. Returns null for non-whitelisted
    types so the worker filters early.

infrastructure/docker-compose/docker-compose.yml:
  - New named volume `ocis_audit_log` mounted writeable on the ocis
    container and read-only on platform-api.
  - OCIS env: OCIS_ADD_RUN_SERVICES=audit (the audit microservice is
    NOT in the default `ocis server` set — opt in explicitly),
    AUDIT_LOG_FILE_PATH=/var/log/ocis/audit.log, AUDIT_LOG_FORMAT=json.
  - platform-api env: OCIS_AUDIT_LOG_PATH points at the same file.

Verified end-to-end with synthetic events written to the audit log:
  - Worker tailed 5 events across initial read + incremental append
    (5 → bytes 0:1276, then 1 → bytes 1276:1519).
  - FileDownloaded correctly filtered by the allowlist (4 mutations
    landed in Mongo, not 5).
  - Tenant inference: events with executingUser.id resolved to
    `dezky` via User → tenantIds → Tenant.slug.
  - Operator /audit shows all three sources (89 events: 79 authentik
    + 5 platform-api + 5 ocis) in one unified timeline.

Known unknown — same shape as the Stalwart commit: I couldn't fully
confirm the OCIS v7 audit microservice emits events with just
OCIS_ADD_RUN_SERVICES=audit + the AUDIT_LOG_FILE_PATH env. The audit
service starts but the file stays empty until OCIS internals start
publishing events to NATS (which may need additional service-side
config). The ingest worker is correct regardless — when OCIS starts
writing real events, they'll flow into /audit. This is a follow-up
in the OCIS-side configuration, not in our ingest code.
2026-05-24 20:30:47 +02:00

499 lines
23 KiB
YAML

# Dezky — Local Development Stack
#
# Start: docker compose up -d
# Logs: docker compose logs -f [service]
# Stop: docker compose down
# Reset: docker compose down -v (WARNING: deletes all data)
#
# Prerequisites:
# 1. mkcert root CA installed (mkcert -install)
# 2. Wildcard cert generated in ./certs/dezky.local.pem
# 3. /etc/hosts entries added (run scripts/setup-hosts.sh)
# 4. .env file created from .env.example
name: dezky
networks:
dezky:
name: dezky
driver: bridge
volumes:
postgres_data:
mongo_data:
redis_data:
authentik_media:
authentik_certs:
authentik_templates:
stalwart_data:
ocis_config:
ocis_data:
ocis_audit_log:
portal_node_modules:
platform_api_node_modules:
operator_node_modules:
services:
# ─────────────────────────────────────────────────────────────────
# Traefik — Reverse proxy with TLS termination via mkcert
# ─────────────────────────────────────────────────────────────────
traefik:
image: traefik:v3.7
container_name: dezky-traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8443:8080" # Dashboard
volumes:
- ${DOCKER_SOCKET:-/var/run/docker.sock}:/var/run/docker.sock:ro
- ./configs/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- ./configs/traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro
- ./certs:/certs:ro
networks:
dezky:
aliases:
- traefik.dezky.local
- auth.dezky.local
- app.dezky.local
- operator.dezky.local
- api.dezky.local
- files.dezky.local
- mail.dezky.local
- office.dezky.local
- collaboration.dezky.local
labels:
- traefik.enable=true
- traefik.http.routers.dashboard.rule=Host(`traefik.dezky.local`)
- traefik.http.routers.dashboard.service=api@internal
- traefik.http.routers.dashboard.tls=true
# ─────────────────────────────────────────────────────────────────
# PostgreSQL — Shared RDBMS (Authentik, OCIS)
# ─────────────────────────────────────────────────────────────────
postgres:
image: postgres:16-alpine
container_name: dezky-postgres
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${POSTGRES_ROOT_PASSWORD}
POSTGRES_DB: postgres
AUTHENTIK_DB_PASSWORD: ${AUTHENTIK_DB_PASSWORD}
OCIS_DB_PASSWORD: ${OCIS_DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./configs/postgres/init.sh:/docker-entrypoint-initdb.d/init.sh:ro
networks: [dezky]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
# ─────────────────────────────────────────────────────────────────
# MongoDB — Portal application data
# ─────────────────────────────────────────────────────────────────
mongo:
image: mongo:7
container_name: dezky-mongo
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
MONGO_INITDB_DATABASE: dezky
volumes:
- mongo_data:/data/db
networks: [dezky]
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
# ─────────────────────────────────────────────────────────────────
# Redis — Cache + session store
# ─────────────────────────────────────────────────────────────────
redis:
image: redis:7-alpine
container_name: dezky-redis
restart: unless-stopped
command: redis-server --save 60 1 --loglevel warning --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
networks: [dezky]
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 3s
retries: 5
# ─────────────────────────────────────────────────────────────────
# Authentik — Identity provider (OIDC/SAML SSO)
# ─────────────────────────────────────────────────────────────────
authentik-server:
image: ghcr.io/goauthentik/server:2025.10
container_name: dezky-authentik
restart: unless-stopped
command: server
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_REDIS__PASSWORD: ${REDIS_PASSWORD}
AUTHENTIK_POSTGRESQL__HOST: postgres
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
AUTHENTIK_DISABLE_UPDATE_CHECK: "true"
AUTHENTIK_BOOTSTRAP_EMAIL: admin@dezky.local
AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD}
AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN}
volumes:
- authentik_media:/media
- authentik_certs:/certs
- authentik_templates:/templates
- ./configs/authentik/blueprints:/blueprints/custom:ro
networks: [dezky]
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
labels:
- traefik.enable=true
- traefik.http.routers.authentik.rule=Host(`auth.dezky.local`)
- traefik.http.routers.authentik.tls=true
- traefik.http.services.authentik.loadbalancer.server.port=9000
authentik-worker:
image: ghcr.io/goauthentik/server:2025.10
container_name: dezky-authentik-worker
restart: unless-stopped
command: worker
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_REDIS__PASSWORD: ${REDIS_PASSWORD}
AUTHENTIK_POSTGRESQL__HOST: postgres
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
volumes:
- authentik_media:/media
- authentik_certs:/certs
- authentik_templates:/templates
networks: [dezky]
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
# ─────────────────────────────────────────────────────────────────
# Stalwart Mail — Mail server (SMTP/IMAP/JMAP/CalDAV/CardDAV/ActiveSync)
# ─────────────────────────────────────────────────────────────────
stalwart:
image: stalwartlabs/stalwart:v0.16
container_name: dezky-stalwart
restart: unless-stopped
ports:
- "25:25" # SMTP
- "465:465" # SMTPS
- "587:587" # Submission
- "143:143" # IMAP
- "993:993" # IMAPS
- "4190:4190" # ManageSieve
environment:
STALWART_FQDN: mail.dezky.local
# Pin the recovery admin so it survives restarts. Without this, Stalwart
# generates a one-time-shown password at first boot and discards it after
# initial setup.
STALWART_RECOVERY_ADMIN: admin:${STALWART_ADMIN_PASSWORD}
# Shared HMAC secret for the audit webhook POSTed to platform-api.
# config.toml references this via %{env:STALWART_WEBHOOK_SECRET}%.
STALWART_WEBHOOK_SECRET: ${STALWART_WEBHOOK_SECRET}
volumes:
- stalwart_data:/opt/stalwart
- ./configs/stalwart/config.toml:/opt/stalwart/etc/config.toml:ro
networks: [dezky]
labels:
- traefik.enable=true
- traefik.http.routers.stalwart.rule=Host(`mail.dezky.local`)
- traefik.http.routers.stalwart.tls=true
- traefik.http.services.stalwart.loadbalancer.server.port=8080
# ─────────────────────────────────────────────────────────────────
# OCIS — File storage with S3-compatible backend
# ─────────────────────────────────────────────────────────────────
ocis:
image: owncloud/ocis:7.0
container_name: dezky-ocis
restart: unless-stopped
entrypoint: /bin/sh
command: ["-c", "ocis init --insecure true || true && ocis server"]
environment:
OCIS_URL: https://files.dezky.local
OCIS_LOG_LEVEL: warn
OCIS_INSECURE: "true" # dev only — self-signed certs
PROXY_HTTP_ADDR: 0.0.0.0:9200
PROXY_TLS: "false" # Traefik terminates TLS; OCIS speaks plain HTTP internally
OCIS_OIDC_ISSUER: https://auth.dezky.local/application/o/ocis/
WEB_OIDC_CLIENT_ID: ocis-web
PROXY_AUTOPROVISION_ACCOUNTS: "true"
PROXY_USER_OIDC_CLAIM: preferred_username
PROXY_USER_CS3_CLAIM: username
OCIS_ADMIN_USER_ID: ""
IDM_CREATE_DEMO_USERS: "false"
IDM_ADMIN_PASSWORD: ${OCIS_ADMIN_PASSWORD}
STORAGE_USERS_DRIVER: ocis # Local filesystem in dev
STORAGE_SYSTEM_DRIVER: ocis
OCIS_CONFIG_DIR: /etc/ocis
OCIS_BASE_DATA_PATH: /var/lib/ocis
# Extend CSP so the OCIS web SPA can reach Authentik for OIDC metadata.
# Enforced by the OCIS proxy service, not web — env var is PROXY_-prefixed.
PROXY_CSP_CONFIG_FILE_LOCATION: /etc/ocis/csp.yaml
# Expose the embedded NATS service registry and gRPC services on the Docker
# network so the collaboration container can talk to OCIS internals.
NATS_NATS_HOST: 0.0.0.0
NATS_NATS_PORT: 9233
GATEWAY_GRPC_ADDR: 0.0.0.0:9142
MICRO_GRPC_CLIENT_DNS_CACHE_TIMEOUT: 10s
# Audit service — JSON Lines to a shared volume that platform-api also
# mounts read-only. Used by the OCIS ingest worker to fold file/share
# mutations into the global audit timeline. The audit microservice is
# NOT part of the default `ocis server` set so we opt in explicitly.
OCIS_ADD_RUN_SERVICES: audit
AUDIT_LOG_FILE_PATH: /var/log/ocis/audit.log
AUDIT_LOG_FORMAT: json
volumes:
- ocis_config:/etc/ocis
- ocis_data:/var/lib/ocis
- ocis_audit_log:/var/log/ocis
- ./configs/ocis/csp.yaml:/etc/ocis/csp.yaml:ro
networks: [dezky]
depends_on:
- authentik-server
labels:
- traefik.enable=true
- traefik.http.routers.ocis.rule=Host(`files.dezky.local`)
- traefik.http.routers.ocis.tls=true
- traefik.http.services.ocis.loadbalancer.server.port=9200
# ─────────────────────────────────────────────────────────────────
# Collabora — Office document editor (loaded inside an iframe by OCIS)
# ─────────────────────────────────────────────────────────────────
collabora:
image: collabora/code:latest
container_name: dezky-collabora
restart: unless-stopped
cap_add:
- MKNOD
environment:
# Allow the WOPI host (OCIS collaboration service) to talk to Collabora
aliasgroup1: https://collaboration.dezky.local:443
DONT_GEN_SSL_CERT: "true"
# frame_ancestors: which hosts may embed Collabora in an iframe.
# Without this set, browsers block the iframe with a Danish "Indhold blokeret".
# home_mode.enable=true disables the "Explore The New" welcome popup AND the
# feedback prompt; caps at 20 connections / 10 documents (fine for dev).
extra_params: --o:ssl.enable=false --o:ssl.termination=true --o:ssl.ssl_verification=false --o:home_mode.enable=true --o:feedback.show=false --o:net.frame_ancestors=files.dezky.local
username: admin
password: ${COLLABORA_ADMIN_PASSWORD}
# Generate a fresh WOPI proof key on every start so the public key Collabora
# advertises matches the private key it signs with. Without this, the OCIS
# collaboration service rejects WOPI calls with "ProofKeys verification failed".
entrypoint: ["/bin/bash", "-c"]
command: ["coolconfig generate-proof-key && /start-collabora-online.sh"]
networks: [dezky]
labels:
- traefik.enable=true
- traefik.http.routers.collabora.rule=Host(`office.dezky.local`)
- traefik.http.routers.collabora.tls=true
- traefik.http.services.collabora.loadbalancer.server.port=9980
# ─────────────────────────────────────────────────────────────────
# OCIS Collaboration — WOPI bridge between OCIS storage and Collabora.
# Shares the ocis_config volume so it picks up the same JWT/transfer secrets
# that ocis init generated. Without this, opening a .docx just downloads.
# ─────────────────────────────────────────────────────────────────
collaboration:
image: owncloud/ocis:7.0
container_name: dezky-collaboration
restart: unless-stopped
entrypoint: ["/bin/sh", "-c"]
command: ["ocis collaboration server"]
environment:
OCIS_URL: https://files.dezky.local
OCIS_LOG_LEVEL: warn
OCIS_INSECURE: "true"
OCIS_CONFIG_DIR: /etc/ocis
OCIS_BASE_DATA_PATH: /var/lib/ocis
COLLABORATION_HTTP_ADDR: 0.0.0.0:9300
COLLABORATION_GRPC_ADDR: 0.0.0.0:9301
COLLABORATION_WOPI_SRC: https://collaboration.dezky.local
COLLABORATION_APP_NAME: Collabora
COLLABORATION_APP_PRODUCT: Collabora
COLLABORATION_APP_DESCRIPTION: Collabora Online
# APP_ADDR is sent to the browser as the iframe src — must be public, not the
# Docker-internal hostname. Collaboration → Collabora traffic goes via Traefik.
COLLABORATION_APP_ADDR: https://office.dezky.local
COLLABORATION_APP_INSECURE: "true"
COLLABORATION_CS3API_DATAGATEWAY_INSECURE: "true"
# Match OCIS JWT/secrets via the shared config volume.
# Service registry: connect to OCIS's embedded NATS (not localhost).
MICRO_REGISTRY: nats-js-kv
MICRO_REGISTRY_ADDRESS: ocis:9233
# Direct gRPC pointer to OCIS's gateway (collaboration can't rely on registry
# lookups returning the right hostname for cross-container traffic).
REVA_GATEWAY: ocis:9142
volumes:
- ocis_config:/etc/ocis
- ocis_data:/var/lib/ocis
networks: [dezky]
depends_on:
- ocis
- collabora
labels:
- traefik.enable=true
- traefik.http.routers.collaboration.rule=Host(`collaboration.dezky.local`)
- traefik.http.routers.collaboration.tls=true
- traefik.http.services.collaboration.loadbalancer.server.port=9300
# ─────────────────────────────────────────────────────────────────
# Portal — Nuxt 3 customer portal (development mode with HMR)
# ─────────────────────────────────────────────────────────────────
portal:
image: node:20-alpine
container_name: dezky-portal
restart: unless-stopped
working_dir: /app
command: sh -c "corepack enable && corepack prepare pnpm@latest --activate && pnpm install && pnpm dev"
environment:
NODE_ENV: development
NUXT_HOST: 0.0.0.0
NUXT_PORT: 3000
NUXT_PUBLIC_AUTH_URL: https://auth.dezky.local
NUXT_PUBLIC_PORTAL_URL: https://app.dezky.local
NUXT_API_BASE: http://platform-api:3001
PLATFORM_API_INTERNAL_URL: http://platform-api:3001
MONGODB_URI: mongodb://root:${MONGO_ROOT_PASSWORD}@mongo:27017/dezky?authSource=admin
# OIDC (confidential client) — used by Nuxt server middleware
NUXT_OIDC_CLIENT_ID: ${PORTAL_OIDC_CLIENT_ID}
NUXT_OIDC_CLIENT_SECRET: ${PORTAL_OIDC_CLIENT_SECRET}
NUXT_OIDC_ISSUER: ${PORTAL_OIDC_ISSUER}
NUXT_OIDC_REDIRECT_URI: https://app.dezky.local/auth/oidc/callback
# Session encryption (required by nuxt-oidc-auth)
NUXT_OIDC_TOKEN_KEY: ${NUXT_OIDC_TOKEN_KEY}
NUXT_OIDC_SESSION_SECRET: ${NUXT_OIDC_SESSION_SECRET}
NUXT_OIDC_AUTH_SESSION_SECRET: ${NUXT_OIDC_AUTH_SESSION_SECRET}
# Trust mkcert root CA for Node fetch (dev only)
NODE_EXTRA_CA_CERTS: /etc/ssl/mkcert-root.pem
volumes:
- ../../apps/portal:/app
- portal_node_modules:/app/node_modules
- ./certs/mkcert-root.pem:/etc/ssl/mkcert-root.pem:ro
networks: [dezky]
depends_on:
mongo:
condition: service_healthy
labels:
- traefik.enable=true
- traefik.http.routers.portal.rule=Host(`app.dezky.local`) || Host(`dezky.local`)
- traefik.http.routers.portal.tls=true
- traefik.http.services.portal.loadbalancer.server.port=3000
# ─────────────────────────────────────────────────────────────────
# Operator portal — internal admin app at operator.dezky.local.
# Separate from the customer portal: own OAuth client (dezky-operator),
# own session secrets, own cookie domain. Audience-gated mutations on
# platform-api require the token this app mints.
# ─────────────────────────────────────────────────────────────────
operator:
image: node:20-alpine
container_name: dezky-operator
restart: unless-stopped
working_dir: /app
command: sh -c "corepack enable && corepack prepare pnpm@latest --activate && pnpm install && pnpm dev"
environment:
NODE_ENV: development
NUXT_HOST: 0.0.0.0
NUXT_PORT: 3000
NUXT_PUBLIC_AUTH_URL: https://auth.dezky.local
# OIDC — dezky-operator OAuth client (separate from dezky-portal)
NUXT_OIDC_CLIENT_ID: ${OPERATOR_OIDC_CLIENT_ID}
NUXT_OIDC_CLIENT_SECRET: ${OPERATOR_OIDC_CLIENT_SECRET}
NUXT_OIDC_ISSUER: ${OPERATOR_OIDC_ISSUER}
NUXT_OIDC_REDIRECT_URI: https://operator.dezky.local/auth/oidc/callback
# Session encryption — distinct from portal so the two surfaces can't
# decrypt each other's session cookies
NUXT_OIDC_TOKEN_KEY: ${OPERATOR_NUXT_OIDC_TOKEN_KEY}
NUXT_OIDC_SESSION_SECRET: ${OPERATOR_NUXT_OIDC_SESSION_SECRET}
NUXT_OIDC_AUTH_SESSION_SECRET: ${OPERATOR_NUXT_OIDC_AUTH_SESSION_SECRET}
# Reach platform-api internally for the server-side token-forwarding proxy
PLATFORM_API_INTERNAL_URL: http://platform-api:3001
NODE_EXTRA_CA_CERTS: /etc/ssl/mkcert-root.pem
volumes:
- ../../apps/operator:/app
- operator_node_modules:/app/node_modules
- ./certs/mkcert-root.pem:/etc/ssl/mkcert-root.pem:ro
networks: [dezky]
labels:
- traefik.enable=true
- traefik.http.routers.operator.rule=Host(`operator.dezky.local`)
- traefik.http.routers.operator.tls=true
- traefik.http.services.operator.loadbalancer.server.port=3000
# ─────────────────────────────────────────────────────────────────
# platform-api — NestJS service. Owns tenants, partners, users,
# subscriptions, and provisioning orchestration.
# ─────────────────────────────────────────────────────────────────
platform-api:
image: node:20-alpine
container_name: dezky-platform-api
restart: unless-stopped
working_dir: /app
command: sh -c "corepack enable && corepack prepare pnpm@latest --activate && pnpm install && pnpm start:dev"
environment:
NODE_ENV: development
PORT: 3001
MONGODB_URI: mongodb://root:${MONGO_ROOT_PASSWORD}@mongo:27017/dezky?authSource=admin
AUTHENTIK_API_URL: https://auth.dezky.local/api/v3
AUTHENTIK_API_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN}
STALWART_API_URL: https://mail.dezky.local
STALWART_ADMIN_USER: admin
STALWART_ADMIN_PASSWORD: ${STALWART_ADMIN_PASSWORD}
# HMAC secret Stalwart signs its webhook POSTs with; we verify on
# /ingest/stalwart/webhook. Both ends read the same env var.
STALWART_WEBHOOK_SECRET: ${STALWART_WEBHOOK_SECRET}
OCIS_API_URL: https://files.dezky.local
# JWT validation against Authentik for portal-issued access tokens.
# Issuers are comma-separated — each Authentik OAuth provider issues tokens
# with its own per-app issuer URL, so we accept both portal and operator.
AUTHENTIK_ISSUER: https://auth.dezky.local/application/o/dezky-portal/,https://auth.dezky.local/application/o/dezky-operator/
# Comma-separated list of accepted JWT audiences. Tokens issued for either
# the customer portal or the operator portal are valid against this service;
# per-endpoint guards further restrict operator-only mutations.
AUTHENTIK_AUDIENCE: dezky-portal,dezky-operator
AUTHENTIK_JWKS_URI: https://auth.dezky.local/application/o/dezky-portal/jwks/
# Trust mkcert root CA for Node fetch (dev only)
NODE_EXTRA_CA_CERTS: /etc/ssl/mkcert-root.pem
# Path to the OCIS audit log inside this container. The same shared
# volume is mounted on the OCIS service writeable; here it's read-only.
OCIS_AUDIT_LOG_PATH: /var/log/ocis/audit.log
volumes:
- ../../services/platform-api:/app
- platform_api_node_modules:/app/node_modules
- ./certs/mkcert-root.pem:/etc/ssl/mkcert-root.pem:ro
- ocis_audit_log:/var/log/ocis:ro
networks: [dezky]
depends_on:
mongo:
condition: service_healthy
labels:
- traefik.enable=true
- traefik.http.routers.api.rule=Host(`api.dezky.local`)
- traefik.http.routers.api.tls=true
- traefik.http.services.api.loadbalancer.server.port=3001