services: ae-netscope: image: ghcr.io/whiteassassins/ae-netscope:v0.3.1-alpha depends_on: postgres: condition: service_healthy redis: condition: service_healthy environment: APP_ENV: docker APP_NAME: AE NetScope DEPLOYMENT_PLATFORM: docker APP_URL: ${APP_URL:-http://127.0.0.1:8080} APP_WEB_DIST_DIR: /app/web API_CORS_ORIGINS: ${API_CORS_ORIGINS:-http://127.0.0.1:8080} POSTGRES_HOST: postgres POSTGRES_PORT: 5432 POSTGRES_DB: ae_netscope POSTGRES_USER: ae_netscope POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change-me-local-only} REDIS_HOST: redis REDIS_PORT: 6379 REDIS_DB: 0 REDIS_PASSWORD: ${REDIS_PASSWORD:-change-me-redis-local-only} REDIS_RATE_LIMIT_FAIL_OPEN: "false" SESSION_SECRET: ${SESSION_SECRET:-change-me-at-least-32-random-bytes-local-only} DATA_ENCRYPTION_KEY: ${DATA_ENCRYPTION_KEY:-} DATA_DECRYPTION_FALLBACK_KEYS: ${DATA_DECRYPTION_FALLBACK_KEYS:-} MFA_ENCRYPTION_KEY: ${MFA_ENCRYPTION_KEY:-} MFA_DECRYPTION_FALLBACK_KEYS: ${MFA_DECRYPTION_FALLBACK_KEYS:-} INITIAL_SETUP_TOKEN: ${INITIAL_SETUP_TOKEN:-} SESSION_COOKIE_NAME: ae_netscope_session SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-false} SESSION_COOKIE_SAMESITE: strict SESSION_TTL_SECONDS: 28800 SESSION_IDLE_TIMEOUT_SECONDS: ${SESSION_IDLE_TIMEOUT_SECONDS:-1800} SESSION_TOUCH_INTERVAL_SECONDS: ${SESSION_TOUCH_INTERVAL_SECONDS:-60} SECURITY_HEADERS_ENABLED: true SECURITY_HSTS_ENABLED: ${SECURITY_HSTS_ENABLED:-false} SECURITY_HSTS_MAX_AGE: 31536000 MAX_IMPORT_JSON_BYTES: 2000000 MAX_REQUEST_BODY_BYTES: 1000000 AUTH_RATE_LIMIT_PER_MINUTE: 5 AUTH_FAILED_LOGIN_LIMIT: 10 AUTH_LOCKOUT_MINUTES: 15 AE_NETSCOPE_RUN_MIGRATIONS: true AE_NETSCOPE_PRE_MIGRATION_BACKUP: ${AE_NETSCOPE_PRE_MIGRATION_BACKUP:-true} AE_NETSCOPE_MIGRATION_BACKUP_DIR: /app/backups AE_NETSCOPE_MIGRATION_BACKUP_RETENTION_COUNT: ${AE_NETSCOPE_MIGRATION_BACKUP_RETENTION_COUNT:-10} INVENTORY_BACKUP_DIR: /app/backups INVENTORY_BACKUP_RETENTION_COUNT: ${INVENTORY_BACKUP_RETENTION_COUNT:-10} BACKUP_ENCRYPTION_KEY: ${BACKUP_ENCRYPTION_KEY:-} BACKUP_DECRYPTION_FALLBACK_KEYS: ${BACKUP_DECRYPTION_FALLBACK_KEYS:-} SESSION_RECORD_RETENTION_DAYS: ${SESSION_RECORD_RETENTION_DAYS:-30} AUDIT_RETENTION_DAYS: ${AUDIT_RETENTION_DAYS:-365} AE_NETSCOPE_AUTO_UPDATE_ENABLED: ${AE_NETSCOPE_AUTO_UPDATE_ENABLED:-false} AE_NETSCOPE_AUTO_UPDATE_COMMAND: ${AE_NETSCOPE_AUTO_UPDATE_COMMAND:-} WEBAUTHN_RP_ID: ${WEBAUTHN_RP_ID:-} WEBAUTHN_ORIGIN: ${WEBAUTHN_ORIGIN:-} WEBAUTHN_RP_NAME: ${WEBAUTHN_RP_NAME:-AE NetScope} ports: - "${AE_NETSCOPE_PORT:-8080}:8000" volumes: - ae_netscope_backups:/app/backups read_only: true tmpfs: - /tmp:size=64m,mode=1777 cap_drop: - ALL security_opt: - no-new-privileges:true init: true pids_limit: 256 restart: unless-stopped healthcheck: test: [ "CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health/live', timeout=3).read()", ] interval: 30s timeout: 5s retries: 3 start_period: 30s postgres: image: postgres:18-alpine environment: POSTGRES_DB: ae_netscope POSTGRES_USER: ae_netscope POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change-me-local-only} POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256 volumes: - ae_netscope_postgres:/var/lib/postgresql restart: unless-stopped security_opt: - no-new-privileges:true healthcheck: test: ["CMD-SHELL", "pg_isready -U ae_netscope -d ae_netscope"] interval: 10s timeout: 5s retries: 5 redis: image: redis:8-alpine environment: REDIS_PASSWORD: ${REDIS_PASSWORD:-change-me-redis-local-only} command: [ "redis-server", "--appendonly", "yes", "--protected-mode", "yes", "--requirepass", "${REDIS_PASSWORD:-change-me-redis-local-only}", ] volumes: - ae_netscope_redis:/data restart: unless-stopped security_opt: - no-new-privileges:true healthcheck: test: ["CMD-SHELL", "REDISCLI_AUTH=\"$${REDIS_PASSWORD:-change-me-redis-local-only}\" redis-cli ping"] interval: 10s timeout: 5s retries: 5 volumes: ae_netscope_backups: ae_netscope_postgres: ae_netscope_redis: