tarakan/deploy/docker/compose.yml
Maxfield Luke af6077b9c3
All checks were successful
CI and deploy / Test (push) Successful in 4m52s
CI and deploy / Deploy production (push) Successful in 23s
Initial commit on Forgejo
Fresh repository history for elektrine/tarakan hosted at
https://git.elektrine.com/elektrine/tarakan.
2026-07-29 04:43:40 -04:00

110 lines
4.5 KiB
YAML

# Single-node Tarakan deployment: the Phoenix release plus PostgreSQL.
#
# From the repo root (or /opt/tarakan after rsync):
#
# 1. cp .env.example .env && edit it (at minimum SECRET_KEY_BASE, PHX_HOST)
# 2. docker compose --project-directory . -f deploy/docker/compose.yml up -d --build
#
# Production activate path: scripts/deploy/deploy.sh (loads a pre-built image).
# Put a TLS-terminating reverse proxy (Caddy, nginx, Traefik) in front for HTTPS.
services:
db:
image: postgres:16
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
environment:
POSTGRES_USER: ${POSTGRES_USER:?set POSTGRES_USER in .env}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: ${POSTGRES_DB:-tarakan}
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 5s
timeout: 5s
retries: 10
app:
image: ${APP_IMAGE:-tarakan-app}
build:
context: ../..
dockerfile: deploy/docker/Dockerfile
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
security_opt:
- no-new-privileges:true
# Erlang sizes its port table from RLIMIT_NOFILE. Some Docker hosts expose
# a billion-file limit, which wastes more than 1 GB before serving traffic.
ulimits:
nofile:
soft: 65536
hard: 65536
depends_on:
db:
condition: service_healthy
environment:
# Required.
DATABASE_URL: ecto://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db/${POSTGRES_DB:-tarakan}
# Same Docker network as Postgres — no TLS between containers.
DATABASE_SSL: ${DATABASE_SSL:-false}
SECRET_KEY_BASE: ${SECRET_KEY_BASE:?set SECRET_KEY_BASE in .env (mix phx.gen.secret)}
PHX_HOST: ${PHX_HOST:-localhost}
PORT: ${PORT:-4000}
# Keep the default pool small enough for the minimum 2 GB deployment.
POOL_SIZE: ${POOL_SIZE:-5}
# When a reverse proxy sits in front, list its Docker/host CIDRs so client
# IPs and rate limits are correct (e.g. 172.16.0.0/12,127.0.0.1).
TRUSTED_PROXIES: ${TRUSTED_PROXIES:-}
# Persistent repository storage (see volumes below).
MIRROR_DIR: /app/storage/mirrors
HOSTED_DIR: /app/storage/hosted
# Git over SSH. Off unless GIT_SSH_ENABLED is true|1. The host key lives
# on its own volume: it is the server's identity, so regenerating it
# makes every client that has ever connected refuse with
# "REMOTE HOST IDENTIFICATION HAS CHANGED".
GIT_SSH_ENABLED: ${GIT_SSH_ENABLED:-false}
GIT_SSH_PORT: ${GIT_SSH_PORT:-2222}
GIT_SSH_HOST_KEY_DIR: /app/storage/ssh
# Recommended in production: authenticated GitHub API (5k req/hr, bulk sync).
GITHUB_TOKEN: ${GITHUB_TOKEN:-}
# Optional OAuth sign-in.
GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}
GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}
# Transactional email through Elektrine's scoped external API.
ELEKTRINE_EMAIL_API_URL: ${ELEKTRINE_EMAIL_API_URL:-https://elektrine.com}
ELEKTRINE_EMAIL_API_KEY: ${ELEKTRINE_EMAIL_API_KEY:?set ELEKTRINE_EMAIL_API_KEY in .env}
# Migrate, then serve. Both boot the release; migrate exits first.
command: ["/bin/sh", "-c", "/app/bin/migrate && /app/bin/server"]
ports:
# The TLS proxy runs on the host. Do not expose Phoenix directly.
- "${BIND_IP:-127.0.0.1}:${PORT:-4000}:${PORT:-4000}"
# SSH speaks its own transport, so unlike HTTP it is published directly
# rather than proxied. Bound to all interfaces by default because a git
# remote has to reach it from outside the host; set GIT_SSH_BIND_IP to
# narrow it. Harmless while GIT_SSH_ENABLED is false - nothing listens.
- "${GIT_SSH_BIND_IP:-0.0.0.0}:${GIT_SSH_PORT:-2222}:${GIT_SSH_PORT:-2222}"
volumes:
# hosted = source of truth for Tarakan-hosted repos. BACK THIS UP.
- hosted:/app/storage/hosted
# mirrors = regenerable cache of remote repos (rebuilt from upstream on a
# miss). Safe to exclude from backups and to wipe.
- mirrors:/app/storage/mirrors
# ssh = the daemon's host key. Small, irreplaceable, BACK THIS UP: losing
# it is indistinguishable from a man-in-the-middle to every existing
# client, and they will refuse to connect until the user clears it.
- ssh:/app/storage/ssh
volumes:
db_data:
hosted:
mirrors:
ssh: