Repository navigation
netlify
Complete guide for deploying soketi.rs WebSocket server with Netlify platform
- Overview
- Prerequisites
- Step-by-Step Deployment
- Environment Variables
- Build Settings
- WebSocket Configuration
- SSL/TLS Setup
- Monitoring and Logging
- Cost Estimation
- Scaling Recommendations
- Troubleshooting
Netlify is a modern cloud platform for web projects with continuous deployment, serverless functions, and edge computing capabilities. Similar to Vercel, Netlify is optimized for static sites and serverless functions, so soketi.rs WebSocket server should be deployed separately while your frontend is hosted on Netlify.
Recommended Architecture:
- Frontend (Next.js chat app): Deployed on Netlify
- soketi.rs WebSocket server: Deployed on a container platform (Railway, Fly.io, or Render)
- Connection: Frontend connects to soketi.rs via WebSocket
Before deploying, ensure you have:
- A Netlify account (sign up here)
- Netlify CLI installed:
npm install -g netlify-cli - Git repository with your project
- A separate hosting solution for soketi.rs server
Deploy soketi.rs on a container platform that supports long-running WebSocket connections:
Option A: Using Render
# Create render.yaml in your soketi.rs project
cat > render.yaml << EOF
services:
- type: web
name: soketi-server
env: docker
dockerfilePath: ./Dockerfile
envVars:
- key: SOKETI_DEFAULT_APP_ID
value: app-id
- key: SOKETI_DEFAULT_APP_KEY
value: app-key
- key: SOKETI_DEFAULT_APP_SECRET
generateValue: true
- key: SOKETI_HOST
value: 0.0.0.0
- key: SOKETI_PORT
value: 6001
EOF
# Deploy to Render
# Push to GitHub and connect via Render dashboardOption B: Using Railway
# Install Railway CLI
npm install -g @railway/cli
# Login and deploy
railway login
railway init
railway upOption C: Using Fly.io
# Install Fly CLI
curl -L https://fly.io/install.sh | sh
# Deploy
fly auth login
fly launch
fly deployMethod 1: Using Netlify CLI
# Login to Netlify
netlify login
# Navigate to your Next.js project
cd next-chat-app
# Initialize Netlify site
netlify init
# Deploy
netlify deploy --prodMethod 2: Using Netlify Dashboard
- Go to Netlify Dashboard
- Click "Add new site" → "Import an existing project"
- Connect your Git provider (GitHub, GitLab, Bitbucket)
- Select your repository
- Configure build settings:
-
Build command:
npm run build -
Publish directory:
.next -
Functions directory:
.netlify/functions
-
Build command:
Create netlify.toml in your project root:
[build]
command = "npm run build"
publish = ".next"
[build.environment]
NEXT_TELEMETRY_DISABLED = "1"
NODE_VERSION = "20"
[[plugins]]
package = "@netlify/plugin-nextjs"
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-Content-Type-Options = "nosniff"
X-XSS-Protection = "1; mode=block"
Referrer-Policy = "strict-origin-when-cross-origin"
[[headers]]
for = "/api/*"
[headers.values]
Access-Control-Allow-Origin = "*"
Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, OPTIONS"
Access-Control-Allow-Headers = "Content-Type, Authorization"
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
[functions]
directory = ".netlify/functions"
node_bundler = "esbuild"
[dev]
command = "npm run dev"
port = 3000
targetPort = 3000
autoLaunch = falseConfigure environment variables in Netlify:
# Using Netlify CLI
netlify env:set NEXT_PUBLIC_PUSHER_HOST your-soketi-host.railway.app
netlify env:set NEXT_PUBLIC_PUSHER_PORT 443
netlify env:set NEXT_PUBLIC_PUSHER_KEY your-app-key
netlify env:set PUSHER_SECRET your-app-secret
# Or use Netlify Dashboard:
# Site settings → Environment variables → Add variablesConfigure these in Netlify Dashboard or via CLI:
# Pusher Client Configuration
NEXT_PUBLIC_PUSHER_KEY=your-app-key
NEXT_PUBLIC_PUSHER_HOST=your-soketi-host.render.com
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.render.com
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-site.netlify.app
# Netlify-specific
NETLIFY_SITE_ID=your-site-id
NETLIFY_AUTH_TOKEN=your-auth-tokenConfigure these on your container platform:
# 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
# CORS Configuration
SOKETI_CORS_ALLOWED_ORIGINS=https://your-site.netlify.app,https://deploy-preview-*--your-site.netlify.app
# SSL Configuration (if needed)
SOKETI_SSL_CERT=/path/to/cert.pem
SOKETI_SSL_KEY=/path/to/key.pemnetlify.toml (detailed configuration):
[build]
command = "npm run build"
publish = ".next"
functions = ".netlify/functions"
[build.environment]
# Node.js version
NODE_VERSION = "20"
# Disable telemetry
NEXT_TELEMETRY_DISABLED = "1"
# Build optimizations
NODE_OPTIONS = "--max-old-space-size=4096"
# Next.js plugin for Netlify
[[plugins]]
package = "@netlify/plugin-nextjs"
# Security headers
[[headers]]
for = "/*"
[headers.values]
Strict-Transport-Security = "max-age=63072000; includeSubDomains; preload"
X-Frame-Options = "DENY"
X-Content-Type-Options = "nosniff"
X-XSS-Protection = "1; mode=block"
Referrer-Policy = "strict-origin-when-cross-origin"
Permissions-Policy = "camera=(), microphone=(), geolocation=()"
# API routes headers
[[headers]]
for = "/api/*"
[headers.values]
Access-Control-Allow-Origin = "*"
Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, OPTIONS"
Access-Control-Allow-Headers = "Content-Type, Authorization"
Cache-Control = "no-cache, no-store, must-revalidate"
# Static assets caching
[[headers]]
for = "/_next/static/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
[[headers]]
for = "/static/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
# Redirects for API routes
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
force = true
# SPA fallback
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
conditions = {Role = ["admin"]}
# Functions configuration
[functions]
directory = ".netlify/functions"
node_bundler = "esbuild"
included_files = ["prisma/**/*"]
# Development settings
[dev]
command = "npm run dev"
port = 3000
targetPort = 3000
autoLaunch = false
framework = "#custom"
# Context-specific settings
[context.production]
environment = { NODE_ENV = "production" }
[context.deploy-preview]
environment = { NODE_ENV = "preview" }
[context.branch-deploy]
environment = { NODE_ENV = "development" }Update next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
// Netlify-specific output
output: 'standalone',
// Image optimization
images: {
domains: ['localhost'],
formats: ['image/avif', 'image/webp'],
// Netlify Image CDN
loader: 'custom',
loaderFile: './lib/netlify-image-loader.js',
},
// Compression
compress: true,
// Trailing slash for Netlify
trailingSlash: false,
// Environment variables
env: {
NEXT_PUBLIC_PUSHER_KEY: process.env.NEXT_PUBLIC_PUSHER_KEY,
NEXT_PUBLIC_PUSHER_HOST: process.env.NEXT_PUBLIC_PUSHER_HOST,
NEXT_PUBLIC_PUSHER_PORT: process.env.NEXT_PUBLIC_PUSHER_PORT,
},
// Webpack configuration
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.fallback = {
...config.resolve.fallback,
fs: false,
net: false,
tls: false,
};
}
return config;
},
// Security headers
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'X-DNS-Prefetch-Control',
value: 'on',
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'X-Frame-Options',
value: 'DENY',
},
],
},
];
},
};
module.exports = nextConfig;Add Netlify-specific scripts:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"netlify:dev": "netlify dev",
"netlify:build": "next build",
"netlify:deploy": "netlify deploy --prod"
}
}Configure Pusher client for Netlify deployment (lib/pusher.ts):
import Pusher from 'pusher-js';
// Enable logging in development
if (process.env.NODE_ENV === 'development') {
Pusher.logToConsole = true;
}
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: true,
encrypted: true,
disableStats: true,
enabledTransports: ['ws', 'wss'],
cluster: process.env.NEXT_PUBLIC_PUSHER_CLUSTER || 'mt1',
authEndpoint: '/api/pusher/auth',
// Connection timeout settings
activityTimeout: 30000,
pongTimeout: 10000,
unavailableTimeout: 10000,
});
// Connection state handlers
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);
});
pusherClient.connection.bind('state_change', (states: any) => {
console.log('🔄 Connection state:', states.current);
});
export default pusherClient;Create .netlify/functions/pusher-auth.ts:
import { Handler } from '@netlify/functions';
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: true,
});
export const handler: Handler = async (event) => {
// Only allow POST requests
if (event.httpMethod !== 'POST') {
return {
statusCode: 405,
body: JSON.stringify({ error: 'Method not allowed' }),
};
}
try {
const body = event.body || '';
const params = new URLSearchParams(body);
const socketId = params.get('socket_id');
const channelName = params.get('channel_name');
if (!socketId || !channelName) {
return {
statusCode: 400,
body: JSON.stringify({ error: 'Missing parameters' }),
};
}
// Get user from session (implement your auth logic)
// const user = await getUser(event);
// Presence channel
if (channelName.startsWith('presence-')) {
const presenceData = {
user_id: 'user-123', // Replace with actual user ID
user_info: {
name: 'User Name',
email: 'user@example.com',
},
};
const authResponse = pusher.authorizeChannel(socketId, channelName, presenceData);
return {
statusCode: 200,
body: JSON.stringify(authResponse),
};
}
// Private channel
if (channelName.startsWith('private-')) {
const authResponse = pusher.authorizeChannel(socketId, channelName);
return {
statusCode: 200,
body: JSON.stringify(authResponse),
};
}
return {
statusCode: 400,
body: JSON.stringify({ error: 'Invalid channel' }),
};
} catch (error) {
console.error('Auth error:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: 'Internal server error' }),
};
}
};Netlify provides automatic SSL certificates for all sites:
- Netlify domains: SSL enabled by default (*.netlify.app)
- Custom domains: Automatic SSL provisioning via Let's Encrypt
- Certificate renewal: Automatic, no manual intervention needed
- HTTPS redirect: Automatic redirect from HTTP to HTTPS
-
Add custom domain in Netlify Dashboard:
- Site settings → Domain management → Add custom domain
- Follow DNS configuration instructions
-
Verify SSL certificate:
- Netlify automatically provisions SSL certificate
- Usually takes 1-2 minutes
- Check status in Domain management section
-
Force HTTPS:
Add to netlify.toml:
[[redirects]]
from = "http://*"
to = "https://:splat"
status = 301
force = trueConfigure SSL on your soketi.rs hosting platform:
Render:
- Automatic SSL for all services
- Custom domains supported with automatic SSL
Railway:
- Automatic SSL for Railway domains
- Custom domain SSL available
Fly.io:
# Add custom domain with SSL
fly certs add your-domain.com
# Check certificate status
fly certs show your-domain.com1. Real-time Logs:
# View function logs
netlify functions:log
# View build logs
netlify watch
# View site logs
netlify logs2. Netlify Dashboard:
- Navigate to your site
- Deploys: View deployment history and logs
- Functions: Monitor function invocations and errors
- Analytics: Track page views and performance
3. Netlify Analytics:
Enable in site settings:
- Real user metrics
- Page views and unique visitors
- Top pages and sources
- No JavaScript required (server-side analytics)
Monitor Netlify Functions:
// Add logging to functions
export const handler: Handler = async (event) => {
console.log('Function invoked:', {
path: event.path,
method: event.httpMethod,
timestamp: new Date().toISOString(),
});
// Your function logic
return {
statusCode: 200,
body: JSON.stringify({ success: true }),
};
};Health Check:
# Check server health
curl https://your-soketi-host.render.com/healthLogging:
# Enable debug logging
SOKETI_DEBUG=true
SOKETI_LOG_LEVEL=debugIntegrate third-party monitoring:
Sentry for Error Tracking:
// lib/sentry.ts
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NETLIFY_CONTEXT || 'development',
tracesSampleRate: 1.0,
});LogRocket for Session Replay:
// lib/logrocket.ts
import LogRocket from 'logrocket';
if (typeof window !== 'undefined' && process.env.NODE_ENV === 'production') {
LogRocket.init(process.env.NEXT_PUBLIC_LOGROCKET_ID!);
}Starter Plan (Free):
- 100 GB bandwidth/month
- 300 build minutes/month
- Automatic SSL
- Deploy previews
- Best for: Personal projects and development
Pro Plan ($19/month):
- 400 GB bandwidth/month
- 1,000 build minutes/month
- Password protection
- Analytics
- Best for: Professional sites
Business Plan ($99/month):
- 1 TB bandwidth/month
- Unlimited build minutes
- SSO/SAML
- Priority support
- Best for: Team projects
Enterprise Plan (Custom):
- Custom bandwidth and builds
- SLA guarantees
- Dedicated support
- Best for: Large organizations
Render:
- Free tier: 750 hours/month (sleeps after inactivity)
- Starter: $7/month (always on, 512 MB RAM)
- Standard: $25/month (2 GB RAM)
Railway:
- Starter: $5/month (512 MB RAM)
- Developer: $10/month (1 GB RAM)
Fly.io:
- Free tier: 3 shared VMs, 160 GB bandwidth
- Paid: ~$5-20/month depending on resources
Small Project:
- Netlify Starter: $0
- Render Free: $0
- Total: $0/month (with limitations)
Production Application:
- Netlify Pro: $19
- Render Starter: $7
- Database (optional): $7
- Total: $33/month
Business Application:
- Netlify Business: $99
- Render Standard: $25
- Database: $15
- Monitoring: $10
- Total: $149/month
Enterprise:
- Netlify Enterprise: Custom ($200+)
- Dedicated servers: $100-500+
- Total: $300-1000+/month
soketi.rs Cluster:
Deploy multiple instances with Redis adapter:
# soketi.rs environment variables
SOKETI_ADAPTER_DRIVER=redis
SOKETI_REDIS_HOST=your-redis-host.com
SOKETI_REDIS_PORT=6379
SOKETI_REDIS_PASSWORD=your-redis-passwordLoad Balancing:
Use your hosting platform's load balancer or deploy behind Nginx/Caddy.
Increase Resources:
Render:
# Upgrade plan in Render dashboard
# Settings → Instance Type → Select higher tierRailway:
# Upgrade in Railway dashboard
# Settings → Plan → Select higher tierNetlify automatically scales:
- Edge Network: Global CDN with 100+ locations
- Functions: Auto-scaling serverless functions
- Instant Cache Invalidation: Fast content updates
- No configuration needed: Scales automatically with traffic
1. Enable Redis for soketi.rs:
# Horizontal scaling with Redis
SOKETI_ADAPTER_DRIVER=redis
SOKETI_REDIS_HOST=redis-host
SOKETI_REDIS_PORT=63792. Optimize Netlify Functions:
// Use edge functions for better performance
export const config = {
path: '/api/pusher/auth',
cache: 'manual',
};3. Implement Caching:
# netlify.toml
[[headers]]
for = "/_next/static/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"4. Use Netlify Image CDN:
// next.config.js
module.exports = {
images: {
loader: 'custom',
loaderFile: './lib/netlify-image-loader.js',
},
};1. Build Failures
Error: Command failed with exit code 1
Solution:
# Check build logs in Netlify dashboard
# Clear cache and retry
netlify build --clear-cache
# Test build locally
npm run build2. Function Timeout
Error: Function execution timed out
Solution:
# Increase function timeout in netlify.toml
[functions]
timeout = 303. WebSocket Connection Failed
Error: WebSocket connection failed
Solution:
- Verify soketi.rs server is running
- Check CORS configuration
- Ensure SSL certificates are valid
- Verify environment variables are set correctly
4. Environment Variables Not Loading
Solution:
# Pull environment variables locally
netlify env:list
# Set missing variables
netlify env:set VARIABLE_NAME value
# Redeploy
netlify deploy --prod5. CORS Errors
Access-Control-Allow-Origin error
Solution:
# Update soketi.rs CORS settings
SOKETI_CORS_ALLOWED_ORIGINS=https://your-site.netlify.app,https://deploy-preview-*--your-site.netlify.app6. Deploy Preview Issues
Solution:
# Configure deploy previews in netlify.toml
[context.deploy-preview]
environment = { NODE_ENV = "preview" }
[context.deploy-preview.environment]
NEXT_PUBLIC_PUSHER_HOST = "preview-soketi-host.com"Enable debug logging:
// lib/pusher.ts
if (process.env.NODE_ENV !== 'production') {
Pusher.logToConsole = true;
}
const pusher = new Pusher(key, {
enabledTransports: ['ws', 'wss'],
// ... other config
});Monitor your deployment:
# Check Netlify site
curl https://your-site.netlify.app/api/health
# Check soketi.rs server
curl https://your-soketi-host.render.com/health
# Check Netlify function
curl https://your-site.netlify.app/.netlify/functions/pusher-auth# Test functions locally
netlify dev
# View function logs
netlify functions:log pusher-auth
# Check site status
netlify status
# View recent deploys
netlify deploy:list