Skip to main content

Prerequisites

Before deploying, ensure you have:
  • Node.js 16+ installed
  • npm or yarn package manager
  • Git for version control
  • A hosting platform account (Render, Heroku, Railway, etc.)

Environment Variables

The server uses the following environment variable:
PORT
number
default:"9090"
The port on which the server will listen. Most cloud platforms automatically set this.

Setting Environment Variables

# Development (.env file)
PORT=9090

# Production (platform-specific)
# Render/Heroku will set PORT automatically
The server falls back to port 9090 if PORT is not set:
const PORT = process.env.PORT || 9090;

Local Development

1. Install Dependencies

npm install
This installs the following packages from package.json:
package.json
{
  "dependencies": {
    "express": "^5.1.0",
    "socket.io": "^4.8.1",
    "socket.io-client": "^4.8.1",
    "ws": "^8.18.2"
  },
  "devDependencies": {
    "vite": "^6.3.4"
  }
}
  • express: Web framework for serving static files and creating the HTTP server
  • socket.io: Real-time bidirectional event-based communication library
  • socket.io-client: Client library (used in frontend)
  • ws: Alternative WebSocket library (used in server2.js)
  • vite: Development server and build tool for the frontend

2. Run Development Server

Backend (Socket.IO Server)

npm start
This runs the main server:
package.json
{
  "scripts": {
    "start": "node server.js"
  }
}
The server will start on http://localhost:9090

Frontend (Vite Dev Server)

npm run dev
This starts the Vite development server:
package.json
{
  "scripts": {
    "dev": "vite"
  }
}
Vite configuration:
vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  root: './public',      // HTML files are in the public directory
  server: {
    host: '0.0.0.0',     // Allow LAN access
    port: 5173           // Default Vite port
  }
})
The frontend will be available at http://localhost:5173
Make sure to update the Socket.IO connection URL in your client code to point to http://localhost:9090 during development.

3. Build for Production

npm run build
This creates an optimized production build:
package.json
{
  "scripts": {
    "build": "vite build"
  }
}
The build output will be in the dist/ directory.

4. Preview Production Build

npm run preview
This serves the production build locally:
package.json
{
  "scripts": {
    "preview": "vite preview"
  }
}

Production Deployment

Deploy to Render

Render is a popular platform for deploying Node.js applications with WebSocket support.

Step 1: Prepare Your Repository

Ensure your code is in a Git repository (GitHub, GitLab, or Bitbucket).

Step 2: Create a New Web Service

  1. Go to render.com and sign in
  2. Click New +Web Service
  3. Connect your repository
  4. Configure the service:
services:
  - type: web
    name: pica-y-fija
    env: node
    buildCommand: npm install && npm run build
    startCommand: npm start
    envVars:
      - key: NODE_ENV
        value: production

Step 3: Configure CORS

Update your server to allow your Render frontend URL:
server.js
const io = new Server(server, {
    cors: {
        origin: process.env.FRONTEND_URL || "*",
        methods: ["GET", "POST"]
    }
});
Add FRONTEND_URL environment variable in Render:
FRONTEND_URL=https://your-app.onrender.com

Step 4: Deploy

Render will automatically:
  1. Install dependencies
  2. Build the frontend
  3. Start the server
  4. Provide a URL like https://pica-y-fija.onrender.com
Render’s free tier may spin down with inactivity. Upgrade to a paid plan for always-on instances.

Deploy to Heroku

Step 1: Install Heroku CLI

npm install -g heroku
heroku login

Step 2: Create Heroku App

heroku create pica-y-fija

Step 3: Add Procfile

Create a Procfile in your project root:
Procfile
web: node server.js

Step 4: Configure Buildpacks

heroku buildpacks:set heroku/nodejs

Step 5: Deploy

git add .
git commit -m "Prepare for Heroku deployment"
git push heroku main

Step 6: Scale Dynos

heroku ps:scale web=1

Step 7: View Logs

heroku logs --tail
Heroku’s free tier was discontinued. You’ll need a paid plan or use alternatives like Render or Railway.

Deploy to Railway

Step 1: Connect Repository

  1. Go to railway.app
  2. Click New ProjectDeploy from GitHub repo
  3. Select your repository

Step 2: Configure

Railway auto-detects Node.js projects. No additional configuration needed.

Step 3: Environment Variables

Railway automatically sets PORT. Add any custom variables in the dashboard.

Step 4: Deploy

Railway automatically deploys on every push to your main branch.

Deploy to VPS (Ubuntu/Debian)

Step 1: SSH into Server

ssh user@your-server-ip

Step 2: Install Node.js

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

Step 3: Clone Repository

git clone https://github.com/yourusername/pica-y-fija.git
cd pica-y-fija

Step 4: Install Dependencies and Build

npm install
npm run build

Step 5: Install PM2 (Process Manager)

sudo npm install -g pm2

Step 6: Start Server with PM2

pm2 start server.js --name pica-y-fija
pm2 save
pm2 startup

Step 7: Configure Nginx as Reverse Proxy

/etc/nginx/sites-available/pica-y-fija
server {
    listen 80;
    server_name your-domain.com;

    location / {
        proxy_pass http://localhost:9090;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/pica-y-fija /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Step 8: SSL with Let’s Encrypt

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com

WebSocket Support

Ensure your hosting platform supports WebSockets. Most modern platforms do, but some require specific configuration.

Platform WebSocket Support

PlatformWebSocket SupportNotes
Render✅ YesNative support, no configuration needed
Heroku✅ YesWorks on all dynos
Railway✅ YesNative support
Vercel⚠️ LimitedServerless functions have 10s timeout
Netlify❌ NoStatic hosting only
VPS✅ YesRequires Nginx configuration

Monitoring and Logging

Add Logging

Enhance server.js with better logging:
server.js
const PORT = process.env.PORT || 9090;
server.listen(PORT, () => {
    console.log(`Servidor Socket.IO corriendo en el puerto ${PORT}`);
    console.log(`Environment: ${process.env.NODE_ENV || 'development'}`);
});

io.on('connection', socket => {
    console.log(`[${new Date().toISOString()}] New connection: ${socket.id}`);
    
    socket.on('disconnect', () => {
        console.log(`[${new Date().toISOString()}] Disconnection: ${socket.id}`);
    });
});

View Logs

# View in dashboard or CLI
render logs -s your-service-name

Performance Optimization

Enable Compression

npm install compression
server.js
const compression = require('compression');
app.use(compression());

Rate Limiting

npm install express-rate-limit
server.js
const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 minutes
    max: 100 // limit each IP to 100 requests per windowMs
});

app.use(limiter);

Redis Adapter for Horizontal Scaling

For multi-server deployments:
npm install @socket.io/redis-adapter redis
server.js
const { createAdapter } = require('@socket.io/redis-adapter');
const { createClient } = require('redis');

const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();

Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
    io.adapter(createAdapter(pubClient, subClient));
});

Troubleshooting

CORS Issues

server.js
const io = new Server(server, {
    cors: {
        origin: ["https://your-frontend.com", "http://localhost:5173"],
        methods: ["GET", "POST"],
        credentials: true
    }
});

Port Already in Use

# Find process using port 9090
lsof -i :9090

# Kill the process
kill -9 <PID>

WebSocket Connection Failed

Check client connection URL:
// Development
const socket = io('http://localhost:9090');

// Production
const socket = io('https://your-app.onrender.com');

Memory Issues

The in-memory room storage can grow. Consider adding cleanup:
server.js
// Clean up empty rooms every 5 minutes
setInterval(() => {
    Object.keys(rooms).forEach(code => {
        if (rooms[code].players.length === 0) {
            delete rooms[code];
            publicRooms = publicRooms.filter(c => c !== code);
        }
    });
}, 5 * 60 * 1000);

Health Checks

Add a health check endpoint:
server.js
app.get('/health', (req, res) => {
    res.json({
        status: 'ok',
        uptime: process.uptime(),
        timestamp: Date.now(),
        rooms: Object.keys(rooms).length
    });
});

Continuous Deployment

Most platforms support automatic deployment:
  1. Render: Auto-deploys on push to main branch
  2. Heroku: Use Heroku Git or GitHub integration
  3. Railway: Auto-deploys on push to main branch

GitHub Actions Example

.github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
      - run: npm ci
      - run: npm run build
      - run: npm test
      # Deploy step (platform-specific)
Remember to update your client-side Socket.IO connection URL to match your production server URL.

Build docs developers (and LLMs) love