Manual Docker Compose Setup
Manual setup guide for Rybbit using Docker Compose without the setup script
This guide is for users who want to manually set up Rybbit using Docker Compose without the setup script. This is useful if you already have a reverse proxy setup (like Nginx, Traefik, or Coolify), or if you want more control over the configuration.
Prerequisites
- Docker and Docker Compose installed
- A domain name pointed to your server
- Basic knowledge of Docker and environment variables
Setup Steps
Clone the Repository
git clone https://github.com/rybbit-io/rybbit.git
cd rybbit
Create Environment File
Create a .env
file in the root directory with the following content:
# Required: Your domain and base URL
DOMAIN_NAME=your.domain.com
BASE_URL=https://your.domain.com
# Required: Authentication secret (generate a random 32+ character string)
BETTER_AUTH_SECRET=your-very-long-random-secret-string-here
# Optional: Disable new user signups after creating admin account
DISABLE_SIGNUP=false
# Optional: Custom ports (only needed if you want different ports)
# HOST_BACKEND_PORT="3001:3001"
# HOST_CLIENT_PORT="3002:3002"
# Optional: Database credentials (defaults work fine)
# CLICKHOUSE_PASSWORD=frog
# POSTGRES_USER=frog
# POSTGRES_PASSWORD=frog
# POSTGRES_DB=analytics
# CLICKHOUSE_DB=analytics
To generate a secure BETTER_AUTH_SECRET
, you can use:
openssl rand -hex 32
Choose Your Setup Method
If you don't have a reverse proxy and want automatic SSL certificates, use the default docker-compose.yml:
docker compose up -d
This will:
- Start all services including Caddy
- Automatically obtain SSL certificates
- Make your app available at
https://your.domain.com
If you have your own reverse proxy (Nginx, Traefik, Coolify, etc.), you need to exclude Caddy and expose the ports:
-
Option B1: Modify the .env file
# Add these lines to expose ports HOST_BACKEND_PORT="3001:3001" HOST_CLIENT_PORT="3002:3002"
Then start without Caddy:
docker compose up -d backend client clickhouse postgres
-
Option B2: Use docker-compose.override.yml Create a
docker-compose.override.yml
file:services: backend: ports: - "3001:3001" client: ports: - "3002:3002"
Then start without Caddy:
docker compose up -d backend client clickhouse postgres
Configure Your Reverse Proxy
If you're using your own reverse proxy, configure it to:
- Proxy requests to
/api/*
tohttp://localhost:3001
- Proxy all other requests to
http://localhost:3002
Example configurations:
server {
listen 80;
server_name your.domain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name your.domain.com;
# Your SSL configuration here
location /api/ {
proxy_pass http://localhost:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://localhost:3002;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
services:
backend:
labels:
- "traefik.enable=true"
- "traefik.http.routers.rybbit-api.rule=Host(`your.domain.com`) && PathPrefix(`/api`)"
- "traefik.http.routers.rybbit-api.tls.certresolver=letsencrypt"
- "traefik.http.services.rybbit-api.loadbalancer.server.port=3001"
client:
labels:
- "traefik.enable=true"
- "traefik.http.routers.rybbit-client.rule=Host(`your.domain.com`)"
- "traefik.http.routers.rybbit-client.tls.certresolver=letsencrypt"
- "traefik.http.services.rybbit-client.loadbalancer.server.port=3002"
Start the Services
# Start all services
docker compose up -d
# Or start specific services (without Caddy)
docker compose up -d backend client clickhouse postgres
Verify Setup
Check that all services are running:
docker compose ps
Monitor logs:
docker compose logs -f
Create Admin Account
Navigate to https://your.domain.com/signup
and create your admin account.
Service Architecture
Rybbit consists of these services:
- client: Next.js frontend (port 3002)
- backend: Node.js API server (port 3001)
- postgres: User data and configuration
- clickhouse: Analytics data storage
- caddy: Reverse proxy with automatic SSL (optional)
Common Configurations
Using Custom Ports
If you need different host ports (e.g., if 3001/3002 are already in use):
HOST_BACKEND_PORT="8080:3001"
HOST_CLIENT_PORT="8081:3002"
Using with Coolify
Since Coolify uses Traefik instead of Caddy as proxy, some modifications have to be made in a docker-compose.yaml
file to avoid conflicts. Specifically, you need to:
- remove Caddy service and volumes
- add network labels to all services
- remove
build
andports
properties from backend and client services
Here's a modified version of docker-compose that works on Coolify:
services:
clickhouse:
container_name: clickhouse
image: clickhouse/clickhouse-server:25.4.2
volumes:
- clickhouse-data:/var/lib/clickhouse
configs:
- source: clickhouse_network
target: /etc/clickhouse-server/config.d/network.xml
- source: clickhouse_json
target: /etc/clickhouse-server/config.d/enable_json.xml
- source: clickhouse_logging
target: /etc/clickhouse-server/config.d/logging_rules.xml
- source: clickhouse_user_logging
target: /etc/clickhouse-server/config.d/user_logging.xml
environment:
- CLICKHOUSE_DB=${CLICKHOUSE_DB:-analytics}
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-default}
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-frog}
healthcheck:
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://localhost:8123/ping",
]
interval: 3s
timeout: 5s
retries: 5
start_period: 10s
restart: unless-stopped
labels:
- traefik.enable=false
postgres:
image: postgres:17.4
container_name: postgres
environment:
- POSTGRES_USER=${POSTGRES_USER:-frog}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-frog}
- POSTGRES_DB=${POSTGRES_DB:-analytics}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 3s
timeout: 5s
retries: 5
start_period: 10s
restart: unless-stopped
labels:
- traefik.enable=false
backend:
image: ghcr.io/rybbit-io/rybbit-backend:${IMAGE_TAG:-latest}
container_name: backend
environment:
- NODE_ENV=production
- CLICKHOUSE_HOST=http://clickhouse:8123
- CLICKHOUSE_DB=${CLICKHOUSE_DB:-analytics}
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-frog}
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- POSTGRES_DB=${POSTGRES_DB:-analytics}
- POSTGRES_USER=${POSTGRES_USER:-frog}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-frog}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
- BASE_URL=${BASE_URL}
- DOMAIN_NAME=${DOMAIN_NAME}
- DISABLE_SIGNUP=${DISABLE_SIGNUP}
- DISABLE_TELEMETRY=${DISABLE_TELEMETRY}
depends_on:
clickhouse:
condition: service_healthy
postgres:
condition: service_started
healthcheck:
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://127.0.0.1:3001/api/health",
]
interval: 3s
timeout: 5s
retries: 5
start_period: 10s
restart: unless-stopped
labels:
- traefik.enable=true
- traefik.docker.network=coolify
- traefik.http.routers.rybbit-backend.entrypoints=https
- traefik.http.routers.rybbit-backend.tls=true
- traefik.http.routers.rybbit-backend.rule=Host(`${DOMAIN_NAME}`) && (Path(`/api`) || PathPrefix(`/api/`))
- traefik.http.services.rybbit-backend.loadbalancer.server.port=3001
- traefik.http.routers.rybbit-backend.priority=100
- traefik.http.middlewares.rybbit-forward-headers.headers.customrequestheaders.X-Forwarded-Proto=https
- traefik.http.middlewares.rybbit-forward-headers.headers.customrequestheaders.X-Forwarded-Host=${DOMAIN_NAME}
- traefik.http.routers.rybbit-backend.middlewares=rybbit-forward-headers
client:
image: ghcr.io/rybbit-io/rybbit-client:${IMAGE_TAG:-latest}
container_name: client
environment:
- NODE_ENV=production
- NEXT_PUBLIC_BACKEND_URL=${BASE_URL}
- NEXT_PUBLIC_DISABLE_SIGNUP=${DISABLE_SIGNUP}
- DOMAIN_NAME=${DOMAIN_NAME}
depends_on:
- backend
restart: unless-stopped
labels:
- traefik.enable=true
- traefik.docker.network=coolify
- traefik.http.routers.rybbit-client.entrypoints=https
- traefik.http.routers.rybbit-client.tls=true
- traefik.http.routers.rybbit-client.rule=Host(`${DOMAIN_NAME}`)
- traefik.http.services.rybbit-client.loadbalancer.server.port=3002
- traefik.http.routers.rybbit-client.priority=10
volumes:
clickhouse-data:
postgres-data:
redis-data:
configs:
clickhouse_network:
content: |
<clickhouse>
<listen_host>0.0.0.0</listen_host>
</clickhouse>
clickhouse_json:
content: |
<clickhouse>
<settings>
<enable_json_type>1</enable_json_type>
</settings>
</clickhouse>
clickhouse_logging:
content: |
<clickhouse>
<logger>
<level>warning</level>
<console>true</console>
</logger>
<query_thread_log remove="remove"/>
<query_log remove="remove"/>
<text_log remove="remove"/>
<trace_log remove="remove"/>
<metric_log remove="remove"/>
<asynchronous_metric_log remove="remove"/>
<session_log remove="remove"/>
<part_log remove="remove"/>
<latency_log remove="remove"/>
<processors_profile_log remove="remove"/>
</clickhouse>
clickhouse_user_logging:
content: |
<clickhouse>
<profiles>
<default>
<log_queries>0</log_queries>
<log_query_threads>0</log_query_threads>
<log_processors_profiles>0</log_processors_profiles>
</default>
</profiles>
</clickhouse>
To deploy Rybbit on Coolify, you need to:
- Create a new project and resource using
docker-compose.yaml
file provided above - Make sure "Escape special characters in labels" option is unchecked when adding docker-compose file so that env variables in labels are read properly
- Set the environment variables in Coolify's interface
- Add a domain for
client
service in Coolify's interface - Deploy all services
Note: you don't need to add a domain for backend
service in Coolify since client and backend services share the same domain.
Using with Nginx Proxy Manager
-
Set up port exposure in your .env:
HOST_BACKEND_PORT="3001:3001" HOST_CLIENT_PORT="3002:3002"
-
Create a proxy host pointing to your server IP:3002
-
Add a custom location
/api/*
pointing to your server IP:3001
Database Persistence
Data is automatically persisted in Docker volumes:
rybbit_clickhouse-data
: Analytics datarybbit_postgres-data
: User accounts and site configurations
Advanced Configurations
For specific reverse proxy setups, see our detailed guides:
- Custom Nginx Setup - Complete Nginx configuration with SSL
- Nginx Proxy Manager - NPM setup without port exposure
These guides provide step-by-step instructions for integrating Rybbit with your existing infrastructure.
Troubleshooting
Services won't start
# Check logs
docker compose logs
# Check service status
docker compose ps
Port conflicts
If you get port binding errors, either:
- Change the host ports in your .env file
- Stop the conflicting service
- Use docker-compose.override.yml to customize ports
Database connection issues
Ensure the database services are healthy:
docker compose ps
Both postgres and clickhouse should show "healthy" status.
For more advanced configurations and setup script options, see our Advanced Self-Hosting Guide.