Prerequisites
- A RamNode VPS running Ubuntu 24.04 LTS (recommended: 2 GB RAM / 1 vCPU minimum — available starting at $10/month)
- A registered domain name with DNS pointed to your VPS IP address
- SSH access to your server with root or sudo privileges
- Basic familiarity with the Linux command line
Initial Server Setup
ssh root@your_server_ip
# Create a dedicated non-root user
adduser remix
usermod -aG sudo remix
# Update system packages
apt update && apt upgrade -yConfigure the Firewall
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable
# Verify the rules are active
ufw statusInstall Node.js
Install Node.js 22 LTS using the NodeSource repository. Remix requires Node.js 18 or later, and Node 22 provides the best performance and long-term support.
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
apt install -y nodejs
# Verify the installation
node -v
npm -vCreate and Build Remix Application
su - remixNew Project
npx create-remix@latest my-remix-app
cd my-remix-appExisting Project
git clone https://github.com/yourusername/your-remix-app.git
cd your-remix-app
npm install# Build for production
npm run build
# Test the production build
npm start
# Visit http://your_server_ip:3000 to confirm
# Press Ctrl+C to stopConfigure PM2 for Process Management
PM2 keeps your Remix app running in the background, automatically restarts it on crashes, and relaunches it after server reboots.
sudo npm install -g pm2module.exports = {
apps: [
{
name: "remix-app",
script: "npm",
args: "start",
cwd: "/home/remix/my-remix-app",
env: {
NODE_ENV: "production",
PORT: 3000,
},
instances: "max",
exec_mode: "cluster",
autorestart: true,
watch: false,
max_memory_restart: "512M",
log_date_format: "YYYY-MM-DD HH:mm:ss Z",
error_file: "/home/remix/.pm2/logs/remix-error.log",
out_file: "/home/remix/.pm2/logs/remix-out.log",
},
],
};The instances: "max" setting runs one process per CPU core for maximum throughput. On a single-core RamNode VPS, this defaults to one instance. For multi-core plans, PM2 will automatically scale across all available cores.
pm2 start ecosystem.config.js
pm2 save
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u remix --hp /home/remixpm2 status # View running processes
pm2 logs remix-app # Tail application logs
pm2 monit # Interactive monitoring dashboard
pm2 restart remix-app # Restart the application
pm2 reload remix-app # Zero-downtime reloadSet Up Nginx Reverse Proxy
sudo apt install -y nginxserver {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml application/xml+rss text/javascript
image/svg+xml;
# Static asset caching — Remix fingerprints assets in /build/
location /build/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Favicon and static public files
location /favicon.ico {
proxy_pass http://127.0.0.1:3000;
expires 30d;
access_log off;
}
# All other requests — proxy to Remix
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
}sudo ln -s /etc/nginx/sites-available/remix-app /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginxSecure with SSL Using Let's Encrypt
sudo apt install -y certbot python3-certbot-nginx
# Obtain and install the SSL certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Verify auto-renewal is configured
sudo certbot renew --dry-runCertbot will automatically modify your Nginx configuration to handle HTTPS and redirect HTTP traffic.
Configure Environment Variables
nano /home/remix/my-remix-app/.envNODE_ENV=production
PORT=3000
DATABASE_URL=your_database_connection_string
SESSION_SECRET=your_random_session_secret# Generate a strong session secret
openssl rand -hex 32
# Lock down file permissions
chmod 600 /home/remix/my-remix-app/.env
# Restart PM2 after environment variable changes
pm2 restart remix-appAutomated Deployments (Optional)
#!/bin/bash
set -e
APP_DIR="/home/remix/my-remix-app"
BRANCH="main"
echo "=== Deploying Remix Application ==="
cd "$APP_DIR"
echo "Pulling latest changes..."
git pull origin "$BRANCH"
echo "Installing dependencies..."
npm ci --production=false
echo "Building application..."
npm run build
echo "Reloading PM2 (zero-downtime)..."
pm2 reload remix-app
echo "=== Deployment complete ==="chmod +x /home/remix/deploy.sh
# Run whenever you push updates
/home/remix/deploy.shFor fully automated CI/CD, add a GitHub Actions workflow or a webhook that triggers this script on push to your main branch.
Monitoring & Maintenance
# Application logs
pm2 logs remix-app --lines 100
# Nginx logs
journalctl -u nginx --since today
# Resource monitoring
pm2 monit # PM2 process dashboard
htop # System resource usage
df -h # Disk usageKeeping Dependencies Updated
sudo apt update && sudo apt upgrade -y
cd /home/remix/my-remix-app && npm auditPM2 Log Rotation
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7Troubleshooting
Application won't start
Check PM2 error logs with pm2 logs remix-app --err --lines 50. Common issues include missing dependencies (run npm install) or incorrect PORT configuration.
502 Bad Gateway from Nginx
The Remix app isn't running or isn't listening on the expected port. Verify with pm2 status and ensure the port in your PM2 config matches the Nginx proxy_pass directive.
SSL certificate renewal fails
Ensure port 80 is open and Nginx is running. Test with sudo certbot renew --dry-run. Check that your DNS records still point to the correct IP.
High memory usage
Reduce PM2 cluster instances in ecosystem.config.js by setting instances: 1 on smaller VPS plans. Also ensure max_memory_restart is configured.
Build fails with out of memory
On VPS plans with 1 GB RAM, add swap space before building:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstabRemix Application Deployed Successfully!
Your Remix application is now running in production on a RamNode VPS with PM2 process management, Nginx reverse proxying, SSL encryption, and a deployment workflow. RamNode's SSD-backed VPS infrastructure provides the low-latency I/O and consistent performance that server-rendered frameworks like Remix depend on — starting at just $4/month.
