vps-launch
v2.0.0
Published
Auto-configure any Linux VPS with Caddy + HTTPS + UFW + systemd, or share locally via Docker tunnel with live request inspector. No ngrok, no middlemen.
Downloads
110
Maintainers
Readme
vps-launch
Auto-configure any Linux VPS (Ubuntu 22.04+) with Caddy + HTTPS + UFW + systemd via SSH key authentication. No tunnels, no monthly fees — real hosting.
Quick Start
npm install -g vps-launch
# Run prerequisite checks first
vps-launch doctor --host 1.2.3.4 --domain myapp.com
# Full VPS setup
vps-launch setup
# Deploy your app
vps-launch deploy --host 1.2.3.4
# Check everything is running
vps-launch status --host 1.2.3.4What It Does
- Installs Caddy — automatic HTTPS via Let's Encrypt, zero config
- Configures UFW — firewall locked to ports 22, 80, 443
- Creates a systemd service — your app auto-restarts on crash, no PM2
- Writes a Caddyfile — reverse proxy + security headers + gzip + access logs
- Backs up before every deploy — one-command rollback if anything breaks
Commands
| Command | Description |
|---|---|
| vps-launch setup | Full VPS configuration (Caddy, UFW, systemd) |
| vps-launch deploy | Push code, backup old version, restart service |
| vps-launch status | Check all services and view recent logs |
| vps-launch rollback | Restore a previous deployment from backup |
| vps-launch logs | Stream Caddy access logs in real time |
| vps-launch doctor | Pre-flight checks (SSH key, DNS, connectivity) |
| vps-launch repair | Re-run only failed setup steps |
| vps-launch config | View saved (and optionally encrypted) config |
Global Flags
| Flag | Description | Default |
|---|---|---|
| --host <ip> | VPS IP address | saved config |
| -u, --user <username> | SSH username | ubuntu |
| -i, --identity <path> | SSH private key path | ~/.ssh/id_rsa |
| -d, --domain <domain> | Your domain name | saved config |
| -p, --port <port> | App port to proxy | 3000 |
| --provider <name> | VPS provider (oracle\|hetzner\|digitalocean\|generic) | generic |
vps-launch logs Flags
| Flag | Description |
|---|---|
| -w, --watch | Stream logs continuously (tail -f) |
| -f, --filter <pattern> | Filter by URL path segment or HTTP status code |
# Watch live traffic
vps-launch logs --watch --host 1.2.3.4
# Filter for errors only
vps-launch logs --watch --filter 500
# Filter by path
vps-launch logs --watch --filter /api/usersVPS Provider Support
vps-launch works with any Ubuntu 22.04+ VPS. The --provider flag prints a one-time setup tip specific to your hosting provider:
| Provider | Tip |
|---|---|
| oracle | Ensure VCN security list allows ports 22, 80, 443 |
| hetzner | Enable IPv4 if you created an IPv6-only instance |
| digitalocean | Add firewall rules for 80/443 in the Networking panel |
| generic | Check your provider's firewall allows ports 22, 80, 443 |
vps-launch setup --provider hetznerDeployment Backups & Rollback
Every vps-launch deploy automatically:
- Archives the current app to
~/vps-launch-backups/<timestamp>/ - Keeps only the last 2 backups, deletes older ones
- Deploys your new code and restarts the service
If something breaks:
vps-launch rollback --host 1.2.3.4This lists available backups, lets you pick one, restores it, and restarts the systemd service.
Setup Failure Recovery
If setup fails midway (e.g., Caddy installs but UFW config fails), vps-launch tracks exactly which steps succeeded and which failed.
# See what failed
vps-launch repair --host 1.2.3.4The repair command:
- Shows completed steps (✓) and failed steps (✗)
- Re-runs only the failed/missing steps
- Skips everything that already succeeded
Step state is stored in ~/.vps-launch-state.json keyed by VPS IP.
Prerequisite Checks (doctor)
Run before setup to catch issues early:
vps-launch doctor --host 1.2.3.4 --domain myapp.com| Check | What it verifies | |---|---| | SSH Key | File exists, permissions are 600 (Unix) | | VPS SSH | TCP ping on port 22 is reachable | | DNS Resolution | Domain A record points to the VPS IP | | Node.js Version | >= 18 | | Local Ports | 80/443 are not already bound locally |
Configurable Security Headers
By default, vps-launch generates a Caddyfile with secure headers. You can customize them by creating a vps-launch.config.js in your project root:
{
"customHeaders": {
"X-Custom-Header": "my-value",
"Permissions-Policy": "camera=(), microphone=()"
},
"disableHeaders": ["X-XSS-Protection"],
"contentSecurityPolicy": "default-src 'self'; script-src 'self' 'unsafe-inline'",
"allowIframes": false
}Config Options
| Key | Type | Description |
|---|---|---|
| customHeaders | Record<string, string> | Additional headers to add (overrides defaults if same name) |
| disableHeaders | string[] | Header names to remove from defaults |
| contentSecurityPolicy | string | Override the default CSP value |
| allowIframes | boolean | If true, removes X-Frame-Options header |
Default Headers
| Header | Value |
|---|---|
| X-Frame-Options | DENY |
| X-Content-Type-Options | nosniff |
| Strict-Transport-Security | max-age=31536000; includeSubDomains |
| Referrer-Policy | strict-origin-when-cross-origin |
| X-XSS-Protection | 1; mode=block |
| Content-Security-Policy | default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' |
Encrypted Configuration
Config is saved to ~/.vps-launch.json. By default it's plaintext (with a warning).
To enable AES-256-GCM encryption:
export VPS_LAUNCH_SECRET="your-strong-passphrase"The encryption key is derived from your machine's hostname + this passphrase via PBKDF2 (100,000 iterations, SHA-512).
# View your config (auto-decrypts if secret is set)
vps-launch config --showWindows Support
vps-launch works on Windows natively. All file paths use path.normalize() and os.homedir() — no hardcoded Unix paths. Remote commands are wrapped in bash -c for consistent behavior.
For the best experience, we recommend running inside WSL2: https://learn.microsoft.com/en-us/windows/wsl/install
Programmatic API
Use vps-launch inside your own Node.js scripts:
import { setup, deploy, status, rollback, doctor, repair } from 'vps-launch';
// Setup a VPS
const setupResult = await setup({
host: '1.2.3.4',
user: 'ubuntu',
identity: '~/.ssh/id_rsa',
domain: 'myapp.com',
port: 3000,
appName: 'myapp',
appDir: '/home/ubuntu/app',
startCommand: 'node index.js',
silent: true,
});
// => { success: true, steps: [...], url: 'https://myapp.com' }
// Deploy
const deployResult = await deploy({
host: '1.2.3.4',
user: 'ubuntu',
identity: '~/.ssh/id_rsa',
source: './dist',
appDir: '/home/ubuntu/app',
appName: 'myapp',
silent: true,
});
// => { success: true, backupPath: '~/vps-launch-backups/2024-01-15T...' }
// Check status
const statusResult = await status({
host: '1.2.3.4',
user: 'ubuntu',
identity: '~/.ssh/id_rsa',
appName: 'myapp',
silent: true,
});
// => { success: true, services: [{label: 'Caddy', status: 'active', healthy: true}, ...] }
// Rollback
const rollbackResult = await rollback({
host: '1.2.3.4',
user: 'ubuntu',
identity: '~/.ssh/id_rsa',
appDir: '/home/ubuntu/app',
appName: 'myapp',
silent: true,
});
// => { success: true, restoredFrom: '2024-01-15T...' }
// Pre-flight checks
const doctorResult = await doctor({
host: '1.2.3.4',
identity: '~/.ssh/id_rsa',
domain: 'myapp.com',
silent: true,
});
// => { allPassed: true, checks: [{name: 'SSH Key', passed: true, ...}, ...] }All functions return structured objects. Set silent: true to suppress terminal output.
When TO Use vps-launch
- Production apps — you have a domain, a VPS, and want real HTTPS hosting
- Side projects — $5/month VPS instead of $20/month managed hosting
- API servers — deploy a Node.js/Express/Fastify API with auto-restart
- Static sites with a backend — serve a React/Vue app behind Caddy
- Multiple apps on one VPS — run setup once, deploy different apps to different directories
When NOT to Use vps-launch
| Use Case | Better Tool | |---|---| | Webhook testing during local development | ngrok | | Quick 10-minute demo to a client | ngrok | | You don't have a domain name yet | ngrok | | Zero-trust internal networking | Cloudflare Tunnel | | Enterprise traffic routing with WAF | Cloudflare Tunnel |
Comparison Table
| Feature | vps-launch | ngrok | Cloudflare Tunnel | |---|---|---|---| | Cost | VPS cost only ($5–10/mo) | Free tier + $8/mo paid | Free tier available | | Custom domain HTTPS | ✅ Built-in (Let's Encrypt) | ✅ Paid plans only | ✅ Yes | | Persistent URL | ✅ Your domain, forever | ❌ Random URLs on free | ✅ Yes | | Setup time | ~5 min (one command) | ~1 min | ~10 min | | Requires a VPS | ✅ Yes | ❌ No | ❌ No | | Requires a domain | ✅ Yes | ❌ No | ✅ Yes | | Firewall config | ✅ Auto (UFW) | N/A | N/A | | SSL cert management | ✅ Auto (Caddy) | ✅ Auto | ✅ Auto | | Process management | ✅ systemd | ❌ Not included | ❌ Not included | | Rollback support | ✅ Built-in | ❌ No | ❌ No | | Access logs | ✅ Streaming | ✅ Dashboard | ✅ Dashboard | | Best for | Production hosting | Local dev / testing | Enterprise / zero-trust |
Requirements
- Node.js ≥ 18
- Ubuntu 22.04+ VPS (any provider)
- Domain with DNS A record pointing to your VPS IP
- SSH key authentication configured on the VPS
License
MIT #� �v�p�s�-�l�a�u�n�c�h� � �
