Skip to main content

Production Deployment Guide

Last Updated: October 19, 2025 Status: Production-tested and verified

Choose the right deployment platform for your DutyCall production environment.


Overview

DutyCall consists of two main components:

  • Backend: Laravel 11 API (PHP 8.3 + MySQL/PostgreSQL)
  • Frontend: Next.js 15 SPA (React)

This guide helps you choose the right hosting platform and provides links to detailed deployment guides.


Platform Comparison

FeatureDigitalOcean DropletRailwayVercel (Frontend)
ControlFull root accessManaged platformManaged platform
ReliabilityYou manage itPlatform-dependentExcellent
Cost$12/month (2GB)Free tier availableFree tier available
Env Var Stability✅ Stable⚠️ Has failed in production✅ Stable
MonitoringYou configure itBuilt-in (basic)Built-in (basic)
Setup Time~60 minutes~45 minutes~15 minutes
Recommended ForProduction backendDevelopment/stagingProduction frontend

⚠️ Railway Warning - October 19, 2025 Incident

Production Outage on Railway

Date: October 19, 2025 Impact: Complete production outage - Login broken for all users Root Cause: Railway FRONTEND_URL environment variable disappeared without warning Duration: 6+ hours (detection + migration to DigitalOcean) Lesson Learned: Do NOT rely on Railway for production without extensive monitoring

If you choose Railway for production, you MUST:

  1. Set up external monitoring (UptimeRobot - see Monitoring section)
  2. Document all environment variables externally (password manager, encrypted file)
  3. Configure manual database backups
  4. Have a migration plan ready for another platform

Our Recommendation: Use Railway for development/staging only. Use DigitalOcean for production.


Deployment Guides

Backend Deployment Options

Best for: Production environments requiring stability and control

What you get:

  • Full root access to Ubuntu 22.04 server
  • Stable environment variables
  • Predictable $12/month flat rate
  • Complete control over infrastructure

Time to deploy: ~60 minutes Technical level: Intermediate-Advanced

👉 Deploy to DigitalOcean →


⚠️ Alternative: Railway (Development/Staging)

Best for: Development, staging, and rapid prototyping

What you get:

  • Managed platform with auto-deploy
  • PostgreSQL database included
  • Free tier ($5/month credit)
  • Quick setup

Time to deploy: ~45 minutes Technical level: Intermediate

Known issues:

  • Environment variables can disappear (production incident Oct 19, 2025)
  • Requires external monitoring and backup documentation

👉 Deploy to Railway →


✅ Vercel (Production & Development)

Best for: All Next.js deployments

What you get:

  • Edge network deployment (global CDN)
  • Automatic SSL and caching
  • Preview deployments for PRs
  • Free tier (generous limits)

Time to deploy: ~15 minutes Technical level: Beginner

👉 Deploy Frontend to Vercel →


Vercel Frontend Deployment

Prerequisites

  • Vercel account
  • GitHub repository connected to Vercel
  • Backend API deployed (DigitalOcean or Railway)

Step 1: Install Vercel CLI

npm install -g vercel
cd frontend/
vercel link # Select your project

Step 3: Configure Environment Variables

CRITICAL: Add to ALL THREE environments (production, preview, development)

# Production
echo "https://api.dutycall.net" | vercel env add NEXT_PUBLIC_API_URL production

# Preview (PR deployments)
echo "https://api.dutycall.net" | vercel env add NEXT_PUBLIC_API_URL preview

# Development
echo "http://localhost:8090" | vercel env add NEXT_PUBLIC_API_URL development

Step 4: Deploy

Option A: Git Integration (Automatic)

git checkout main
git merge develop
git push origin main

Option B: Manual Deploy

cd frontend/
vercel deploy --prod

Step 5: Verify Deployment

vercel ls --prod
# Visit production URL

CORS Configuration

The Problem

Backend CORS configured for ONE specific URL breaks when Vercel creates new deployment URLs.

The Solution

Use pattern matching in backend/config/cors.php:

<?php

return [
'paths' => ['api/*', 'sanctum/csrf-cookie', 'dashboard/*', 'auth/*', 'analytics/*'],
'allowed_methods' => ['*'],
'allowed_origins' => array_filter([
'http://localhost:3000',
'http://localhost:3001',
'http://localhost:3002',
env('FRONTEND_URL'), // Primary production URL
]),

// ✅ CRITICAL: Allow all Vercel preview deployments
'allowed_origins_patterns' => ['#https://.*\.vercel\.app$#'],

'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];

After Updating CORS Config

# DigitalOcean
ssh root@YOUR_DROPLET_IP
cd /var/www/dutycall/backend
php artisan config:clear
php artisan config:cache

# Railway
railway run php artisan config:clear
railway run php artisan config:cache

Monitoring Setup

Monitoring is Mandatory

The October 19, 2025 incident caused a 6+ hour outage because we had NO monitoring. Don't make the same mistake!

Monitoring is not optional. It is mandatory for production deployments.

UptimeRobot (Free)

Create free account: https://uptimerobot.com/

Configure 3 monitors:

1. Backend API Health

Type: HTTP(s)
Name: DutyCall Backend API
URL: https://api.dutycall.net/api/user
Interval: 5 minutes
Method: HEAD
Expected Status: 401
Alert: Your email

2. SSL Certificate Monitor

Type: HTTP(s)
Name: DutyCall SSL Certificate
URL: https://api.dutycall.net
Interval: 5 minutes
SSL Monitoring: Enabled
Alert when expires in: 30 days
Alert: Your email

3. Frontend Health

Type: HTTP(s)
Name: DutyCall Frontend
URL: https://dutycall.vercel.app
Interval: 5 minutes
Method: HEAD
Expected Status: 200
Alert: Your email

Backend:

composer require sentry/sentry-laravel
php artisan vendor:publish --provider="Sentry\Laravel\ServiceProvider"

Frontend:

npm install --save @sentry/nextjs
npx @sentry/wizard@latest -i nextjs

Security Checklist

Backend (Laravel):

  • APP_DEBUG=false in production
  • APP_ENV=production
  • Strong database password (20+ random characters)
  • .env file permissions: chmod 600 .env
  • Storage permissions: chown -R www-data:www-data storage
  • SSL certificate installed and auto-renewing
  • Firewall configured (only ports 22, 80, 443 open)
  • SSH key authentication (disable password auth)
  • Regular security updates scheduled

Frontend (Next.js):

  • No secrets in client-side code
  • Environment variables use NEXT_PUBLIC_ prefix only for public values
  • Content Security Policy configured
  • Rate limiting on API routes

Next Steps

  1. Choose your platform:

  2. Deploy frontend:

  3. Configure CORS:

    • Add pattern matching to config/cors.php
  4. Set up monitoring:

    • Create UptimeRobot account
    • Configure 3 monitors
    • Install Sentry (recommended)
  5. Review security:

    • Complete security checklist above
    • Test all endpoints
    • Verify monitoring alerts work

Additional Resources


Ready to deploy? Choose your backend platform above and follow the detailed guide! 🚀