services: migrate: image: irdb-api:latest build: { context: ./api } command: migrate env_file: .env # SEC_REVIEW F20: rootfs read-only — /app source cannot be overwritten # by an RCE. Writable paths are restricted to the irdb-data volume # plus a few small tmpfs mounts (PHP `/tmp`, Caddy/FrankenPHP XDG # state). These tmpfs mounts inherit uid=1000 so the unprivileged # `app` user can write to them. read_only: true tmpfs: - /tmp:uid=1000,gid=1000,mode=1777 - /home/app/.config:uid=1000,gid=1000,mode=0700 - /home/app/.local/share:uid=1000,gid=1000,mode=0700 volumes: - irdb-data:/data restart: "no" api: image: irdb-api:latest command: api env_file: .env # SEC_REVIEW F20: see migrate above. read_only: true tmpfs: - /tmp:uid=1000,gid=1000,mode=1777 - /home/app/.config:uid=1000,gid=1000,mode=0700 - /home/app/.local/share:uid=1000,gid=1000,mode=0700 ports: - "8081:8081" volumes: - irdb-data:/data depends_on: migrate: condition: service_completed_successfully healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:8081/healthz"] interval: 30s timeout: 5s retries: 3 restart: unless-stopped ui: image: irdb-ui:latest build: { context: ./ui } env_file: .env # SEC_REVIEW F20: rootfs read-only. The ui has no /data volume — # all writes (PHP sessions in /tmp, Caddy/FrankenPHP XDG state) go # to ephemeral tmpfs mounts owned by uid=1000. read_only: true tmpfs: - /tmp:uid=1000,gid=1000,mode=1777 - /home/app/.config:uid=1000,gid=1000,mode=0700 - /home/app/.local/share:uid=1000,gid=1000,mode=0700 ports: - "8080:8080" depends_on: api: condition: service_healthy healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"] interval: 30s timeout: 5s retries: 3 restart: unless-stopped # Uncomment to use MySQL. Also set DB_DRIVER=mysql in .env. # mysql: # image: mysql:8 # environment: # MYSQL_DATABASE: ${DB_MYSQL_DATABASE} # MYSQL_USER: ${DB_MYSQL_USERNAME} # MYSQL_PASSWORD: ${DB_MYSQL_PASSWORD} # MYSQL_ROOT_PASSWORD: ${DB_MYSQL_ROOT_PASSWORD} # volumes: # - mysql-data:/var/lib/mysql # healthcheck: # test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] # interval: 10s # timeout: 5s # retries: 10 # restart: unless-stopped volumes: irdb-data: # mysql-data: