services: account-server: image: ${ACCOUNT_IMAGE:-ghcr.io/hkgood/osg-account-server}:${IMAGE_TAG:-main} pull_policy: always restart: unless-stopped init: true user: "10001:10001" stop_grace_period: 30s environment: APP_ENV: production PORT: "8080" PUBLIC_BASE_URL: https://account.osglab.com INVITE_BASE_URL: https://osglab.com/i APP_STORE_URL: ${APP_STORE_URL:?set the production App Store HTTPS URL} # Reuse the existing MySQL; this stack intentionally creates no database. DATABASE_URL: ${DATABASE_URL:?set DATABASE_URL for the existing MySQL} DATABASE_USER: ${DATABASE_USER:?set DATABASE_USER} DATABASE_PASSWORD: ${DATABASE_PASSWORD:?set DATABASE_PASSWORD} DATABASE_POOL_SIZE: ${DATABASE_POOL_SIZE:-10} DATABASE_MIGRATION_USER: ${DATABASE_MIGRATION_USER:?set DATABASE_MIGRATION_USER} DATABASE_MIGRATION_PASSWORD: ${DATABASE_MIGRATION_PASSWORD:?set DATABASE_MIGRATION_PASSWORD} JWT_ISSUER: https://account.osglab.com JWT_AUDIENCE: ${JWT_AUDIENCE:-osgkeyboard-ios} JWT_SECRET: ${JWT_SECRET:?set a random JWT secret} ACCESS_TOKEN_MINUTES: ${ACCESS_TOKEN_MINUTES:-15} REFRESH_TOKEN_DAYS: ${REFRESH_TOKEN_DAYS:-30} GATEWAY_GRANT_DAYS: ${GATEWAY_GRANT_DAYS:-30} FIELD_ENCRYPTION_KEY: ${FIELD_ENCRYPTION_KEY:?set a 32-byte Base64 key} IDENTITY_HMAC_KEY: ${IDENTITY_HMAC_KEY:?set a distinct Base64 key} IDENTITY_TOMBSTONE_RETENTION_DAYS: ${IDENTITY_TOMBSTONE_RETENTION_DAYS:-365} ADMIN_ENABLED: ${ADMIN_ENABLED:-false} ADMIN_BOOTSTRAP_ENABLED: ${ADMIN_BOOTSTRAP_ENABLED:-false} ADMIN_BOOTSTRAP_OPERATOR_ID: ${ADMIN_BOOTSTRAP_OPERATOR_ID:-} ADMIN_BOOTSTRAP_USERNAME: ${ADMIN_BOOTSTRAP_USERNAME:-} ADMIN_BOOTSTRAP_PASSWORD_HASH: ${ADMIN_BOOTSTRAP_PASSWORD_HASH:-} ADMIN_BOOTSTRAP_TOTP_SECRET_BASE32: ${ADMIN_BOOTSTRAP_TOTP_SECRET_BASE32:-} ADMIN_SESSION_HOURS: ${ADMIN_SESSION_HOURS:-8} ADMIN_MAXIMUM_MANUAL_GRANT: ${ADMIN_MAXIMUM_MANUAL_GRANT:-100000} APPLE_TEAM_ID: ${APPLE_TEAM_ID:?set Apple team ID} APPLE_KEY_ID: ${APPLE_KEY_ID:?set Apple key ID} APPLE_CLIENT_ID: ${APPLE_CLIENT_ID:-com.osgkeyboard.ios} APPLE_PRIVATE_KEY_PEM: ${APPLE_PRIVATE_KEY_PEM:?set Apple private key PEM} APPLE_INTEGRITY_ENVIRONMENT: production APP_ATTEST_CHALLENGE_TTL_SECONDS: ${APP_ATTEST_CHALLENGE_TTL_SECONDS:-300} ENFORCE_DEVICE_CHECK: "true" ENFORCE_APP_ATTEST: "true" VOLCENGINE_API_KEY: ${VOLCENGINE_API_KEY:?set Volcengine API key} VOLCENGINE_RESOURCE_ID: ${VOLCENGINE_RESOURCE_ID:-volc.seedasr.sauc.duration} VOLCENGINE_ASR_ENDPOINT: ${VOLCENGINE_ASR_ENDPOINT:-wss://openspeech.bytedance.com/api/v3/sauc/bigmodel} DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:?set DeepSeek API key} DEEPSEEK_MODEL: ${DEEPSEEK_MODEL:-deepseek-v4-flash} DEEPSEEK_ENDPOINT: ${DEEPSEEK_ENDPOINT:-https://api.deepseek.com/v1} SIGNUP_TRIAL_CREDITS: ${SIGNUP_TRIAL_CREDITS:-1000} REFERRAL_INVITER_CREDITS: ${REFERRAL_INVITER_CREDITS:-3000} REFERRAL_INVITEE_CREDITS: ${REFERRAL_INVITEE_CREDITS:-3000} REFERRAL_BINDING_DAYS: ${REFERRAL_BINDING_DAYS:-7} ports: - "127.0.0.1:${ACCOUNT_BIND_PORT:-18080}:8080" read_only: true pids_limit: 256 tmpfs: - /tmp:size=64m,mode=1777,noexec,nosuid,nodev cap_drop: - ALL security_opt: - no-new-privileges:true healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8080/health/ready"] interval: 30s timeout: 3s start_period: 30s retries: 3 logging: driver: json-file options: max-size: "10m" max-file: "3" networks: - account-backend # Separate egress keeps Apple/provider traffic available when the shared # database network was created with Docker's --internal flag. - account-egress networks: # Pre-create this shared network with: # docker network create --internal account-backend # Attach the existing MySQL container without publishing port 3306. account-backend: external: true name: ${ACCOUNT_DOCKER_NETWORK:-account-backend} account-egress: driver: bridge