Deploying WebSocket Applications
1. Deploying to Cloud Platforms
| Platform | WS Support |
|---|---|
| AWS (EC2/ECS/EKS + ALB/NLB) | Full |
| GCP (GKE / Cloud Run) | Full; Cloud Run has 1h cap |
| Azure (AKS / App Service) | Full with sticky |
| Fly.io | Native, region-routed |
| Render / Railway | Supported |
2. Deploying to Heroku
| Detail | Notes |
|---|---|
| WS support | Yes, on all dynos |
| Idle timeout | 55s (router); heartbeat ≤ 45s |
| Sticky sessions | Lab feature |
| Max conn / dyno | ~5000 |
3. Deploying to Vercel
| Constraint | Detail |
|---|---|
| Serverless functions | No long-lived WS |
| Recommended | External WS service (Ably/Pusher/PartyKit) |
| Edge functions | Limited WS via upgradeWebSocket |
4. Deploying to DigitalOcean
| Resource | WS Notes |
|---|---|
| Droplet | Full Linux server |
| App Platform | Native WS support |
| Load Balancer | L4 passthrough or L7 (HTTP) |
| Kubernetes | Standard ingress (nginx) |
5. Configuring Docker Containers
Example: Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 8080
ENV NODE_ENV=production
CMD ["node", "server.js"]
| Setting | Detail |
|---|---|
EXPOSE | WS port |
ulimit nofile | Increase for many conns |
| Healthcheck | HEALTHCHECK CMD curl /healthz |
| Signal handling | SIGTERM → graceful drain |
6. Setting Environment Variables
| Var | Purpose |
|---|---|
PORT | Listen port |
NODE_ENV | production |
JWT_PUBLIC_KEY | Verify tokens |
REDIS_URL | Pub/sub backplane |
LOG_LEVEL | info / debug |
7. Configuring SSL/TLS Certificates
| Source | Detail |
|---|---|
| Let's Encrypt + certbot | Free, auto-renew |
| AWS ACM | Free for AWS LBs |
| Cloudflare | Edge TLS |
| Terminate at LB | Common pattern |
8. Setting Up Process Managers
| Tool | Use |
|---|---|
| PM2 | Node clustering, restart |
| systemd | OS-level service |
| Docker / K8s | Container orchestration |
| forever / nodemon | Dev only |
9. Implementing Health Checks
Example: Liveness vs readiness
app.get("/livez", (_, res) => res.send("ok"));
app.get("/readyz", async (_, res) => {
try { await redis.ping(); res.send("ready"); }
catch { res.status(503).send("down"); }
});
| Endpoint | Purpose |
|---|---|
| /livez | Process alive |
| /readyz | Can accept traffic |
| /healthz | Aggregate |
10. Configuring Auto-Restart
| Trigger | Detail |
|---|---|
| Crash | PM2/systemd restart |
| OOM | K8s pod restart |
| Healthcheck fail | K8s readiness flip |
| Deploy | Rolling update |