Loading...
Loading...
Use this skill whenever a user wants to deploy, host, run, or set up any project on a Linux VPS (Virtual Private Server). Triggers include: setting up a Node.js/Python/other app on a server, checking server compatibility with a project, making an app accessible online, fixing port issues, keeping an app running with PM2 or systemd, setting up tunnels (ngrok, localtunnel, pinggy), cloning private GitHub repos to a server, configuring environment variables, managing logs, enabling auto-restart on reboot, dealing with AWS/GCP firewalls, or any combination of these. Always use this skill when the user is working on a remote Linux server and wants to deploy or run any kind of application — even if they don't use the word "VPS" explicitly.
npx skill4agent add dev-muhammad-junaid/agent-skills vps-project-setuplscpu # CPU cores, architecture
free -h # Total/available RAM
df -h # Disk space
cat /etc/os-release # OS and version
uname -r # Kernel versionSeefor reading and interpreting common output formats.references/spec-interpretation.md
| Factor | What to check |
|---|---|
| Runtime | Node.js version, Python version, Go, etc. — is it installed? |
| RAM | Does the build + runtime fit? Next.js builds need ~1GB free |
| Disk | Does app + dependencies + data fit? |
| OS | Does the project require specific Linux distros or kernel features? |
| Native deps | FFmpeg, yt-dlp, ImageMagick, etc. — are they available? |
| Concurrent load | How many simultaneous users/jobs can the server handle? |
git clone https://github.com/user/repo.git project-folder
cd project-folderrepogit clone https://YOUR_TOKEN@github.com/user/repo.git project-folderSecurity note: Tokens in URLs are stored in. After cloning, optionally remove it:.git/configgit remote set-url origin https://github.com/user/repo.git
npm installcurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install --ltspip install -r requirements.txt # or
pip install -r requirements.txt --break-system-packages.env.example# Create .env from example
cp .env.example .env
nano .env # Edit values
# Or write a specific value directly
echo 'DATABASE_URL="file:./dev.db"' > .envDATABASE_URLPORTNODE_ENV=productionSECRET_KEYAWS_ACCESS_KEY_IDS3_BUCKET# Prisma
npx prisma generate
npx prisma db push # or npx prisma migrate deploy
# Django
python manage.py migratenpm run build # Next.js, React, etc.Monorepo warning: Ifwarns about multiplenpm run buildfiles or "workspace root mismatch", delete the conflicting lockfile in the parent directory:package-lock.jsonthen rebuild. This commonly happens in cloud IDEs (Gitpod, etc.).rm ../package-lock.json
# Install PM2
sudo npm install -g pm2
# Start app
pm2 start npm --name "my-app" -- run start
# OR for a specific command:
pm2 start "python app.py" --name "my-app"
pm2 start "gunicorn app:app" --name "my-app"
# Enable auto-restart on server reboot
pm2 startup # Follow the printed command exactly — copy/paste it
pm2 save # Save current process list
# Useful PM2 commands
pm2 list # See all running apps
pm2 logs my-app # View live logs
pm2 restart my-app
pm2 stop my-app
pm2 delete my-appreferences/systemd-service.md.serviceDoes the server have a stable public IP?
├── YES → Is port open?
│ ├── Check with: curl http://localhost:PORT from server
│ ├── UFW (Ubuntu/Debian): sudo ufw allow PORT/tcp
│ ├── firewalld (CentOS/RHEL): sudo firewall-cmd --add-port=PORT/tcp --permanent
│ └── AWS/GCP/Azure → Must open in CLOUD CONSOLE (see below)
└── NO (IP changes, behind NAT, cloud shell, no console access)
└── Use a tunnel (see Tunneling section)localhostufw30000.0.0.0/0curl ifconfig.me
# If IP keeps changing → you're behind a NAT → use tunneling# Install
sudo npm install -g ngrok
# OR: snap install ngrok
# Authenticate (one-time, token from ngrok dashboard)
ngrok config add-authtoken YOUR_TOKEN_HERE
# Start tunnel
ngrok http 3000Forwardinghttps://abc123.ngrok-free.appImportant: Free tier generates a new URL every restart. Useor keep the terminal alive. On first visit, ngrok shows a warning page — click "Visit Site" to proceed.pm2
ssh -R 80:localhost:3000 nokey@localhost.runhttps://xxx.localhost.runssh -p 443 -R0:localhost:3000 a.pinggy.ioreferences/cloudflare-tunnel.md| Error | Cause | Fix |
|---|---|---|
| App not running on that port | Check |
| Browser cache from old app | Open in Incognito, clear cache |
| URL expired | Free tunnel timeout | Restart tunnel, use ngrok with account |
| Connection refused | App crashed | Check logs: |
pm2 logs my-app # Live tail (last 15 lines)
pm2 logs my-app --lines 100 # Last 100 lines
pm2 logs my-app --err # Only errors
~/.pm2/logs/my-app-out.log # stdout log file
~/.pm2/logs/my-app-error.log # stderr log filejournalctl -u my-service -f # systemd service logs
journalctl -n 50 # last 50 system log lines
tail -f /var/log/nginx/access.log # nginx access logs (if proxying)pm2 list # PM2-managed apps
curl http://localhost:3000 # Does the app respond locally?
ss -tlnp | grep 3000 # Is something listening on port 3000?
ps aux | grep node # Find running Node processescd project-folder
git pull
npm install # if dependencies changed
npm run build # if build step needed
pm2 restart my-appgit pushreferences/github-actions-deploy.md# Stop app (keep VPS running)
pm2 stop my-app
# Remove app from PM2 permanently
pm2 delete my-app
pm2 save
# Shut down entire server
sudo shutdown now
# OR
sudo poweroffAWS/GCP note: After, you must restart from the cloud console (EC2 → Start Instance).shutdown now
ss -tlnp | grep 3000 # Find what's using port 3000
kill -9 $(lsof -t -i:3000) # Kill it0.0.0.0127.0.0.1--hostname 0.0.0.0iptablesfirewall-cmd# Node.js — increase memory limit
NODE_OPTIONS="--max-old-space-size=2048" npm run buildsudosudo