Deploying HeritageGraph on Coolify
This guide explains how to deploy the full HeritageGraph stack on Coolify.
Prerequisites
- Coolify installed on your VM (v4.x recommended)
- A domain pointing to your VM (e.g.,
heritagegraph.xyz) - GitHub repository access configured in Coolify
Architecture on Coolify
┌─────────────────────────────────────────────────────────────────┐
│ COOLIFY VM │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ coolify-proxy │ ← Traefik (managed by Coolify) │
│ │ (ports 80/443) │ Handles SSL, routing, domains │
│ └────────┬────────┘ │
│ │ │
│ ├──────────────┬──────────────┬─────────────────┐ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────┐│
│ │ frontend │ │ backend │ │ landing │ │postgres ││
│ │ (Next.js) │ │ (Django) │ │ (Next.js) │ │ (DB) ││
│ │ :3000 │ │ :8000 │ │ :3000 │ │ :5432 ││
│ └──────────────┘ └──────────────┘ └──────────────┘ └─────────┘│
│ │
└─────────────────────────────────────────────────────────────────┘
Key Point: Coolify's own Traefik proxy (coolify-proxy) handles all routing and SSL. We do NOT include Traefik in our compose file.
Step 1: Create the Resource in Coolify
- Go to your Coolify dashboard
- Create a new Project (or use existing)
- Add a new Resource → Select Docker Compose
- Choose Git Repository as the source
- Connect your HeritageGraph repository
- Set the Docker Compose file path to:
docker-compose-coolify.yml
Step 2: Configure Environment Variables
In Coolify's Environment Variables section, add:
Required Variables
| Variable | Example | Description |
|---|---|---|
POSTGRES_PASSWORD |
your-secure-password-123 |
Database password (generate a strong one) |
DJANGO_SECRET_KEY |
your-50-char-random-string |
Django secret key |
NEXTAUTH_SECRET |
your-32-char-random-string |
NextAuth session secret |
NEXTAUTH_URL |
http://heritagegraph.xyz |
Frontend public URL |
NEXT_PUBLIC_API_URL |
http://api.heritagegraph.xyz |
Backend API URL |
Optional Variables (for Google OAuth)
| Variable | Example | Description |
|---|---|---|
GOOGLE_CLIENT_ID |
xxx.apps.googleusercontent.com |
Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
GOCSPX-xxx |
Google OAuth secret |
Other Variables
| Variable | Default | Description |
|---|---|---|
POSTGRES_DB |
heritage_db |
Database name |
POSTGRES_USER |
heritage_user |
Database user |
ALLOWED_HOSTS |
* |
Django allowed hosts (Coolify handles this) |
CORS_ALLOWED_ORIGINS |
http://heritagegraph.xyz |
CORS origins |
Generate Secrets
# Generate DJANGO_SECRET_KEY
openssl rand -base64 50 | tr -d '\n'
# Generate NEXTAUTH_SECRET
openssl rand -base64 32 | tr -d '\n'
# Generate POSTGRES_PASSWORD
openssl rand -base64 24 | tr -d '\n'
Step 3: Configure Domains in Coolify
Coolify manages domains through its UI, NOT through Docker labels. For each service that needs a public domain:
Frontend Service
- Click on frontend service in Coolify
- Go to Network → Domains
- Add:
http://heritagegraph.xyz(or your domain) - Port:
3000 - Enable HTTPS if you have SSL configured
Backend Service
- Click on backend service
- Go to Network → Domains
- Add:
http://api.heritagegraph.xyz(or your domain) - Port:
8000 - Enable HTTPS if you have SSL configured
Landing Service (Optional)
- Click on landing service
- Go to Network → Domains
- Add:
http://landing.heritagegraph.xyz(or your preferred subdomain) - Port:
3000 - Enable HTTPS if you have SSL configured
Step 4: Configure Service Dependencies
In Coolify, set up health check dependencies:
- backend depends on postgres (healthy)
- frontend can start independently
- landing can start independently
This is already defined in the compose file via depends_on.
Step 5: Deploy
- Click Deploy in Coolify
- Watch the build logs for each service
- Wait for all health checks to pass (green status)
Step 6: Post-Deployment Setup
Run Django Migrations
After first deployment, you may need to run migrations manually:
# SSH into your Coolify VM
ssh your-vm
# Find the backend container
docker ps | grep backend
# Run migrations
docker exec -it <container_id> python manage.py migrate
# Create superuser (optional)
docker exec -it <container_id> python manage.py createsuperuser
API homepage, admin, and documentation
After the backend domain resolves to the Django container, open it in a browser:
| What | URL (replace with your API host) |
|---|---|
| Entry page (links to everything below) | https://api.example.com/ |
| Same as JSON | https://api.example.com/?format=json |
| Django admin | https://api.example.com/admin/ |
| Swagger UI (interactive API docs) | https://api.example.com/docs or /docs/ |
| ReDoc | https://api.example.com/redoc/ |
| OpenAPI schema | https://api.example.com/schema/ |
| Health | https://api.example.com/health/ |
If /admin/ or /docs return 404, the domain is almost certainly mapped to the frontend (port 3000) instead of backend (8000). Fix the service mapping in Coolify.
Verify Services
# Check backend health
curl http://api.heritagegraph.xyz/health/
# Check API index (HTML or JSON)
curl -s http://api.heritagegraph.xyz/?format=json
# Check frontend
curl http://heritagegraph.xyz
# Check landing
curl http://landing.heritagegraph.xyz
DNS Configuration
Point your domains to your Coolify VM's IP address:
| Record Type | Name | Value |
|---|---|---|
| A | heritagegraph.xyz |
<VM_IP> |
| A | api.heritagegraph.xyz |
<VM_IP> |
Or use a wildcard:
| Record Type | Name | Value |
|---|---|---|
| A | *.heritagegraph.xyz |
<VM_IP> |
| A | heritagegraph.xyz |
<VM_IP> |
Troubleshooting
Build Fails
- Check Dockerfile paths are correct
- Ensure
heritage_graph_ui/Dockerfileandheritage_graph_landing/Dockerfileexist - Check Coolify build logs for specific errors
Services Won't Start
- Check environment variables are set correctly
- Verify postgres is healthy before backend starts
- Check container logs in Coolify
SSL Issues
- Ensure DNS is pointing to Coolify VM
- Let's Encrypt needs ports 80 and 443 open
- Wait a few minutes for certificate provisioning
Database Connection Errors
- Check
POSTGRES_PASSWORDmatches in both places - Ensure postgres health check passes
- Backend should wait for postgres via
depends_on
InconsistentMigrationHistory: admin.0001_initial … users.0001_initial
The backend entrypoint runs migrate on every start. If Postgres was initialized with a bad migration order (or a restored dump), migrations loop forever.
- Disposable data: drop and recreate the public schema or delete the Postgres volume, then redeploy (see TROUBLESHOOTING.md §10 — PostgreSQL / Coolify).
- Keep data:
DELETE FROM django_migrations WHERE app = 'admin';thenmigratefrom the backend container; use--fake-initialforusersonly if tables already exist and match.
Full steps: TROUBLESHOOTING.md → section 10.
CORS Errors
- Update
CORS_ALLOWED_ORIGINSto include your actual frontend domain - Include both
http://heritagegraph.xyzandhttps://heritagegraph.xyzif needed
Updating the Deployment
Code Updates
- Push changes to your Git repository
- In Coolify, click Redeploy on the affected service
- Or enable Auto Deploy for automatic deployments on push
Environment Variable Changes
- Update variables in Coolify UI
- Click Restart on affected services
Database Migrations
docker exec -it <backend_container> python manage.py migrate
Backup & Recovery
Database Backup
# Create backup
docker exec heritage-postgres pg_dump -U heritage_user heritage_db > backup.sql
# Restore backup
docker exec -i heritage-postgres psql -U heritage_user heritage_db < backup.sql
Volume Backup
Coolify stores volumes in /var/lib/docker/volumes/. Back up:
- postgres-data (database)
- backend-media (uploaded files)
- backend-static (static files)
Security Checklist
- [ ] Strong
POSTGRES_PASSWORD(24+ characters) - [ ] Strong
DJANGO_SECRET_KEY(50+ characters) - [ ] Strong
NEXTAUTH_SECRET(32+ characters) - [ ] HTTPS enabled on all public services
- [ ]
DEBUG=Falsein production - [ ] Restricted
ALLOWED_HOSTS(not*in production) - [ ] Proper
CORS_ALLOWED_ORIGINS - [ ] Firewall rules (80, 443 open; other ports closed)
Architecture Differences from Local Development
| Aspect | Local (docker-compose.yml) | Coolify |
|---|---|---|
| Reverse Proxy | Own Traefik container | Coolify's coolify-proxy |
| SSL | Manual or self-signed | Auto Let's Encrypt |
| Domains | *.localhost |
Real domains |
| Routing | Traefik labels | Coolify UI |
| Env Vars | .env file |
Coolify UI |
| Builds | Local Docker | Coolify build system |
| Monitoring | Manual | Coolify dashboard |