# ───────────────────────────────────────────────────────────────────── # AlianHub - Project Management System (self-hosted) # # Quick start: # 1. Copy .env.example to .env and set at least JWT_SECRET # 2. docker compose up -d # 3. Open http://localhost:4000 # # Update to a newer version: # docker compose pull && docker compose up -d # # Build the image from local source instead of pulling the registry image: # docker compose build # docker compose up -d # ───────────────────────────────────────────────────────────────────── services: # ── AlianHub backend + bundled frontend ──────────────────────────── app: image: ghcr.io/aliansoftwareteam/alianhub:${ALIANHUB_VERSION:-latest} build: context: . dockerfile: Dockerfile container_name: ${ALIANHUB_APP_CONTAINER:-alianhub} restart: unless-stopped ports: - "${APP_PORT:-4000}:4000" environment: # Required — the app derives one database per company from this base URL, # so give the server address only, never a database name. MONGODB_URL: mongodb://mongo:27017 # Required — generate a random string for each new install JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required — set it in .env} # Optional — public URL clients use to reach the API APIURL: ${APIURL:-http://localhost:4000/} WEBURL: ${WEBURL:-http://localhost:4000} # Optional — "server" (local filesystem) or "wasabi" (S3-compatible) STORAGE_TYPE: ${STORAGE_TYPE:-server} # Optional — override port (uncommon) PORT: 4000 env_file: # Picks up any additional env vars defined in .env (e.g. SMTP, OAuth) - path: .env required: false volumes: # Uploaded files when STORAGE_TYPE=server - alianhub_storage:/app/storage # Rotating application logs, readable from Settings > Instance > Logs - alianhub_logs:/app/log # Backups taken from Settings > Instance > Backups - alianhub_backups:/app/backups depends_on: mongo: condition: service_healthy networks: - alianhub # ── MongoDB ─────────────────────────────────────────────────────── mongo: image: mongo:7 container_name: ${ALIANHUB_MONGO_CONTAINER:-alianhub-mongo} restart: unless-stopped volumes: - alianhub_mongo_data:/data/db # Don't expose Mongo on the host by default — the app talks to it # over the internal network only. Uncomment to access from host: # ports: # - "27017:27017" healthcheck: test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"] interval: 10s timeout: 5s retries: 5 start_period: 30s networks: - alianhub # ── TURN relay for audio/video calling (optional) ────────────────── # # Calls are peer-to-peer, so most connect browser-to-browser with no help. # A minority cannot — symmetric NAT and strict corporate firewalls, roughly # 15-20% of real connections — and those need a relay or they simply fail. # # Disabled by default because it only works with real configuration: a # public IP the relay can advertise, and open ports. Enable with: # # docker compose --profile calling up -d # # then set in .env: # TURN_URLS="turn::3478" # TURN_STATIC_AUTH_SECRET="" # # NOTE: host networking is used because a relay has to hand out addresses # that are reachable from the outside; behind Docker's NAT it would # advertise an address only the container can reach. # # The two required values are checked inside the container rather than with # `${VAR:?}`: compose interpolates the whole file even for inactive profiles, # so a `:?` here would break `docker compose up` for everyone. coturn: image: coturn/coturn:4.6-alpine container_name: ${ALIANHUB_COTURN_CONTAINER:-alianhub-coturn} restart: unless-stopped profiles: ["calling"] network_mode: host environment: TURN_REALM: ${TURN_REALM:-alianhub} TURN_STATIC_AUTH_SECRET: ${TURN_STATIC_AUTH_SECRET:-} TURN_PUBLIC_IP: ${TURN_PUBLIC_IP:-} entrypoint: ["/bin/sh", "-c"] command: - > if [ -z "$$TURN_STATIC_AUTH_SECRET" ] || [ -z "$$TURN_PUBLIC_IP" ]; then echo "coturn: set TURN_STATIC_AUTH_SECRET and TURN_PUBLIC_IP in .env" >&2; exit 1; fi; exec turnserver -n --realm="$$TURN_REALM" --use-auth-secret --static-auth-secret="$$TURN_STATIC_AUTH_SECRET" --external-ip="$$TURN_PUBLIC_IP" --listening-port=3478 --min-port=49160 --max-port=49200 --no-cli --no-tlsv1 --no-tlsv1_1 volumes: alianhub_mongo_data: name: alianhub_mongo_data alianhub_storage: name: alianhub_storage alianhub_logs: name: alianhub_logs alianhub_backups: name: alianhub_backups networks: alianhub: name: alianhub driver: bridge