Full reference for the Docker Compose deployment, including reverse proxy and TLS.
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 2 cores | 4+ cores |
| RAM | 2 GB | 4–8 GB |
| Disk | 10 GB | 50 GB+ (depends on register size) |
| OS | Any Linux with Docker 20.10+ | Ubuntu LTS, Debian stable, RHEL 8+ |
Three services: app (Rust / Actix-web 4), mysql (business data) and clickhouse (analytics & activity). Data is persisted in named Docker volumes; both databases include healthchecks — the app waits for them before starting. The image is pulled from GHCR.
services: app: image: ghcr.io/mlab-sh/tprm.mlab.sh:latest ports: - "${APP_PORT:-8080}:8080" depends_on: mysql: { condition: service_healthy } clickhouse: { condition: service_healthy } env_file: .env environment: - DB_HOST=mysql - CH_HOST=clickhouse volumes: - uploads:/app_mlab_sh/uploads - logs:/app_mlab_sh/logs restart: unless-stopped mysql: image: mysql:8 environment: MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} MYSQL_DATABASE: mlabtprm MYSQL_USER: ${DB_USERNAME} MYSQL_PASSWORD: ${DB_PASSWORD} volumes: - mysql_data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 5s restart: unless-stopped clickhouse: image: clickhouse/clickhouse-server:latest environment: CLICKHOUSE_USER: ${CH_USERNAME} CLICKHOUSE_PASSWORD: ${CH_PASSWORD} CLICKHOUSE_DB: mlabtprm volumes: - clickhouse_data:/var/lib/clickhouse healthcheck: test: ["CMD", "clickhouse-client", "--query", "SELECT 1"] interval: 5s restart: unless-stopped volumes: mysql_data: clickhouse_data: uploads: logs:
| Service | Port | Exposed? |
|---|---|---|
app | 8080 | Yes — behind your reverse proxy |
mysql | 3306 | No — internal network only |
clickhouse | 8123 / 9000 | No — internal network only |
Images are published to GitHub Container Registry via GitHub Actions. No authentication is required for the public image:
docker pull ghcr.io/mlab-sh/tprm.mlab.sh:latest
Don't expose app directly. Put nginx, Caddy or Traefik in front for TLS termination, HTTP/2 and request limits.
tprm.example.com {
reverse_proxy localhost:8080
encode gzip
}
server {
listen 443 ssl http2;
server_name tprm.example.com;
ssl_certificate /etc/letsencrypt/live/tprm.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/tprm.example.com/privkey.pem;
client_max_body_size 25m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
TRUSTED_PROXY=127.0.0.1 (or your proxy IP) in .env so the app honors X-Forwarded-* headers for client IP logging.
Both database volumes are mountable. The recommended backup is volume-level snapshots plus a logical dump:
docker exec mysql mysqldump -uroot -p$DB_ROOT_PASSWORD mlabtprm | gzip > mlabtprm-$(date +%F).sql.gz docker exec clickhouse clickhouse-client --query="BACKUP DATABASE mlabtprm TO Disk('backups','mlabtprm-$(date +%F).zip')"