Skip to main content

Morphee Production Deployment with Coolify

Complete step-by-step guide to deploy Morphee v2.0 to production using Coolify

Status: ✅ Production-ready Last Updated: February 27, 2026 Estimated Time: 12-16 hours (over 2-3 days)


Table of Contents

  1. Overview
  2. Prerequisites
  3. Phase 1: Server Setup
  4. Phase 2: Domain Configuration
  5. Phase 3: Database & Auth
  6. Phase 4: Backend Deployment
  7. Phase 5: Verify Deployment
  8. Phase 6: Monitoring (Optional)
  9. Phase 7: Backups
  10. Phase 8: Testing
  11. Troubleshooting
  12. Cost Breakdown

Overview

What is Coolify?

Coolify is an open-source, self-hosted Platform-as-a-Service (PaaS) alternative to Heroku, Vercel, and Netlify. It provides:

  • Docker Compose native support — deploy Morphee's multi-service architecture easily
  • Built-in SSL via Let's Encrypt (automatic HTTPS)
  • Built-in reverse proxy (Traefik) — routes traffic to your apps
  • Environment variable management — secure secrets storage
  • Zero-downtime deployments — rolling updates with health checks
  • Git integration — auto-deploy on push to main
  • Web UI — manage everything from a dashboard

Why Coolify for Morphee?

  • Cost-effective: $17-42/mo vs $100+ on AWS
  • Docker Compose ready: Morphee has docker-compose.coolify.yml with Rust server + monitoring
  • Easy migration: Move to Kubernetes later if needed
  • Open source: No vendor lock-in

Prerequisites

Required

  • Domain namemorphee.app (or your domain)
    • Registered and accessible
    • DNS managed via Cloudflare, DigitalOcean, or Route53
  • LLM API key — Anthropic (recommended) or OpenAI
  • GitHub account — for repository access
    • Morphee repo: https://github.com/your-org/morphee-beta
  • Email account — for Coolify admin + Let's Encrypt
  • Supabase account (free) — for managed PostgreSQL + Auth
  • Server provider account — Hetzner (cheapest), DigitalOcean (easiest), or AWS
  • Payment method — credit card for server billing

Optional

  • 🔧 AWS account — for S3 offsite backups
  • 🔧 Google OAuth credentials — for Calendar/Gmail integrations
  • 🔧 Firebase account — for mobile push notifications
  • 🔧 Apple Developer account — for iOS push notifications

Phase 1: Server Setup (1-2 hours)

1.1 Choose Server Provider

Recommended: Hetzner Cloud (best price/performance)

SpecsPriceUse Case
CPX21 — 3 vCPU, 4GB RAM, 80GB SSD€8.19/mo (~$9/mo)Small (100-500 users)
CPX31 — 4 vCPU, 8GB RAM, 160GB SSD€16.09/mo (~$17/mo)Medium (500-2000 users)

Alternative: DigitalOcean

SpecsPriceUse Case
Basic — 2 vCPU, 4GB RAM, 80GB SSD$24/moSmall
Basic — 2 vCPU, 8GB RAM, 160GB SSD$48/moMedium

1.2 Create Server

Hetzner Example:

  1. Go to https://console.hetzner.cloud
  2. Create new project: "Morphee Production"
  3. Add server:
    • Location: Closest to your users (e.g., Ashburn, VA for US)
    • Image: Ubuntu 22.04 LTS
    • Type: CPX31 (4 vCPU, 8GB RAM) — recommended
    • Networking: Enable IPv4 + IPv6
    • SSH keys: Add your public key (~/.ssh/id_rsa.pub)
    • Name: morphee-prod
  4. Create server (takes ~60 seconds)
  5. Copy server IP address: YOUR_SERVER_IP

DigitalOcean Example:

  1. Go to https://cloud.digitalocean.com
  2. Create Droplet:
    • Image: Ubuntu 22.04 LTS
    • Plan: Basic, $48/mo (2 vCPU, 8GB RAM, 160GB SSD)
    • Datacenter: Closest to users
    • Authentication: SSH keys (recommended)
    • Hostname: morphee-prod
  3. Create Droplet
  4. Copy IP address

1.3 Initial Server Configuration

SSH into server:

ssh root@YOUR_SERVER_IP

Update system:

apt update && apt upgrade -y
apt install -y curl wget git vim ufw fail2ban

Configure firewall:

# Allow SSH
ufw allow 22/tcp

# Allow HTTP/HTTPS (for Coolify)
ufw allow 80/tcp
ufw allow 443/tcp

# Allow Coolify dashboard (port 8000)
ufw allow 8000/tcp

# Enable firewall
ufw --force enable

# Verify
ufw status

Optional: Create non-root user

# Create user
adduser morphee
usermod -aG sudo morphee

# Add SSH key for new user
mkdir -p /home/morphee/.ssh
cp /root/.ssh/authorized_keys /home/morphee/.ssh/
chown -R morphee:morphee /home/morphee/.ssh
chmod 700 /home/morphee/.ssh
chmod 600 /home/morphee/.ssh/authorized_keys

# Test login (from local machine)
ssh morphee@YOUR_SERVER_IP

# Disable root SSH login (security best practice)
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
systemctl restart ssh

1.4 Install Coolify

One-line installer:

curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash

This installs:

  • Docker Engine (latest)
  • Docker Compose (v2)
  • Coolify server (runs on port 8000)
  • Traefik reverse proxy (for routing + SSL)
  • PostgreSQL (Coolify's database)
  • Redis (Coolify's cache)

Installation takes ~5-10 minutes.

Expected output:

✅ Docker installed
✅ Docker Compose installed
✅ Coolify installed
✅ Traefik proxy started
✅ Coolify server started

🎉 Coolify is now running!

Access dashboard: http://YOUR_SERVER_IP:8000

Verify installation:

docker ps

You should see containers:

  • coolify
  • coolify-db
  • coolify-redis
  • coolify-proxy (Traefik)

1.5 Access Coolify Dashboard

  1. Open browser: http://YOUR_SERVER_IP:8000
  2. First-time setup wizard:
    • Email: your-email@example.com (for Let's Encrypt SSL notifications)
    • Username: admin (or your preferred username)
    • Password: Create strong password (min 12 characters)
    • Root Domain: morphee.app (your domain)
  3. Click Complete Setup
  4. You'll be redirected to Coolify dashboard

Security: Restrict Dashboard Access

After setup, restrict Coolify dashboard to your IP only:

# On server
sudo ufw delete allow 8000/tcp
sudo ufw allow from YOUR_HOME_IP to any port 8000 proto tcp

# Verify
sudo ufw status

Access dashboard via SSH tunnel instead:

# From local machine
ssh -L 8000:localhost:8000 morphee@YOUR_SERVER_IP

# Then open: http://localhost:8000

Phase 2: Domain Configuration (30 minutes)

2.1 DNS Records

You need 3 subdomains:

  1. api.morphee.app — Backend API
  2. app.morphee.app — Frontend web app
  3. monitoring.morphee.app — Grafana (optional)

Option A: Individual A records

TypeNameValueTTL
AapiYOUR_SERVER_IP300
AappYOUR_SERVER_IP300
AmonitoringYOUR_SERVER_IP300
AwwwYOUR_SERVER_IP300
A@ (root)YOUR_SERVER_IP300

Option B: Wildcard (simpler)

TypeNameValueTTL
A*YOUR_SERVER_IP300
A@YOUR_SERVER_IP300

Cloudflare Example:

  1. Go to https://dash.cloudflare.com
  2. Select your domain (morphee.app)
  3. Go to DNSRecords
  4. Click Add record
  5. Add records above
  6. Click Save

Verify DNS propagation:

# Test from local machine
dig api.morphee.app +short
# Should return: YOUR_SERVER_IP

dig app.morphee.app +short
# Should return: YOUR_SERVER_IP

DNS propagation takes 5-60 minutes (usually ~5 min with Cloudflare).

2.2 SSL Certificates

Coolify uses Let's Encrypt for automatic SSL certificates.

Wildcard SSL setup (recommended):

  1. Go to Coolify → SettingsSSL
  2. Choose DNS Provider: Cloudflare (or your provider)
  3. Add API Token:
    • Cloudflare: Go to My ProfileAPI TokensCreate Token
    • Use template: Edit zone DNS
    • Permissions: Zone.DNS.Edit for morphee.app
    • Copy token
  4. Paste token in Coolify
  5. Click Request Wildcard Certificate
  6. Coolify will request *.morphee.app cert via DNS-01 challenge
  7. Wait ~2 minutes for certificate issuance

Verify SSL:

curl -I https://api.morphee.app
# Should return "HTTP/2 200" (after backend is deployed)

Phase 3: Database & Auth (Automatic)

With docker-compose.coolify.yml, PostgreSQL and GoTrue are self-hosted in the same stack. No external Supabase account needed.

Everything is automatic on first deploy:

  • PostgreSQL 15 with pgvector starts with auto-generated password (SERVICE_PASSWORD_POSTGRES)
  • Migrations run automatically via the migrations one-shot container (tracks applied migrations in _migrations table, safe to re-run)
  • GoTrue connects to PostgreSQL internally, uses auto-generated JWT secret shared with backend
  • No manual setup — no psql, no CREATE EXTENSION, no migration scripts to run

SMTP Configuration (required for email confirmation)

GoTrue sends confirmation emails on signup. You need an SMTP provider:

ProviderFree TierSetup
Resend3,000 emails/moSet SMTP_HOST=smtp.resend.com, SMTP_USER=resend, SMTP_PASS=re_...
Mailgun1,000 emails/moSet SMTP_HOST=smtp.mailgun.org, user + pass from Mailgun dashboard
SendGrid100 emails/daySet SMTP_HOST=smtp.sendgrid.net, SMTP_USER=apikey, SMTP_PASS=SG...

Set these in Coolify UI:

SMTP_HOST=smtp.resend.com
SMTP_PORT=587
SMTP_USER=resend
SMTP_PASS=re_your_api_key
SMTP_FROM=noreply@morphee.app

Quick start without SMTP: Set GOTRUE_MAILER_AUTOCONFIRM=true to skip email confirmation (not recommended for production).

SSO Providers (optional)

To enable Google/Apple/Microsoft login, set in Coolify UI:

# Google SSO
GOOGLE_SSO_ENABLED=true
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-your-client-secret
GOTRUE_GOOGLE_REDIRECT_URI=http://supabase-auth:9999/callback

# Apple SSO
APPLE_SSO_ENABLED=true
APPLE_CLIENT_ID=app.morphee.mobile
APPLE_CLIENT_SECRET=your-apple-secret

# Microsoft / Azure AD SSO
AZURE_SSO_ENABLED=true
AZURE_CLIENT_ID=your-azure-client-id
AZURE_CLIENT_SECRET=your-azure-secret

Optional: External Supabase Database

If you prefer managed PostgreSQL (automatic backups, point-in-time recovery), use Supabase Cloud ($25/mo) instead:

  1. Create a project at https://supabase.com/dashboard
  2. In Coolify UI, override these variables:
    • DATABASE_URL → Supabase connection string
    • SUPABASE_AUTH_URLhttps://[PROJECT_ID].supabase.co/auth/v1
    • SUPABASE_JWT_SECRET → from Supabase Settings → API
  3. Remove or stop the supabase-db, supabase-auth, and migrations services in Coolify

Phase 4: Application Deployment (2 hours)

4.1 Create Application in Coolify

  1. Go to Coolify → Applications → New Application

  2. Select deployment type:

    • Choose Docker Compose
    • Morphee has a Coolify-specific compose file
  3. Connect Git repository:

    • Source: GitHub
    • Repository: https://github.com/your-org/morphee-beta
    • Branch: main
    • Compose file path: docker-compose.coolify.yml (at root)
    • Click Connect
  4. Assign domains to services:

    • frontend: https://app.morphee.app (port 80)
    • server: https://api.morphee.app (port 3000)
    • grafana: https://monitoring.morphee.app (port 3000) — optional
    • Coolify's Traefik proxy routes traffic automatically

4.2 Configure Environment Variables

In Coolify → Application → Environment, set the required variables.

Auto-generated secrets (do NOT set manually):

Coolify auto-generates and persists these across redeployments:

VariablePurpose
SERVICE_PASSWORD_POSTGRESPostgreSQL password
SERVICE_PASSWORD_REDISRedis authentication

Required variables (set in Coolify UI):

# Secrets (generate ONCE, never change)
JWT_SECRET=<base64-secret> # Generate: openssl rand -base64 32
MORPHEE_SIGNING_KEY=<base64-ed25519-key> # Generate: openssl rand -base64 32

# URLs
VITE_API_URL=https://api.morphee.app
VITE_WS_URL=wss://api.morphee.app
MORPHEE_CORS_ORIGINS=https://app.morphee.app,tauri://localhost,http://tauri.localhost,https://tauri.localhost
FRONTEND_URL=https://app.morphee.app

Optional variables:

# SMTP (strongly recommended — see Phase 3 for providers)
SMTP_HOST=smtp.resend.com
SMTP_PORT=587
SMTP_USER=resend
SMTP_PASS=re_your_api_key
SMTP_FROM=noreply@morphee.app

# Google SSO
GOOGLE_SSO_ENABLED=true
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-your-client-secret

# Analytics (PostHog — opt-in)
MORPHEE_ANALYTICS_ENABLED=true
MORPHEE_POSTHOG_API_KEY=phc_your_key

# Grafana
GRAFANA_PASSWORD=your-secure-password

Important:

  • Click the lock icon next to sensitive vars (API keys, signing key) — encrypts them at rest
  • Mark VITE_* variables as Build Variables — they are baked into the JS bundle at build time, not runtime

4.3 Persistent Volumes

Docker volumes are managed by Coolify. No manual directory creation needed.

VolumeContainer PathPurpose
pg-data/var/lib/postgresql/dataPostgreSQL data
redis-data/dataRedis AOF persistence
knowledge-data/var/lib/morphee/knowledgeGit-backed knowledge repos
model-cache/var/lib/morphee/modelsCached ML models
prometheus-data/prometheusPrometheus time-series data
grafana-data/var/lib/grafanaGrafana config + dashboards

4.4 Deploy

  1. Click "Deploy" button in Coolify
  2. Monitor build logs:
    • Coolify will:
      • Clone repo
      • Build Rust server image (using Dockerfile.server — multi-stage cargo build)
      • Build frontend image (npm + nginx)
      • Pull infrastructure images (PostgreSQL, GoTrue, Redis, Prometheus, Grafana)
      • Start all services with health checks
  3. Wait for "Deployed" status (green checkmark)
  4. Check logs:
    • Coolify → Application → Logs

    • Look for:

      INFO morphee-server: Starting morphee-server host=0.0.0.0 port=3000
      INFO morphee-server: Database connected
      INFO morphee-server: Migrations complete
      INFO morphee-server: morphee-server listening addr=0.0.0.0:3000

Note: First build takes ~5-10 minutes (Rust compilation). Subsequent builds are faster due to Docker layer caching.

4.5 Verify Deployment

Using the deployment script (recommended):

export COOLIFY_URL=https://coolify.morphee.app
export COOLIFY_TOKEN=your-api-token
export COOLIFY_APP_UUID=your-app-uuid
./scripts/coolify-deploy.sh health

Manual verification:

# Health check
curl https://api.morphee.app/health
# Expected: {"status":"ok","version":"0.1.0","capabilities":[...]}

# Prometheus metrics
curl https://api.morphee.app/metrics | head -5

# Frontend
curl -I https://app.morphee.app
# Expected: HTTP/2 200

4.6 Troubleshooting Server

Issue: Build fails

# Check build logs in Coolify UI
# Common issues:
# - Cargo build OOM (increase server RAM to 8GB+)
# - Missing system deps (cmake, libssl-dev — already in Dockerfile)
# - Out of disk space

# Fix: SSH into server, check disk
df -h

# Clean up old Docker images if needed
docker system prune -a

Issue: Health check fails

# Check server logs
docker logs <server-container> -f

# Common issues:
# - MORPHEE_DATABASE_URL not set or incorrect
# - GoTrue not healthy (check supabase-auth container)
# - MORPHEE_SUPABASE_JWT_SECRET doesn't match GOTRUE_JWT_SECRET

# Verify environment variables
docker exec <server-container> env | grep MORPHEE_

Issue: 502 Bad Gateway

# Server is not listening on port 3000
docker logs <server-container> --tail 50

# Verify server is running
docker ps | grep server

# Check container health
docker inspect --format='{{.State.Health.Status}}' <server-container>

Phase 5: Verify Deployment (30 minutes)

With docker-compose.coolify.yml, all services deploy together as one stack: Rust server, frontend, PostgreSQL, GoTrue, Redis, Prometheus, Grafana.

5.1 Automated Verification

Use the deployment script for a complete health check:

export COOLIFY_URL=https://coolify.morphee.app
export COOLIFY_TOKEN=your-api-token
export COOLIFY_APP_UUID=your-app-uuid
export MORPHEE_API_URL=https://api.morphee.app
export MORPHEE_APP_URL=https://app.morphee.app

# Full health check
./scripts/coolify-deploy.sh health

# If issues found, auto-diagnose + fix
./scripts/coolify-deploy.sh diagnose

5.2 Manual Verification

Test frontend loads:

curl https://app.morphee.app | grep -i morphee

Open in browser: https://app.morphee.app — you should see the login page.

Test API connection (browser console):

fetch('https://api.morphee.app/health')
.then(r => r.json())
.then(console.log)
// Expected: {status: "ok", version: "0.1.0", capabilities: [...]}

5.3 Troubleshooting

Issue: Blank page

// Check browser console for errors
// Verify build args were applied
console.log(import.meta.env.VITE_API_URL)
// Should show: https://api.morphee.app
// If undefined: VITE_* vars need to be marked as Build Variables in Coolify

Issue: CORS errors

# Verify MORPHEE_CORS_ORIGINS includes frontend domain
docker exec <server-container> env | grep MORPHEE_CORS
# Should include: https://app.morphee.app

Issue: Assets 404

# Check nginx serves files
docker exec <frontend-container> ls -la /usr/share/nginx/html

Phase 6: Monitoring (Included in Stack)

Monitoring is built into the Coolify deployment — Prometheus + Grafana are included in docker-compose.coolify.yml.

What's Included

  • Prometheus scrapes the Rust server's built-in /metrics endpoint every 10s
  • Grafana provides dashboards for API performance, error rates, and system health
  • The Rust server exposes metrics via prometheus-client (HTTP request counts, latencies, etc.)

Setup

  1. Add DNS record: monitoring.morphee.appYOUR_SERVER_IP
  2. Assign domain in Coolify: grafana service → https://monitoring.morphee.app
  3. Set Grafana password: GRAFANA_PASSWORD=your-secure-password in Coolify env vars

Access Grafana

  • Open: https://monitoring.morphee.app
  • Login: admin / YOUR_GRAFANA_PASSWORD

Import Dashboards

  1. Go to Dashboards → Import
  2. Import custom Morphee dashboard from monitoring/grafana/dashboards/ (auto-provisioned)
  3. Optional community dashboards:
    • 9628 — PostgreSQL Database
    • 193 — Docker Container Metrics

Verify Metrics

# Check Prometheus scrapes the server
curl https://api.morphee.app/metrics | head -10

# Check Prometheus targets (from server)
curl http://localhost:9090/api/v1/targets

Optional: Full Monitoring Stack

For additional exporters (node-exporter, cAdvisor, postgres-exporter, Alertmanager, Loki), use the standalone monitoring compose:

docker compose -f docker-compose.monitoring.yml up -d

Phase 7: Backups (1 hour)

7.1 Database Backups

Option A: Supabase Automatic Backups (RECOMMENDED)

If using Supabase Database:

  • Automatic daily backups included (7-day retention on Pro)
  • Point-in-time recovery (restore to any minute within 7 days)
  • Download backups via dashboard (Settings → Database → Backups)

Option B: Manual Backup Script

  1. Upload backup script:

    scp scripts/backup-morphee.sh morphee@YOUR_SERVER_IP:/root/
  2. SSH into server and configure:

    ssh morphee@YOUR_SERVER_IP

    # Make executable
    chmod +x /root/backup-morphee.sh

    # Test run
    DATABASE_URL="postgresql://..." /root/backup-morphee.sh

    # Verify backup created
    ls -lh /data/backups/morphee/
  3. Schedule daily backups via cron:

    # Edit crontab
    crontab -e

    # Add line (runs daily at 2 AM)
    0 2 * * * DATABASE_URL="postgresql://..." /root/backup-morphee.sh >> /var/log/morphee-backup.log 2>&1
  4. Optional: Upload to S3 for offsite storage:

    # Install AWS CLI
    apt install -y awscli

    # Configure AWS credentials
    aws configure
    # Enter: Access Key ID, Secret Access Key, Region (us-east-1)

    # Test S3 upload
    DATABASE_URL="postgresql://..." \
    S3_BUCKET="s3://your-morphee-backups" \
    /root/backup-morphee.sh

7.2 Test Disaster Recovery

Simulate data loss and restore:

# SSH into server
ssh morphee@YOUR_SERVER_IP

# 1. Create test data
psql $DATABASE_URL -c "INSERT INTO conversations (id, title, user_id, group_id, space_id, created_at, updated_at) VALUES (gen_random_uuid(), 'Test Conversation', (SELECT id FROM users LIMIT 1), (SELECT id FROM groups LIMIT 1), (SELECT id FROM spaces LIMIT 1), NOW(), NOW());"

# 2. Backup
DATABASE_URL="postgresql://..." /root/backup-morphee.sh

# 3. Delete test data
psql $DATABASE_URL -c "DELETE FROM conversations WHERE title = 'Test Conversation';"

# 4. Restore from latest backup
LATEST_BACKUP=$(ls -t /data/backups/morphee/morphee_db_*.sql.gz | head -1)
gunzip -c $LATEST_BACKUP | psql $DATABASE_URL

# 5. Verify restoration
psql $DATABASE_URL -c "SELECT * FROM conversations WHERE title = 'Test Conversation';"
# Should return the restored row

Phase 8: Testing (1 hour)

8.1 Smoke Tests

Server API:

# Health check
curl https://api.morphee.app/health
# Expected: {"status":"ok","version":"0.1.0","capabilities":[...]}

# Prometheus metrics
curl https://api.morphee.app/metrics | head -5

# Auth (verify GoTrue proxy works)
curl -X POST https://api.morphee.app/v1/auth/verify \
-H "Content-Type: application/json" \
-d '{"token":"test"}'
# Expected: 401 (bad token — but endpoint is reachable)

# Capabilities
curl https://api.morphee.app/v1/capabilities

Frontend:

# Test HTML loads
curl https://app.morphee.app | grep -i morphee

# Test assets load
curl -I https://app.morphee.app/assets/index.js
# Should return 200 OK

WebSocket:

// In browser console (after login)
const ws = new WebSocket('wss://api.morphee.app/ws?token=YOUR_JWT_TOKEN');
ws.onopen = () => console.log('✅ WebSocket connected');
ws.onmessage = (e) => console.log('📨 Message:', e.data);
ws.onerror = (e) => console.error('❌ Error:', e);

8.2 End-to-End Test

Complete user flow:

  1. Open https://app.morphee.app in browser
  2. Click Sign Up
  3. Enter: email, password, name
  4. Click Create Account
  5. Should redirect to /onboarding
  6. Chat with AI: "I'm a parent with 2 kids"
  7. AI should create group + spaces
  8. Redirect to /chat
  9. Send message: "Hello Morphee!"
  10. AI should respond
  11. Check WebSocket events in DevTools → Network → WS

8.3 Load Test (Optional)

Install k6:

# macOS
brew install k6

# Linux
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6

Run load test:

// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

export let options = {
stages: [
{ duration: '2m', target: 100 }, // Ramp to 100 users
{ duration: '5m', target: 100 }, // Stay at 100
{ duration: '2m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95% < 500ms
http_req_failed: ['rate<0.01'], // <1% error rate
},
};

export default function () {
let response = http.get('https://api.morphee.app/health');
check(response, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}

Run:

k6 run load-test.js

Expected results:

  • ✅ 95th percentile < 500ms
  • ✅ Error rate < 1%
  • ✅ All checks pass

Troubleshooting

Common Issues

1. SSL certificate not provisioning

# Check Traefik logs
docker logs coolify-proxy -f

# Common issues:
# - DNS not propagated yet (wait 5-60 min)
# - Cloudflare DNS-only mode (should be "Proxied")
# - Rate limit (Let's Encrypt allows 5 certs/week per domain)

# Fix: Re-trigger certificate
# Coolify → Application → Domain → Re-issue Certificate

2. Server can't connect to database

# Check MORPHEE_DATABASE_URL format
# Correct: postgresql://user:pass@supabase-db:5432/postgres
# Incorrect: postgres://... (should be postgresql://)

# Check server logs for connection errors
docker logs <server-container> --tail 50 | grep -i "database\|connect\|error"

3. Frontend can't reach server (CORS)

# Check MORPHEE_CORS_ORIGINS in server
docker exec <server-container> env | grep MORPHEE_CORS

# Should include: https://app.morphee.app

# Update in Coolify → Environment → MORPHEE_CORS_ORIGINS
# Redeploy

4. WebSocket connection fails

// In browser console, check error
const ws = new WebSocket('wss://api.morphee.app/v1/ws?token=YOUR_TOKEN');
ws.onerror = (e) => console.error(e);

// Common issues:
// - Invalid JWT token
// - Server not listening on /v1/ws
// - Traefik not upgrading connection

5. Out of disk space

# Check disk usage
df -h

# Clean up Docker images/containers
docker system prune -a -f --volumes

# Remove old logs
journalctl --vacuum-time=7d

# Check large directories
du -sh /var/lib/docker
du -sh /data/coolify

Cost Breakdown

Everything in docker-compose.coolify.yml — no external accounts.

ServiceProviderCost/mo
Server (8GB RAM)Hetzner CPX31€16 (~$17)
Domain + SSLCloudflare$0 (free)
SMTPResend$0 (free tier: 3k emails/mo)
Total~$17/mo

Pros: Cheapest, full control, data sovereignty, no vendor dependency Cons: Single server (no redundancy), manual backups

Option 2: Hybrid (Managed Database)

Self-hosted app + managed PostgreSQL for automatic backups.

ServiceProviderCost/mo
Server (4GB RAM)Hetzner CPX21€8 (~$9)
Database + AuthSupabase Pro$25
Domain + SSLCloudflare$0 (free)
Total~$34/mo

Pros: Automatic backups, point-in-time recovery Cons: Vendor dependency, higher cost

Option 3: Full Managed (Future)

ServiceProviderCost/mo
DatabaseAWS RDS$30
App HostingAWS ECS Fargate$30
Load BalancerAWS ALB$20
RedisElastiCache$15
CDNCloudFront$5
Total~$100/mo

When to migrate: >10k users, multi-region, compliance needs


Next Steps

After successful deployment:

  1. Update documentation:

    • Mark deployment.md as "✅ Deployed"
    • Add production URLs to README.md
  2. Set up monitoring alerts:

    • CPU > 80% for 5 min
    • Disk > 90%
    • HTTP error rate > 5%
  3. Enable CI/CD:

    • GitHub Actions → Coolify webhook
    • Auto-deploy on push to main
  4. User testing:

    • Invite beta users
    • Monitor errors in Sentry/Grafana
  5. Performance tuning:

    • Add database indexes if slow
    • Enable Redis caching
    • Optimize Docker images

Support

Need help?

Emergency contacts:


Last updated: February 27, 2026 Deployment status: ✅ Production-ready (v2.0 — Rust server) Next review: After first production deployment