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 -yInstall dependencies
Install essential tools:
sudo apt install -y build-essential curl software-properties-common gitInstall Node.js
Use the NodeSource setup script:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejsInstall pnpm globally:
corepack enable
corepack prepare pnpm@latest --activateInstall PostgreSQL
sudo apt install -y postgresql postgresql-contrib
sudo -u postgres psqlIn the PostgreSQL shell, set up a user:
CREATE USER postgres WITH PASSWORD 'secure_password';
ALTER USER postgres WITH SUPERUSER;
\qInstall PM2
sudo npm install -g pm2DNS 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/achromatic
cd /var/www/achromaticInstall dependencies and build
Use pnpm for faster and disk-efficient installs:
pnpm install
pnpm buildStart applications with PM2
Set up the Marketing and Dashboard services:
pm2 start npm --name "marketing" --prefix ./marketing -- run start
pm2 start npm --name "dashboard" --prefix ./dashboard -- run start
pm2 saveEnsure PM2 restarts your apps on reboot:
pm2 startupSSL with Certbot
Install Certbot and generate SSL certificates:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com -d dashboard.yourdomain.comConfigure auto-renewal:
sudo systemctl enable certbot.timerNginx configuration
Marketing application
Create a configuration for Marketing:
sudo nano /etc/nginx/sites-available/marketingserver {
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 nginxDashboard application
Create a configuration for Dashboard:
sudo nano /etc/nginx/sites-available/dashboardserver {
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 nginxCI/CD pipeline
GitHub Actions workflow
Create .github/workflows/deploy.yml in your repository:
name: Deploy Achromatic
on:
push:
branches: - main
jobs:
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 allSetting 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 list
pm2 logsFurther 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.