Virtual Private Server (VPS)
Learn how to deploy a VPS.
This is a barebones tutorial without nixpacks or docker and an interesting read so you can roughly understand how your apps can be hosted using a reverse proxy, certbot, Postgres and pm2. However for production usage we recommend using Coolify since it also comes with CI/CD and DB->S3 backups.
A VPS offers the best performance among hosting options while keeping costs low. A clever hosting trick is to grab an inexpensive, overprovisioned server—like a Hetzner auction deal during Christmas week—and run both your apps and database on it, achieving near-instant 0ms network latency.
Prerequisites
- Linux-based VPS (Debian or Ubuntu recommended).
- DNS control for
yourdomain.com
. - SSH access to your VPS
Server preparation
Update the system
sudo apt update && sudo apt upgrade -y
Install dependencies
Install essential tools:
sudo apt install -y build-essential curl software-properties-common git
Install Node.js
Use the NodeSource setup script:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -sudo apt install -y nodejs
Install pnpm globally:
corepack enablecorepack prepare pnpm@latest --activate
Install PostgreSQL
sudo apt install -y postgresql postgresql-contribsudo -u postgres psql
In the PostgreSQL shell, set up a user:
CREATE USER postgres WITH PASSWORD 'secure_password';ALTER USER postgres WITH SUPERUSER;\q
Install PM2
sudo npm install -g pm2
DNS configuration
Add DNS records
Configure the following DNS records:
Type | Name | Value |
---|---|---|
A | @ | VPS_IP_ADDRESS |
A | dashboard | VPS_IP_ADDRESS |
Replace VPS_IP_ADDRESS
with your server's IP address.
Application Deployment
Clone the repository
Log in to your VPS and clone your project:
git clone https://github.com/your-repo/achromatic.git /var/www/achromaticcd /var/www/achromatic
Install dependencies and build
Use pnpm for faster and disk-efficient installs:
pnpm installpnpm build
Start applications with PM2
Set up the Marketing and Dashboard services:
pm2 start npm --name "marketing" --prefix ./marketing -- run startpm2 start npm --name "dashboard" --prefix ./dashboard -- run startpm2 save
Ensure PM2 restarts your apps on reboot:
pm2 startup
SSL with Certbot
Install Certbot and generate SSL certificates:
sudo apt install certbot python3-certbot-nginx -ysudo certbot --nginx -d yourdomain.com -d dashboard.yourdomain.com
Configure auto-renewal:
sudo systemctl enable certbot.timer
Nginx configuration
Marketing application
Create a configuration for Marketing:
sudo nano /etc/nginx/sites-available/marketing
server { listen 80; server_name yourdomain.com; return 301 https://$host$request_uri;}server { listen 443 ssl http2; server_name yourdomain.com; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; location / { proxy_pass http://localhost:3001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}
Enable the configuration:
sudo ln -s /etc/nginx/sites-available/marketing /etc/nginx/sites-enabled/sudo nginx -t && sudo systemctl reload nginx
Dashboard application
Create a configuration for Dashboard:
sudo nano /etc/nginx/sites-available/dashboard
server { listen 80; server_name dashboard.yourdomain.com; return 301 https://$host$request_uri;}server { listen 443 ssl http2; server_name dashboard.yourdomain.com; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; location / { proxy_pass http://localhost:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}
Enable the configuration:
sudo ln -s /etc/nginx/sites-available/dashboard /etc/nginx/sites-enabled/sudo nginx -t && sudo systemctl reload nginx
CI/CD pipeline
GitHub Actions workflow
Create .github/workflows/deploy.yml
in your repository:
name: Deploy Achromaticon: push: branches: - mainjobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 - name: Set up Node.js uses: actions/setup-node@v3 with: node-version: 20 cache: 'pnpm' - name: Install pnpm run: | corepack enable corepack prepare pnpm@latest --activate - name: Install Dependencies run: pnpm install - name: Build Applications run: pnpm build - name: Deploy to Server uses: appleboy/ssh-action@master with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USERNAME }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /var/www/achromatic git pull origin main pnpm install pnpm build pm2 restart all
Setting up secrets
Add the following secrets in your repository settings:
Secret Name | Value |
---|---|
SSH_HOST | VPS_IP_ADDRESS |
SSH_USERNAME | Your SSH username |
SSH_PRIVATE_KEY | Your private SSH key |
Monitoring
Check application status:
pm2 listpm2 logs
Further steps
Next you can harden your security by installing ufw
as your firewall, fail2ban
to prevent intrusions and a cron job to upload your db backups to s3
.