Deployment Guide

Version: 1.0.0

This guide covers deploying notifito to production using Docker Compose on a single VPS.


Prerequisites

Server Requirements

Resource Minimum Recommended
CPU 2 cores 4 cores
RAM 4 GB 8 GB
Storage 20 GB 50 GB
OS Ubuntu 22.04+ Ubuntu 24.04

Software Requirements


Step 1: Server Setup

Create a VPS

DigitalOcean:

# Create a droplet with Ubuntu 24.04
# Recommended: Regular Intel, 4 GB RAM, 2 CPUs

AWS EC2:

# Launch instance with Ubuntu 24.04
# Recommended: t3.medium (2 vCPU, 4 GB RAM)

Linode:

# Create instance with Ubuntu 24.04
# Recommended: Linode 4GB (2 cores, 4 GB RAM)

Initial Server Configuration

# Update system
sudo apt update && sudo apt upgrade -y

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Add user to docker group
sudo usermod -aG docker $USER

# Log out and back in, then verify
docker --version
docker compose version

Step 2: Clone Repository

# Clone the repository
git clone https://github.com/turkerince/notifito.git
cd notifito

# Checkout the latest release
git checkout v1.0.0

Step 3: Configure Environment

Create Environment Files

# Copy example environment files
cp apps/core/.env.example apps/core/.env
cp apps/edge/.env.example apps/edge/.env
cp apps/dispatch/.env.example apps/dispatch/.env
cp apps/dashboard/.env.example apps/dashboard/.env

Configure Core Environment

Edit apps/core/.env:

APP_NAME=notifito-core
APP_ENV=production
APP_KEY=base64:generate-a-random-key
APP_DEBUG=false
APP_URL=https://core.yourdomain.com

LOG_CHANNEL=stderr

DB_CONNECTION=pgsql
DB_HOST=postgres
DB_PORT=5432
DB_DATABASE=notifito_core
DB_USERNAME=notifito
DB_PASSWORD=your-secure-database-password

REDIS_HOST=redis
REDIS_PORT=6379

CACHE_STORE=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis

INTERNAL_SECRET=your-internal-secret-key
EDGE_URL=https://edge.yourdomain.com

Configure Edge Environment

Edit apps/edge/.env:

APP_NAME=notifito-edge
APP_ENV=production
APP_KEY=base64:generate-a-random-key
APP_DEBUG=false
APP_URL=https://edge.yourdomain.com

LOG_CHANNEL=stderr

DB_CONNECTION=pgsql
DB_HOST=postgres
DB_PORT=5432
DB_DATABASE=notifito_core
DB_USERNAME=notifito
DB_PASSWORD=your-secure-database-password

REDIS_HOST=redis
REDIS_PORT=6379

CACHE_STORE=redis
QUEUE_CONNECTION=redis

INTERNAL_SECRET=your-internal-secret-key

Configure Dispatch Environment

Edit apps/dispatch/.env:

APP_NAME=notifito-dispatch
APP_ENV=production
APP_KEY=base64:generate-a-random-key
APP_DEBUG=false
APP_URL=https://dispatch.yourdomain.com

LOG_CHANNEL=stderr

DB_CONNECTION=pgsql
DB_HOST=postgres
DB_PORT=5432
DB_DATABASE=notifito_dispatch
DB_USERNAME=notifito
DB_PASSWORD=your-secure-database-password

REDIS_HOST=redis
REDIS_PORT=6379

CACHE_STORE=redis
QUEUE_CONNECTION=redis

POSTMARK_TOKEN=your-postmark-api-token
POSTMARK_BASE_URL=https://api.postmarkapp.com

Configure Dashboard Environment

Edit apps/dashboard/.env:

APP_NAME=notifito-dashboard
APP_ENV=production
APP_KEY=base64:generate-a-random-key
APP_DEBUG=false
APP_URL=https://app.yourdomain.com

LOG_CHANNEL=stderr

DB_CONNECTION=null

REDIS_HOST=redis
REDIS_PORT=6379

CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=sync

CORE_URL=http://core:8000
EDGE_URL=https://edge.yourdomain.com
INTERNAL_SECRET=your-internal-secret-key

Step 4: Configure DNS

Set up DNS records for your domain:

Record Type Value
edge.yourdomain.com A Your server IP
app.yourdomain.com A Your server IP
cdn.yourdomain.com A Your server IP

Example for DigitalOcean:

edge.notifito.com    A    123.456.789.0
app.notifito.com     A    123.456.789.0
cdn.notifito.com     A    123.456.789.0

Step 5: Configure Caddy

Edit docker/caddy/Caddyfile:

{
    auto_https on
    admin off
}

edge.notifito.com {
    reverse_proxy edge:8000
}

app.notifito.com {
    reverse_proxy dashboard:8000
}

cdn.notifito.com {
    root * /srv/widget
    header Cache-Control "public, max-age=300"
    header Access-Control-Allow-Origin "*"
    file_server
}

Step 6: Build and Deploy

Build Docker Images

# Build all services
docker compose build

Start Services

# Start all services
docker compose up -d

# Check status
docker compose ps

Run Migrations

# Run core migrations
./bin/artisan core migrate --force

# Run dispatch migrations
./bin/artisan dispatch migrate --force

Generate Application Keys

# Generate keys for each app
./bin/artisan core key:generate
./bin/artisan edge key:generate
./bin/artisan dispatch key:generate
./bin/artisan dashboard key:generate

Step 7: Seed Initial Data

Create Admin User

# Access core tinker
./bin/artisan core tinker

# Create tenant and user
$tenant = App\Models\Tenant::create([
    'name' => 'Your Company',
    'slug' => 'your-company',
    'timezone' => 'UTC',
    'domains' => ['yourdomain.com'],
    'from_name' => 'Your Company',
    'from_email' => 'notifications@yourdomain.com',
]);

$user = App\Models\User::create([
    'tenant_id' => $tenant->id,
    'name' => 'Admin',
    'email' => 'admin@yourdomain.com',
    'password' => Hash::make('your-secure-password'),
]);

$keys = app(App\Domain\Tenancy\ApiKeyFactory::class);
$keys->issue($tenant, 'Widget', App\Domain\Tenancy\ApiKeyKind::Publishable);
$keys->issue($tenant, 'Push', App\Domain\Tenancy\ApiKeyKind::Secret);

Step 8: Verify Deployment

Run Smoke Test

# Run the smoke deployment test
./bin/smoke-deploy

Expected output:

edge is public through caddy           OK
dashboard is public through caddy      OK
widget bundle is served by caddy       OK
core is NOT public through caddy       OK
dispatch is NOT public through caddy   OK
core horizon is running                OK
dispatch horizon is running            OK

Test Endpoints

# Test edge health
curl https://edge.notifito.com/health

# Test dashboard
curl https://app.notifito.com/health

# Test widget schema
curl "https://edge.notifito.com/v1/widget/schema?key=your-publishable-key&item_type=sneaker"

Cloud Deployment Variants

DigitalOcean Droplet

# 1. Create droplet
doctl compute droplet create notifito \
  --region nyc1 \
  --size s-2vcpu-4gb \
  --image ubuntu-24-04-x64 \
  --ssh-keys your-ssh-key-id

# 2. SSH into droplet
ssh root@your-droplet-ip

# 3. Follow deployment steps above

AWS EC2

# 1. Launch EC2 instance
aws ec2 run-instances \
  --image-id ami-0c55b159cbfafe1f0 \
  --instance-type t3.medium \
  --key-name your-key-pair \
  --security-group-ids sg-xxxxxxxx

# 2. Configure security groups
# Allow: SSH (22), HTTP (80), HTTPS (443)

# 3. Set up Elastic IP
aws ec2 allocate-address
aws ec2 associate-address --instance-id i-xxxxxxxx --allocation-id eipalloc-xxxxxxxx

# 4. Configure Route 53
# Create A records pointing to Elastic IP

# 5. SSH into instance
ssh -i your-key.pem ubuntu@your-instance-ip

# 6. Follow deployment steps above

Linode

# 1. Create Linode
linode-cli linodes create \
  --type g6-standard-2 \
  --region us-east \
  --image linode/ubuntu24.04 \
  --authorized_keys your-ssh-key

# 2. SSH into Linode
ssh root@your-linode-ip

# 3. Follow deployment steps above

SSL/TLS Configuration

Caddy automatically handles SSL/TLS with Let's Encrypt. No additional configuration needed.

Verify SSL

# Check certificate
curl -vI https://edge.notifito.com 2>&1 | grep -i "issuer"

Custom SSL Certificates

If you need custom certificates:

edge.notifito.com {
    tls /path/to/cert.pem /path/to/key.pem
    reverse_proxy edge:8000
}

Monitoring

View Logs

# View all logs
docker compose logs -f

# View specific service logs
docker compose logs -f core
docker compose logs -f edge
docker compose logs -f dispatch
docker compose logs -f dashboard

# View Horizon logs
docker compose logs -f core-horizon
docker compose logs -f dispatch-horizon

Check Service Status

# Check all services
docker compose ps

# Check specific service
docker compose ps core

Monitor Queues

Access Horizon dashboards: - Core: http://your-server-ip:8001/horizon (internal only) - Dispatch: http://your-server-ip:8003/horizon (internal only)


Backup Strategy

Database Backup

# Create backup script
cat > /opt/notifito/backup.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/opt/notifito/backups"
DATE=$(date +%Y%m%d_%H%M%S)

# Backup core database
docker compose exec -T postgres pg_dump -U notifito notifito_core | gzip > "$BACKUP_DIR/core_$DATE.sql.gz"

# Backup dispatch database
docker compose exec -T postgres pg_dump -U notifito notifito_dispatch | gzip > "$BACKUP_DIR/dispatch_$DATE.sql.gz"

# Keep last 7 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
EOF

chmod +x /opt/notifito/backup.sh

# Add to crontab
echo "0 2 * * * /opt/notifito/backup.sh" | crontab -

Restore from Backup

# Restore core database
gunzip -c /opt/notifito/backups/core_20260828_020000.sql.gz | docker compose exec -T postgres psql -U notifito notifito_core

# Restore dispatch database
gunzip -c /opt/notifito/backups/dispatch_20260828_020000.sql.gz | docker compose exec -T postgres psql -U notifito notifito_dispatch

Security Considerations

Firewall Configuration

# Install UFW
sudo apt install ufw

# Allow SSH
sudo ufw allow ssh

# Allow HTTP/HTTPS
sudo ufw allow 80
sudo ufw allow 443

# Enable firewall
sudo ufw enable

Environment Variables

Database Security


Updating

Pull Latest Changes

cd /path/to/notifito
git pull origin main

Rebuild and Restart

# Rebuild images
docker compose build

# Restart services
docker compose down
docker compose up -d

# Run migrations
./bin/artisan core migrate --force
./bin/artisan dispatch migrate --force

Zero-Downtime Updates

For zero-downtime updates, use rolling deployments:

# Update one service at a time
docker compose up -d --no-deps core
docker compose up -d --no-deps edge
docker compose up -d --no-deps dispatch
docker compose up -d --no-deps dashboard

Troubleshooting

Services Not Starting

# Check logs
docker compose logs

# Check specific service
docker compose logs core

# Restart services
docker compose restart

Database Connection Issues

# Check PostgreSQL status
docker compose exec postgres pg_isready

# Check database exists
docker compose exec postgres psql -U notifito -l

Queue Workers Not Processing

# Check Horizon status
docker compose exec core php artisan horizon:status

# Restart Horizon
docker compose restart core-horizon
docker compose restart dispatch-horizon

SSL Certificate Issues

# Check Caddy logs
docker compose logs caddy

# Verify DNS
dig edge.notifito.com

Related Documentation