How to Run Multiple Projects on One Linux Server

Vibesies Team | 2026-06-08 | Hosting & Deployment

Why Run Multiple Projects on One Server?

If you're a freelancer, agency, or solo developer, spinning up a new VPS for every project gets expensive fast. A single managed Linux VPS can comfortably host 5–10 projects at once, each isolated and independent, without one crashing the others.

The trick is using the right tooling: process managers to keep each app alive, a reverse proxy to route traffic to the right port, and sensible naming conventions so you don't confuse which project is which at 2 a.m.

This guide walks through the architecture, the tools, and the gotchas.

The Architecture: Process Manager + Reverse Proxy

The standard pattern for running multiple projects on one Linux server is simple:

  • Each project runs on its own port — Project A on 3001, Project B on 3002, etc.
  • A reverse proxy (usually Nginx) sits on port 80/443 — it listens for incoming traffic and forwards requests to the right port based on the domain.
  • A process manager (PM2, systemd, or Supervisor) — keeps each app running, restarts it if it crashes, and handles logging.

This separation means if Project A has a memory leak and dies, Project B keeps running. The reverse proxy detects the failure and can serve a 502 error or fallback page without taking down the whole server.

Step 1: Choose a Process Manager

You have three main options:

PM2 (Recommended for Node.js)

PM2 is the easiest to learn and works great for Node.js, Python, and Go apps. Install it once globally:

npm install -g pm2
pm2 startup
pm2 save

Then start each app with a descriptive name:

pm2 start app.js --name "client-dashboard"
pm2 start server.py --name "api-service" --interpreter python3
pm2 start index.js --name "blog-site"

Check status anytime:

pm2 status

PM2 auto-restarts apps on reboot and if they crash. It also handles log rotation and gives you a centralized log viewer.

Systemd (More Control, Steeper Learning Curve)

If you want fine-grained control or are running non-Node apps, systemd is powerful. You create a unit file for each app:

[Unit]
Description=Client Dashboard
After=network.target

[Service]
Type=simple
User=vibe
WorkingDirectory=/home/vibe/projects/client-dashboard
ExecStart=/usr/bin/node app.js
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Then enable and start it:

sudo systemctl enable client-dashboard
sudo systemctl start client-dashboard
sudo systemctl status client-dashboard

Systemd is more verbose but integrates deeply with Linux and gives you better resource limits and dependencies.

Supervisor (Older, Still Solid)

Supervisor is language-agnostic and works well for Python and PHP apps. It's less trendy than PM2 but battle-tested. Skip it unless you have a specific reason — PM2 or systemd are better starting points.

Step 2: Set Up a Reverse Proxy with Nginx

Nginx listens on ports 80 and 443, reads the incoming domain name, and forwards traffic to the right port. Install it:

sudo apt update
sudo apt install nginx

Create a config file for each project in /etc/nginx/sites-available/:

sudo nano /etc/nginx/sites-available/client-dashboard

Paste this template:

upstream client_dashboard {
    server 127.0.0.1:3001;
}

server {
    listen 80;
    server_name dashboard.example.com;

    location / {
        proxy_pass http://client_dashboard;
        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;
        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;
    }
}

Enable the site and test the config:

sudo ln -s /etc/nginx/sites-available/client-dashboard /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Repeat for each project, changing the upstream port and domain name. Nginx will route traffic based on the Host header (the domain), so each project gets its own subdomain or domain.

Step 3: Use SSL/TLS with Let's Encrypt

Don't run unencrypted. Certbot makes SSL free and automatic:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d dashboard.example.com -d api.example.com -d blog.example.com

Certbot updates your Nginx configs automatically and sets up renewal. Check the renewal is working:

sudo certbot renew --dry-run

Step 4: Organize Your Projects

Create a clear directory structure so you don't lose track of which project is which:

/home/vibe/projects/
├── client-dashboard/
│   ├── app.js
│   ├── package.json
│   └── .env
├── api-service/
│   ├── server.py
│   ├── requirements.txt
│   └── .env
└── blog-site/
    ├── index.js
    ├── package.json
    └── .env

Use consistent naming: lowercase, hyphens, no spaces. Document which port each app uses in a README at the top level or in your process manager config.

Step 5: Manage Secrets and Environment Variables

Each project needs its own .env file with database URLs, API keys, and other secrets. Never commit .env to git.

If you're using PM2, you can also pass environment variables in an ecosystem.config.js file:

module.exports = {
  apps: [
    {
      name: 'client-dashboard',
      script: 'app.js',
      cwd: '/home/vibe/projects/client-dashboard',
      env: {
        NODE_ENV: 'production',
        PORT: 3001,
        DATABASE_URL: 'postgres://...',
      },
    },
    {
      name: 'api-service',
      script: 'server.py',
      cwd: '/home/vibe/projects/api-service',
      interpreter: 'python3',
      env: {
        FLASK_ENV: 'production',
        PORT: 3002,
      },
    },
  ],
};

Then start all apps with:

pm2 start ecosystem.config.js

Step 6: Monitor and Debug

Check logs for each project:

pm2 logs client-dashboard
pm2 logs api-service --lines 100

Check resource usage:

pm2 monit

If Nginx isn't routing traffic correctly, check the error log:

sudo tail -f /var/log/nginx/error.log

If a project is crashing, check its logs and restart it:

pm2 restart client-dashboard

Common Pitfalls

Port Conflicts

If two apps try to use the same port, one will fail to start. Use a spreadsheet or a comment in your config to track which app uses which port. Better yet, automate it with a script that assigns the next available port.

Memory Leaks

One project with a slow memory leak will eventually consume all RAM and crash. Set memory limits in PM2:

pm2 start app.js --max-memory-restart 500M

Or in systemd with MemoryLimit= in the unit file.

Domain Routing Mistakes

If traffic for dashboard.example.com ends up at the wrong app, double-check the Nginx server_name directive and make sure DNS is pointing to your server.

Forgetting to Enable Sites

Creating an Nginx config file doesn't activate it. You must symlink it to sites-enabled/ and reload Nginx. If a domain works for one project but not another, this is often the culprit.

Scaling Beyond One Server

If you grow to 20+ projects or need higher availability, you'll eventually want separate servers or containers. But for most freelancers and small agencies, one well-managed Linux VPS handles 5–10 projects fine.

Tools like Vibesies abstract away some of this setup — you get a pre-configured Linux environment with Claude Code or Codex built in, so you can focus on building and deploying your projects instead of wrestling with systemd and Nginx. That said, the architecture above still applies whether you're self-managing or using managed hosting.

Checklist: Running Multiple Projects on One Linux Server

  • Choose PM2, systemd, or Supervisor and install it
  • Create a process manager config or unit file for each project
  • Assign each project a unique port (3001, 3002, 3003, …)
  • Install and configure Nginx as a reverse proxy
  • Create Nginx config files for each domain/project
  • Enable Nginx sites and test the config
  • Set up SSL with Certbot
  • Organize projects in a clear directory structure
  • Create .env files for secrets
  • Test that each domain routes to the correct app
  • Set up log rotation and monitoring
  • Document which port each project uses
  • Set memory limits to prevent one app from crashing others

Conclusion

Running multiple projects on one Linux server is a practical, cost-effective way to host your work. The key is separating concerns: each app runs on its own port, a reverse proxy routes traffic by domain, and a process manager keeps everything alive. With PM2, Nginx, and a bit of organization, you can manage dozens of projects without much overhead.

As you scale, you'll refine your setup — adding monitoring, automating deployments, maybe moving to containers. But the fundamentals of developer hosting — process isolation, reverse proxying, and sensible naming — stay the same.

Back to Blog
["linux vps", "multiple projects", "nginx", "process manager", "pm2"]