#Self-Hosting Guide
Deploy Relaticle on your own infrastructure with Docker or manually.
#Quick Start
Get Relaticle running in 5 steps:
- Download the compose file:
curl -o compose.yml https://raw.githubusercontent.com/Relaticle/relaticle/main/compose.yml
- Generate an application key:
echo "APP_KEY=base64:$(openssl rand -base64 32)"
- Create a
.envfile with your settings:
APP_KEY=base64:your-generated-key-here
DB_PASSWORD=your-secure-database-password
APP_URL=https://crm.example.com
- Start the containers:
docker compose up -d
- Create your admin account:
docker compose exec app php artisan make:filament-user
Your CRM is now available at {APP_URL}/app.
#Requirements
| Resource | Minimum | Recommended |
|---|---|---|
| RAM | 2 GB | 4 GB |
| CPU | 1 core | 2 cores |
| Disk | 10 GB | 20 GB+ |
| Docker | 20.10+ | Latest |
| Docker Compose | v2.0+ | Latest |
#Environment Variables
#Required
These must be set or the containers will refuse to start.
| Variable | Description |
|---|---|
APP_KEY |
Encryption key. Generate with openssl rand -base64 32, then prefix with base64:. |
DB_PASSWORD |
PostgreSQL password. Use a strong random value. |
#Application
| Variable | Default | Description |
|---|---|---|
APP_NAME |
Relaticle |
Displayed in the browser tab and emails. |
APP_ENV |
production |
Set to production for self-hosting. |
APP_DEBUG |
false |
Set to true only for debugging. Never in production. |
APP_TIMEZONE |
UTC |
Application timezone. |
APP_URL |
http://localhost |
Full URL where Relaticle is accessible. Include the scheme. |
APP_PORT |
80 |
Host port the app container binds to. |
APP_PANEL_DOMAIN |
(empty) | Set for subdomain routing (e.g., app.example.com). Leave empty for path mode (/app). |
LOG_CHANNEL |
stderr |
Where logs go. stderr is recommended for Docker. |
LOG_LEVEL |
warning |
Minimum log level. Use debug for troubleshooting. |
| Variable | Default | Description |
|---|---|---|
MAIL_MAILER |
log |
Mail driver: smtp, ses, mailgun, postmark, or log. |
MAIL_HOST |
(empty) | SMTP host (e.g., smtp.mailgun.org). |
MAIL_PORT |
587 |
SMTP port. |
MAIL_USERNAME |
(empty) | SMTP username. |
MAIL_PASSWORD |
(empty) | SMTP password. |
MAIL_ENCRYPTION |
tls |
tls or ssl. |
MAIL_FROM_ADDRESS |
[email protected] |
Sender email address. |
MAIL_FROM_NAME |
Relaticle |
Sender display name. |
#Database and Redis
These are pre-configured in compose.yml and generally don't need changing.
| Variable | Default | Description |
|---|---|---|
DB_DATABASE |
relaticle |
PostgreSQL database name. |
DB_USERNAME |
relaticle |
PostgreSQL username. |
REDIS_PASSWORD |
null |
Redis password. Leave as null for no auth. |
#Optional
| Variable | Description |
|---|---|
GOOGLE_CLIENT_ID |
Google OAuth client ID for social login. |
GOOGLE_CLIENT_SECRET |
Google OAuth client secret. |
GITHUB_CLIENT_ID |
GitHub OAuth client ID for social login. |
GITHUB_CLIENT_SECRET |
GitHub OAuth client secret. |
SENTRY_LARAVEL_DSN |
Sentry DSN for error tracking. |
FATHOM_ANALYTICS_SITE_ID |
Fathom Analytics site ID. |
#Architecture
The Docker setup runs 5 containers:
| Container | Image | Purpose |
|---|---|---|
| app | ghcr.io/relaticle/relaticle:latest |
Web server (nginx + PHP-FPM) on port 8080. Runs migrations automatically on startup. |
| horizon | ghcr.io/relaticle/relaticle:latest |
Queue worker powered by Laravel Horizon. Processes background jobs. |
| scheduler | ghcr.io/relaticle/relaticle:latest |
Runs schedule:work for recurring tasks (e.g., cleanup, notifications). |
| postgres | postgres:17-alpine |
PostgreSQL 17 database. |
| redis | redis:7-alpine |
Cache, sessions, and queue backend. Runs with append-only persistence. |
#Volumes
| Volume | Purpose |
|---|---|
postgres |
Database files. Back this up. |
redis |
Redis persistence data. |
storage |
Uploaded files and application storage. Back this up. |
#Networking
The app container listens on port 8080 internally and maps to APP_PORT (default 80) on the host. All containers communicate through Docker's internal network. Only the app container exposes a port to the host.
#Creating Your Admin Account
After starting the containers, create your first admin user:
docker compose exec app php artisan make:filament-user
You will be prompted for a name, email, and password. Once created, access the CRM panel at {APP_URL}/app.
Note: By default the CRM panel is available at the /app path. To use subdomain routing instead (e.g., app.example.com), set the APP_PANEL_DOMAIN environment variable.
#Reverse Proxy and SSL
The app container serves HTTP on port 8080 internally. Place a reverse proxy in front to handle SSL termination and route traffic to the container.
#Nginx
server {
listen 443 ssl http2;
server_name crm.example.com;
ssl_certificate /etc/letsencrypt/live/crm.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/crm.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:80;
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;
}
}
server {
listen 80;
server_name crm.example.com;
return 301 https://$server_name$request_uri;
}
#Caddy
crm.example.com {
reverse_proxy 127.0.0.1:80
}
Caddy handles SSL certificates automatically via Let's Encrypt.
#Traefik
Add these labels to the app service in your compose.yml:
labels:
- "traefik.enable=true"
- "traefik.http.routers.relaticle.rule=Host(`crm.example.com`)"
- "traefik.http.routers.relaticle.entrypoints=websecure"
- "traefik.http.routers.relaticle.tls.certresolver=letsencrypt"
- "traefik.http.services.relaticle.loadbalancer.server.port=8080"
Note: When using a reverse proxy, set APP_URL to your public HTTPS URL (e.g., https://crm.example.com). The TRUSTED_PROXIES environment variable defaults to * in Docker, so forwarded headers are handled automatically.
#Deploying on Dokploy
Dokploy is an open-source deployment platform. Here's how to deploy Relaticle on it.
#1. Create a Project
In the Dokploy dashboard, click Create Project and give it a name (e.g., "Relaticle").
#2. Add a Compose Service
- Inside your project, click Create Service and select Compose
- Set the source to Raw and paste the contents of the compose.yml
- Click Create
#3. Set Environment Variables
In the service's Environment tab, add the required variables:
APP_KEY=base64:your-generated-key-here
DB_PASSWORD=your-secure-database-password
APP_URL=https://crm.yourdomain.com
APP_PORT=8080
Generate your APP_KEY with:
echo "base64:$(openssl rand -base64 32)"
Note: Set APP_PORT=8080 so the container maps port 8080:8080, avoiding conflicts with Dokploy's own port 80.
#4. Deploy
Click Deploy. Dokploy will pull the images and start all 5 containers. Wait for health checks to pass.
#5. Configure Domain
- Go to the Domains tab of the
appservice - Add your domain (e.g.,
crm.yourdomain.com) - Set the container port to
8080 - Enable HTTPS (Dokploy handles Let's Encrypt automatically)
#6. Create Admin User
Open the Dokploy terminal for the app container and run:
php artisan make:filament-user
Your Relaticle instance is now live at https://crm.yourdomain.com/app.
#Deploying on Coolify
Coolify is an open-source, self-hostable platform for deploying applications.
#1. Create a New Project
In the Coolify dashboard, click New Project and give it a name.
#2. Add a Docker Compose Resource
- Click Add Resource in your project
- Select Docker Compose
- Choose Empty as the source, then paste the contents of the compose.yml
#3. Configure Environment Variables
In the resource's Environment Variables section, add:
APP_KEY=base64:your-generated-key-here
DB_PASSWORD=your-secure-database-password
APP_URL=https://crm.yourdomain.com
#4. Set Up Domain
- Go to the app service's Settings
- Set your domain (e.g.,
crm.yourdomain.com) - Coolify will automatically provision an SSL certificate
#5. Deploy
Click Deploy. Coolify will pull the images, create containers, and start the services.
#6. Create Admin User
Use Coolify's Terminal feature to run in the app container:
php artisan make:filament-user
Access your CRM at https://crm.yourdomain.com/app.
#Upgrading
#1. Back Up Your Data
Always back up before upgrading. See the Backup and Restore section below.
#2. Pull the Latest Images
docker compose pull
#3. Restart the Containers
docker compose up -d
Database migrations run automatically on startup. The app container will apply any pending migrations before serving traffic.
Note: Check the release notes before upgrading. Breaking changes will be documented there.
#Backup and Restore
#Database Backup
docker compose exec postgres pg_dump -U relaticle relaticle > backup-$(date +%Y%m%d).sql
#Database Restore
docker compose exec -T postgres psql -U relaticle relaticle < backup-20260320.sql
#Storage Backup
Back up the storage volume which contains uploaded files:
docker compose cp app:/var/www/html/storage/app ./storage-backup
#Automated Backups
Add a cron job to back up daily:
0 3 * * * cd /path/to/relaticle && docker compose exec -T postgres pg_dump -U relaticle relaticle | gzip > /backups/relaticle-$(date +\%Y\%m\%d).sql.gz
#Manual Deployment
If you prefer not to use Docker, you can deploy Relaticle directly on a server.
#Requirements
- PHP 8.4+ with extensions: pdo_pgsql, gd, bcmath, mbstring, xml, redis
- PostgreSQL 17+
- Redis 7+
- Node.js 20+
- Composer 2+
- Nginx or Apache
- Supervisor (for queue workers)
#Installation
- Clone the repository:
git clone https://github.com/Relaticle/relaticle.git /var/www/relaticle
cd /var/www/relaticle
- Install dependencies:
composer install --no-dev --optimize-autoloader
npm ci && npm run build
- Configure the environment:
cp .env.example .env
php artisan key:generate
Edit .env with your database credentials, mail settings, and APP_URL.
- Set up the database:
php artisan migrate --force
php artisan storage:link
- Set permissions:
chown -R www-data:www-data storage bootstrap/cache
chmod -R 775 storage bootstrap/cache
- Create your admin user:
php artisan make:filament-user
#Nginx Configuration
server {
listen 80;
server_name crm.example.com;
root /var/www/relaticle/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
#Supervisor for Horizon
Create /etc/supervisor/conf.d/relaticle-horizon.conf:
[program:relaticle-horizon]
process_name=%(program_name)s
command=php /var/www/relaticle/artisan horizon
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/relaticle/storage/logs/horizon.log
stopwaitsecs=3600
Then start it:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start relaticle-horizon
#Scheduler Cron
Add to www-data's crontab:
* * * * * cd /var/www/relaticle && php artisan schedule:run >> /dev/null 2>&1
#Troubleshooting
#"APP_KEY is required" error on startup
The APP_KEY environment variable is not set. Generate one:
echo "base64:$(openssl rand -base64 32)"
Add it to your .env file and restart:
docker compose up -d
#Container restart loops
Check the logs:
docker compose logs app --tail 50
Common causes:
- Missing required environment variables (
APP_KEY,DB_PASSWORD) - PostgreSQL not ready yet (the app waits for a health check, but custom configs may skip this)
- Insufficient memory (need at least 2 GB)
#500 errors after deployment
- Check
APP_DEBUG=truetemporarily to see the full error - View logs:
docker compose logs app --tail 100 - Ensure
APP_URLmatches your actual domain (including scheme) - Run
docker compose exec app php artisan optimize:clearto clear all caches
#Email not sending
- Verify
MAIL_MAILERis set tosmtp(notlog) - Check your SMTP credentials are correct
- Test with:
docker compose exec app php artisan tinker --execute "Mail::raw('Test', fn(\$m) => \$m->to('[email protected]')->subject('Test'))" - Check logs:
docker compose logs app | grep -i mail
#Horizon not processing jobs
- Check Horizon status:
docker compose exec app php artisan horizon:status - Verify the horizon container is running:
docker compose ps - Check horizon logs:
docker compose logs horizon --tail 50 - Restart Horizon:
docker compose restart horizon
#Permission errors on storage
docker compose exec app chown -R www-data:www-data /var/www/html/storage
docker compose exec app chmod -R 775 /var/www/html/storage
#Database connection refused
- Verify PostgreSQL is running:
docker compose ps postgres - Check PostgreSQL logs:
docker compose logs postgres --tail 20 - Ensure
DB_PASSWORDmatches between the app and postgres containers (both read from the same.envvariable by default)