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:
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
This installs the following packages from 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)
This runs the main server:
{
"scripts" : {
"start" : "node server.js"
}
}
The server will start on http://localhost:9090
Frontend (Vite Dev Server)
This starts the Vite development server:
{
"scripts" : {
"dev" : "vite"
}
}
Vite configuration:
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
This creates an optimized production build:
{
"scripts" : {
"build" : "vite build"
}
}
The build output will be in the dist/ directory.
4. Preview Production Build
This serves the production build locally:
{
"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
Go to render.com and sign in
Click New + → Web Service
Connect your repository
Configure the service:
render.yaml
Manual Configuration
services :
- type : web
name : pica-y-fija
env : node
buildCommand : npm install && npm run build
startCommand : npm start
envVars :
- key : NODE_ENV
value : production
Update your server to allow your Render frontend URL:
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:
Install dependencies
Build the frontend
Start the server
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:
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
Step 7: View Logs
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
Go to railway.app
Click New Project → Deploy from GitHub repo
Select your repository
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
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)
Step 6: Start Server with PM2
pm2 start server.js --name pica-y-fija
pm2 save
pm2 startup
/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 Notes Render ✅ Yes Native support, no configuration needed Heroku ✅ Yes Works on all dynos Railway ✅ Yes Native support Vercel ⚠️ Limited Serverless functions have 10s timeout Netlify ❌ No Static hosting only VPS ✅ Yes Requires Nginx configuration
Monitoring and Logging
Add Logging
Enhance server.js with better logging:
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
Render
Heroku
Railway
PM2 (VPS)
# View in dashboard or CLI
render logs -s your-service-name
Enable Compression
const compression = require ( 'compression' );
app . use ( compression ());
Rate Limiting
npm install express-rate-limit
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
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
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 < PI D >
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:
// 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:
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:
Render : Auto-deploys on push to main branch
Heroku : Use Heroku Git or GitHub integration
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.