Repository navigation
vercel
Complete guide for deploying soketi.rs WebSocket server on Vercel platform
- Overview
- Prerequisites
- Step-by-Step Deployment
- Environment Variables
- Build Settings
- WebSocket Configuration
- SSL/TLS Setup
- Monitoring and Logging
- Cost Estimation
- Scaling Recommendations
- Troubleshooting
Vercel is a cloud platform optimized for frontend frameworks and serverless functions. While Vercel is primarily designed for static sites and serverless APIs, you can deploy soketi.rs as a containerized application using Vercel's Docker support or as a separate service that your Vercel-hosted frontend connects to.
Recommended Architecture:
- Frontend (Next.js chat app): Deployed on Vercel
- soketi.rs WebSocket server: Deployed on a container platform (Railway, Fly.io, or DigitalOcean)
- Connection: Frontend connects to soketi.rs via WebSocket
Before deploying, ensure you have:
- A Vercel account (sign up here)
- Vercel CLI installed:
npm install -g vercel - Git repository with your soketi.rs project
- A separate hosting solution for the soketi.rs server (Railway, Fly.io, etc.)
Since Vercel doesn't natively support long-running WebSocket servers, deploy soketi.rs on a container platform:
Option A: Using Railway
# Install Railway CLI
npm install -g @railway/cli
# Login to Railway
railway login
# Initialize project
railway init
# Deploy soketi.rs
railway upOption B: Using Fly.io
# Install Fly CLI
curl -L https://fly.io/install.sh | sh
# Login to Fly
fly auth login
# Launch soketi.rs
fly launch
# Deploy
fly deploy- Connect your repository:
# Login to Vercel
vercel login
# Navigate to your Next.js project
cd next-chat-app
# Deploy
vercel- Configure through Vercel Dashboard:
- Go to Vercel Dashboard
- Click "Import Project"
- Select your Git repository
- Configure project settings
Update your frontend environment variables to point to your soketi.rs deployment:
# Set environment variables
vercel env add NEXT_PUBLIC_PUSHER_HOST
# Enter your soketi.rs host (e.g., your-app.railway.app)
vercel env add NEXT_PUBLIC_PUSHER_PORT
# Enter: 443
vercel env add NEXT_PUBLIC_PUSHER_KEY
# Enter your Pusher app key
vercel env add PUSHER_SECRET
# Enter your Pusher app secretConfigure these in your Vercel project settings or .env.production:
# Pusher Client Configuration
NEXT_PUBLIC_PUSHER_KEY=your-app-key
NEXT_PUBLIC_PUSHER_HOST=your-soketi-host.railway.app
NEXT_PUBLIC_PUSHER_PORT=443
NEXT_PUBLIC_PUSHER_CLUSTER=mt1
NEXT_PUBLIC_PUSHER_FORCE_TLS=true
NEXT_PUBLIC_PUSHER_ENCRYPTED=true
# Pusher Server Configuration
PUSHER_APP_ID=your-app-id
PUSHER_SECRET=your-app-secret
PUSHER_HOST=your-soketi-host.railway.app
PUSHER_PORT=443
PUSHER_USE_TLS=true
# Database (if using Better Auth)
DATABASE_URL=postgresql://user:password@host:5432/database
# Better Auth
AUTH_SECRET=your-random-secret-key
AUTH_URL=https://your-app.vercel.appConfigure these on your container platform (Railway, Fly.io, etc.):
# App Configuration
SOKETI_DEFAULT_APP_ID=your-app-id
SOKETI_DEFAULT_APP_KEY=your-app-key
SOKETI_DEFAULT_APP_SECRET=your-app-secret
# Server Configuration
SOKETI_HOST=0.0.0.0
SOKETI_PORT=6001
# SSL Configuration (if using custom domain)
SOKETI_SSL_CERT=/path/to/cert.pem
SOKETI_SSL_KEY=/path/to/key.pem
# CORS Configuration
SOKETI_CORS_ALLOWED_ORIGINS=https://your-app.vercel.appCreate or update vercel.json in your Next.js project:
{
"version": 2,
"buildCommand": "npm run build",
"devCommand": "npm run dev",
"installCommand": "npm install",
"framework": "nextjs",
"regions": ["iad1"],
"env": {
"NEXT_PUBLIC_PUSHER_KEY": "@pusher-key",
"NEXT_PUBLIC_PUSHER_HOST": "@pusher-host",
"NEXT_PUBLIC_PUSHER_PORT": "@pusher-port",
"PUSHER_APP_ID": "@pusher-app-id",
"PUSHER_SECRET": "@pusher-secret"
},
"build": {
"env": {
"NEXT_TELEMETRY_DISABLED": "1"
}
},
"headers": [
{
"source": "/api/(.*)",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "*"
},
{
"key": "Access-Control-Allow-Methods",
"value": "GET, POST, PUT, DELETE, OPTIONS"
},
{
"key": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
}
]
}
]
}Optimize your next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
// Output configuration
output: 'standalone',
// Image optimization
images: {
domains: ['localhost'],
formats: ['image/avif', 'image/webp'],
},
// Compression
compress: true,
// Headers for security
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'X-Frame-Options',
value: 'DENY',
},
{
key: 'X-XSS-Protection',
value: '1; mode=block',
},
],
},
];
},
};
module.exports = nextConfig;Configure Pusher client in your Next.js app (lib/pusher.ts):
import Pusher from 'pusher-js';
export const pusherClient = new Pusher(process.env.NEXT_PUBLIC_PUSHER_KEY!, {
wsHost: process.env.NEXT_PUBLIC_PUSHER_HOST,
wsPort: parseInt(process.env.NEXT_PUBLIC_PUSHER_PORT || '443'),
wssPort: parseInt(process.env.NEXT_PUBLIC_PUSHER_PORT || '443'),
forceTLS: process.env.NEXT_PUBLIC_PUSHER_FORCE_TLS === 'true',
encrypted: true,
disableStats: true,
enabledTransports: ['ws', 'wss'],
cluster: process.env.NEXT_PUBLIC_PUSHER_CLUSTER || 'mt1',
authEndpoint: '/api/pusher/auth',
});
// Connection state monitoring
pusherClient.connection.bind('connected', () => {
console.log('✅ Connected to soketi.rs');
});
pusherClient.connection.bind('disconnected', () => {
console.log('❌ Disconnected from soketi.rs');
});
pusherClient.connection.bind('error', (err: any) => {
console.error('❌ Connection error:', err);
});
export default pusherClient;Configure Pusher server in your API routes (app/api/pusher/auth/route.ts):
import { NextRequest, NextResponse } from 'next/server';
import Pusher from 'pusher';
const pusher = new Pusher({
appId: process.env.PUSHER_APP_ID!,
key: process.env.NEXT_PUBLIC_PUSHER_KEY!,
secret: process.env.PUSHER_SECRET!,
cluster: process.env.NEXT_PUBLIC_PUSHER_CLUSTER || 'mt1',
host: process.env.PUSHER_HOST,
port: process.env.PUSHER_PORT,
useTLS: process.env.PUSHER_USE_TLS === 'true',
});
export async function POST(req: NextRequest) {
// Authentication logic here
const body = await req.text();
const params = new URLSearchParams(body);
const socketId = params.get('socket_id');
const channelName = params.get('channel_name');
if (!socketId || !channelName) {
return NextResponse.json({ error: 'Missing parameters' }, { status: 400 });
}
// Authorize channel
const authResponse = pusher.authorizeChannel(socketId, channelName);
return NextResponse.json(authResponse);
}Vercel automatically provides SSL certificates for all deployments:
- Custom domains: Automatic SSL provisioning
- Vercel domains: SSL enabled by default
- Certificate renewal: Automatic via Let's Encrypt
For your soketi.rs server, configure SSL on your hosting platform:
Railway:
- Automatic SSL for custom domains
- Use Railway's provided domain with SSL
Fly.io:
# Add custom domain
fly certs add your-domain.com
# Check certificate status
fly certs show your-domain.comManual SSL Configuration:
If using a VPS, configure SSL in soketi.rs:
# Environment variables
SOKETI_SSL_CERT=/etc/ssl/certs/cert.pem
SOKETI_SSL_KEY=/etc/ssl/private/key.pem
SOKETI_SSL_PASSPHRASE=your-passphrase- Real-time Logs:
# View deployment logs
vercel logs
# Follow logs in real-time
vercel logs --follow-
Vercel Dashboard:
- Navigate to your project
- Click "Deployments" → Select deployment
- View logs, metrics, and errors
-
Analytics:
- Enable Vercel Analytics in project settings
- Monitor page views, performance, and Web Vitals
Health Check Endpoint:
# Check server health
curl https://your-soketi-host.railway.app/healthLogging Configuration:
# Enable debug logging
SOKETI_DEBUG=true
SOKETI_LOG_LEVEL=debugMonitoring Tools:
- Railway: Built-in metrics and logs
-
Fly.io:
fly logscommand and dashboard - External: Use services like Datadog, New Relic, or Sentry
Integrate error tracking in your Next.js app:
// lib/monitoring.ts
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
});Hobby Plan (Free):
- 100 GB bandwidth/month
- Unlimited deployments
- Automatic SSL
- Best for: Development and small projects
Pro Plan ($20/month):
- 1 TB bandwidth/month
- Advanced analytics
- Password protection
- Best for: Production applications
Enterprise Plan (Custom):
- Custom bandwidth
- SLA guarantees
- Dedicated support
- Best for: Large-scale applications
Railway:
- Starter: $5/month (512 MB RAM, 1 GB storage)
- Developer: $10/month (1 GB RAM, 10 GB storage)
- Team: $20/month (2 GB RAM, 20 GB storage)
Fly.io:
- Free tier: 3 shared-cpu-1x VMs, 160 GB bandwidth
- Paid: ~$5-20/month depending on resources
DigitalOcean:
- Basic Droplet: $6/month (1 GB RAM, 1 vCPU)
- App Platform: $5/month (512 MB RAM)
Small Project:
- Vercel Hobby: $0
- Railway Starter: $5
- Total: $5/month
Production Application:
- Vercel Pro: $20
- Railway Developer: $10
- Database (optional): $7
- Total: $37/month
Enterprise:
- Vercel Enterprise: Custom
- Dedicated servers: $50-200+
- Total: $100-500+/month
soketi.rs Cluster:
Deploy multiple soketi.rs instances behind a load balancer:
# docker-compose.yml
version: '3.8'
services:
soketi-1:
image: quay.io/soketi/soketi:latest-16-alpine
environment:
- SOKETI_DEFAULT_APP_ID=app-id
- SOKETI_DEFAULT_APP_KEY=app-key
- SOKETI_DEFAULT_APP_SECRET=app-secret
soketi-2:
image: quay.io/soketi/soketi:latest-16-alpine
environment:
- SOKETI_DEFAULT_APP_ID=app-id
- SOKETI_DEFAULT_APP_KEY=app-key
- SOKETI_DEFAULT_APP_SECRET=app-secret
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- soketi-1
- soketi-2Increase Resources:
Railway:
# Upgrade plan in Railway dashboard
# Settings → Plan → Select higher tierFly.io:
# Scale VM size
fly scale vm shared-cpu-2x
# Scale VM count
fly scale count 3Vercel automatically scales your frontend:
- Edge Network: Global CDN distribution
- Serverless Functions: Auto-scaling based on traffic
- No configuration needed: Scales automatically
- Enable Redis for soketi.rs:
# Use Redis adapter for horizontal scaling
SOKETI_ADAPTER_DRIVER=redis
SOKETI_REDIS_HOST=your-redis-host
SOKETI_REDIS_PORT=6379- Connection Pooling:
// Optimize Pusher client connections
const pusher = new Pusher(key, {
cluster: 'mt1',
enabledTransports: ['ws', 'wss'],
activityTimeout: 30000,
pongTimeout: 10000,
});- Caching Strategy:
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/static/:path*',
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable',
},
],
},
];
},
};1. WebSocket Connection Failed
Error: WebSocket connection to 'wss://...' failed
Solution:
- Verify
NEXT_PUBLIC_PUSHER_HOSTis correct - Ensure soketi.rs server is running
- Check firewall rules allow WebSocket connections
- Verify SSL certificate is valid
2. CORS Errors
Access to XMLHttpRequest blocked by CORS policy
Solution:
# Add Vercel domain to soketi.rs CORS
SOKETI_CORS_ALLOWED_ORIGINS=https://your-app.vercel.app,https://your-app-*.vercel.app3. Environment Variables Not Loading
Solution:
# Redeploy after setting environment variables
vercel env pull
vercel --prod4. Build Failures
Error: Module not found
Solution:
# Clear cache and rebuild
vercel --force5. High Latency
Solution:
- Deploy soketi.rs in same region as Vercel deployment
- Use Vercel's edge network
- Enable compression in Next.js config
Enable debug logging:
// lib/pusher.ts
Pusher.logToConsole = true;
const pusher = new Pusher(key, {
enabledTransports: ['ws', 'wss'],
// ... other config
});Monitor your deployment:
# Check Vercel deployment
curl https://your-app.vercel.app/api/health
# Check soketi.rs server
curl https://your-soketi-host.railway.app/health