General
Deployment

Virtual Private Server (VPS)

Learn how to deploy a VPS.

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

Terminal
sudo apt update && sudo apt upgrade -y

Install dependencies

Install essential tools:

Terminal
sudo apt install -y build-essential curl software-properties-common git

Install Node.js

Use the NodeSource setup script:

Terminal
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -sudo apt install -y nodejs

Install pnpm globally:

Terminal
corepack enablecorepack prepare pnpm@latest --activate

Install PostgreSQL

Terminal
sudo apt install -y postgresql postgresql-contribsudo -u postgres psql

In the PostgreSQL shell, set up a user:

Terminal
CREATE USER postgres WITH PASSWORD 'secure_password';ALTER USER postgres WITH SUPERUSER;\q

Install PM2

Terminal
sudo npm install -g pm2

DNS configuration

Add DNS records

Configure the following DNS records:

TypeNameValue
A@VPS_IP_ADDRESS
AdashboardVPS_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:

Terminal
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:

Terminal
pnpm installpnpm build

Start applications with PM2

Set up the Marketing and Dashboard services:

Terminal
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:

Terminal
pm2 startup

SSL with Certbot

Install Certbot and generate SSL certificates:

Terminal
sudo apt install certbot python3-certbot-nginx -ysudo certbot --nginx -d yourdomain.com -d dashboard.yourdomain.com

Configure auto-renewal:

Terminal
sudo systemctl enable certbot.timer

Nginx configuration

Marketing application

Create a configuration for Marketing:

Terminal
sudo nano /etc/nginx/sites-available/marketing
/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:

Terminal
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:

Terminal
sudo nano /etc/nginx/sites-available/dashboard
/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:

Terminal
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:

.github/workflows/deploy.yml
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 NameValue
SSH_HOSTVPS_IP_ADDRESS
SSH_USERNAMEYour SSH username
SSH_PRIVATE_KEYYour private SSH key

Monitoring

Check application status:

Terminal
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.