Traefik with Watchtower Deployment¶
This is the most straight forward way to host chithi instances.
To host chithi, you need 3 parts.
- A S3 compatible storage instance
- A Postgres Database instance
- A Redis Instance
Docker Compose¶
Here is a ready to use docker file that can be used to deploy your site:
services:
traefik:
image: traefik:latest
container_name: traefik
restart: unless-stopped
ports:
- '80:80'
- '443:443/tcp'
- '443:443/udp'
command:
- '--providers.docker=true'
- '--providers.docker.exposedbydefault=false'
- '--entrypoints.web.address=:80'
- '--entrypoints.websecure.address=:443'
# Enable dashboard
- '--api.dashboard=true'
- '--api.insecure=true'
# Enable http/3
- '--entrypoints.websecure.http3=true'
# Experimental FastProxy
- '--experimental.fastProxy'
# Info logs
- '--log.level=INFO'
# Global redirect
- '--entrypoints.web.http.redirections.entrypoint.to=websecure'
- '--entrypoints.web.http.redirections.entrypoint.scheme=https'
# --- Add these lines for Let's Encrypt ---
- '--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web'
# Disable timeout
- '--entrypoints.websecure.transport.respondingTimeouts.readTimeout=0'
- '--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=0'
labels:
# Watchtower
- 'com.centurylinklabs.watchtower.enable=true'
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- letsencrypt:/letsencrypt
postgres:
image: postgres:18
container_name: postgres-db
restart: unless-stopped
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: supersecretpassword
POSTGRES_DB: chithi
volumes:
- postgres_data:/var/lib/postgresql
healthcheck:
test: ['CMD-SHELL', 'pg_isready']
interval: 10s
timeout: 5s
retries: 5
volume-permission-helper:
image: alpine
volumes:
- rustfs:/data
command: >
sh -c "
chown -R 10001:10001 /data &&
echo 'Volume Permissions fixed' &&
exit 0
"
restart: 'no'
rustfs:
image: rustfs/rustfs:latest
security_opt:
- 'no-new-privileges:true'
container_name: rustfs
restart: unless-stopped
user: '10001:10001'
volumes:
- rustfs:/data
labels:
# Watchtower
- 'com.centurylinklabs.watchtower.enable=true'
environment:
RUSTFS_ADDRESS: '0.0.0.0:9000'
RUSTFS_CONSOLE_ADDRESS: '0.0.0.0:9001'
RUSTFS_VOLUMES: '/data/rustfs'
RUSTFS_ACCESS_KEY: 'rustfsadmin'
RUSTFS_SECRET_KEY: 'rustfsadmin'
RUSTFS_CONSOLE_ENABLE: 'true'
healthcheck:
test:
[
'CMD',
'sh',
'-c',
'curl -f http://localhost:9000/health && curl -f http://localhost:9001/rustfs/console/health',
]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
depends_on:
volume-permission-helper:
condition: service_completed_successfully
redis:
image: redis:8.6-alpine
container_name: redis
restart: unless-stopped
volumes:
- redis_data:/data
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 30s
timeout: 10s
retries: 3
backend:
image: ghcr.io/chithi-dev/chithi-backend:latest
container_name: backend
restart: unless-stopped
command: /bin/sh /app/scripts/start_backend.sh
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.backend.rule=Host(`<your_domain>`) && PathPrefix(`/api`)'
# This middleware strips /api from the URL before it hits the container
- 'traefik.http.middlewares.api-strip.stripprefix.prefixes=/api'
- 'traefik.http.routers.backend.middlewares=api-strip'
- 'traefik.http.routers.backend.entrypoints=websecure'
- 'traefik.http.services.backend.loadbalancer.server.port=8000'
# Enable letsencrypt
- 'traefik.http.routers.backend.tls=true'
- 'traefik.http.routers.backend.tls.certresolver=letsencrypt'
# Watchtower
- 'com.centurylinklabs.watchtower.enable=true'
environment: &backend-variable
POSTGRES_SERVER: postgres
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
POSTGRES_PASSWORD: supersecretpassword
POSTGRES_DB: chithi
RUSTFS_ENDPOINT_URL: http://rustfs:9000
RUSTFS_ACCESS_KEY: rustfsadmin
RUSTFS_SECRET_ACCESS_KEY: rustfsadmin
CELERY_BROKER_URL: redis://redis:6379/0
CELERY_RESULT_BACKEND: redis://redis:6379/0
# Redis
REDIS_ENDPOINT: redis://redis:6379/1
# Running behind reverse proxy
ROOT_PATH: /api
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
rustfs:
condition: service_healthy
networks:
- default
celery:
image: ghcr.io/chithi-dev/chithi-backend:latest
container_name: celery
restart: unless-stopped
command: /bin/sh /app/scripts/start_celery.sh
environment: *backend-variable
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
backend:
condition: service_started
frontend:
image: ghcr.io/chithi-dev/chithi-frontend-node:latest
container_name: frontend
restart: unless-stopped
labels:
# Traefik
- 'traefik.enable=true'
- 'traefik.http.routers.frontend.rule=Host(`<your_domain>`)'
- 'traefik.http.routers.frontend.priority=1'
- 'traefik.http.routers.frontend.entrypoints=websecure'
- 'traefik.http.routers.frontend.tls=true'
- 'traefik.http.routers.frontend.tls.certresolver=letsencrypt'
- 'traefik.http.services.frontend.loadbalancer.server.port=3000'
- "traefik.http.middlewares.coep.headers.customResponseHeaders.Cross-Origin-Opener-Policy=same-origin"
- "traefik.http.middlewares.coep.headers.customResponseHeaders.Cross-Origin-Embedder-Policy=require-corp"
- "traefik.http.middlewares.coep.headers.customResponseHeaders.Cross-Origin-Resource-Policy=same-origin"
- "traefik.http.routers.frontend.middlewares=coep@docker"
# Watchtower
- 'com.centurylinklabs.watchtower.enable=true'
environment:
PUBLIC_BACKEND_API: https://<your_domain>/api
depends_on:
backend:
condition: service_started
watchtower:
image: nickfedor/watchtower
container_name: watchtower
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WATCHTOWER_CLEANUP=true
- WATCHTOWER_POLL_INTERVAL=60
# WATCHTOWER_SCHEDULE: "0 0 4 * * *" # optional: daily at 4am
volumes:
postgres_data:
redis_data:
rustfs:
letsencrypt:
Danger
Please replace <your_domain> with the actual domain you are going to use to point to chithi instance.
If you still have any issues around hosting your instances, please open a discussion