Auto Deploy Demo Script

1. What the Script Does

Step Purpose
 1. Prompts you for input Domain, sub‑domain, Git repo, branch/tag, internal port, Let’s Encrypt email, and any environment variables.
 2. Installs packages git, nginx, ufw, certbot, latest Node LTS, and the lightweight serve package for static hosting.
 3. Builds your Vite project npm ci && npm run build inside /opt/<sub>.<domain>
 4. Creates/updates a systemd service Runs serve -s dist -l <PORT> under user www‑data. If the service already exists, it restarts it so changes take effect.
 5. Configures Nginx Sets up a virtual host pointing https://<sub>.<domain> to 127.0.0.1:<PORT> with automatic HTTPS via Certbot.
 6. Enables the firewall Opens only SSH and HTTPS.
 7. Prints DNS instructions Shows the exact A record you need to add.

Re‑run the script any time you want to:

  • spin up another demo (pick a new sub‑domain + port)

  • redeploy an existing one (same sub‑domain + port, script will restart the service)


2. Prerequisites

  • Ubuntu 22.04 LTS or Debian 12 on your Hetzner VPS (script may work elsewhere but is tested here).

  • A domain you control, with the ability to create A/AAAA records.

  • An SSH key for root login.


3. Quick‑Start

# On your workstation
scp deploy_demo_app.sh root@<SERVER_IP>:/root
ssh root@<SERVER_IP>

# On the server
sudo bash /root/deploy_demo_app.sh

Then follow the interactive prompts.


4. Environment Variables

When the script says “Add an env var (key=value) or press [Enter] to stop” it is building an /etc/<sub>.env file that gets sourced by the systemd service.

4.1 Supabase Example

Copy‑paste these two lines (with your own values) when prompted:

# Supabase Configuration
VITE_SUPABASE_URL=https://<your-project-id>.supabase.co
VITE_SUPABASE_ANON_KEY=<your_anon_key_here>
  • VITE_ prefix is required by Vite so the vars are exposed to the browser bundle.

  • The env‑file is chmod 640 (readable by root and www-data only).

  • You can reopen the file later: sudo nano /etc/<sub>.env and restart: sudo systemctl restart <sub>.

Tip: Need other secrets (Stripe, Sentry, etc.)? Just add them in the same key=value format.


5. Managing a Demo Instance

Action Command
Check status sudo systemctl status <sub>
View realtime logs sudo journalctl -u <sub> -f
Restart after env‑file change sudo systemctl restart <sub>
Stop / start sudo systemctl stop <sub> / sudo systemctl start <sub>
Remove permanently sudo systemctl disable --now <sub>  then  sudo rm /etc/systemd/system/<sub>.service & sudo rm /etc/nginx/sites-enabled/<fqdn>.conf & sudo rm -r /opt/<fqdn>

6. Troubleshooting

Symptom Likely Cause Fix
502 Bad Gateway Nginx points to a port where no service is listening. sudo systemctl restart <sub> (if you redeployed with a new port) or update Nginx proxy_pass.
Port in use Another service already bound to that port. Choose a different port (or stop the conflicting service).
Certbot fails DNS not propagated yet or port 80 blocked. Verify A‑record, wait a minute, ensure port 80 is open (UFw allows Nginx Full).

7. Security Notes

  • Env‑files live in /etc with limited permissions; adjust as needed.

  • www-data non‑privileged user runs the apps.

  • UFw defaults to deny‑incoming except SSH & Nginx.


8. Updating the Script

The script is idempotent. Replace it with a newer version and rerun — existing demos will either restart (if same sub‑domain) or stay untouched (if different).

COPY PASTE THE FOLLOWING CODE INTO THE ROOT OF THE VPS. EXECUTE IT AND ENTER THE REQUIRED DATA WHEN PROMPTED.

#!/usr/bin/env bash
# -----------------------------------------------------------------------------
# Automated Demo-App Deployment Script for a Hetzner VPS
# -----------------------------------------------------------------------------
# Features
# • Deploy any Git-hosted Vite front‑end (perfect for demo builds)
# • Reverse‑proxy via Nginx with per‑sub‑domain TLS (Let’s Encrypt/Certbot)
# • Runs each demo as an isolated systemd service on its own port
# • Prompts you for Supabase (or any) env vars and stores them securely
# • Meant to be **re‑run** for every additional demo you need
# -----------------------------------------------------------------------------
# Usage
# 1. Copy to server → scp deploy_demo_app.sh root@<IP>:/root
# 2. SSH in & run → sudo bash /root/deploy_demo_app.sh
# 3. Follow prompts, then add the suggested DNS record.
# -----------------------------------------------------------------------------
# Tested on: Ubuntu 22.04 LTS, Debian 12 (bookworm) — requires systemd
# -----------------------------------------------------------------------------
set -euo pipefail

# ---------- helper functions ----------
color() { local c="$1"; shift; echo -e "\033[${c}m$*\033[0m"; }
ask() { read -rp "$1: " _ans && echo "${_ans}"; }
check_port() {
if ss -tln | awk '{print $4}' | grep -Eq ":$1$"; then
color 31 "Port $1 appears to be in use. Choose another." && exit 1
fi
}
root_check() {
if [[ $EUID -ne 0 ]]; then
color 31 "Please run as root (use sudo)." && exit 1
fi
}

root_check

# ---------- collect user input ----------
PRIMARY_DOMAIN=$(ask "Primary domain (e.g. example.com)")
SUBDOMAIN=$(ask "Sub‑domain for this demo (e.g. demo1)")
FQDN="${SUBDOMAIN}.${PRIMARY_DOMAIN}"
EMAIL=$(ask "Email for Let's Encrypt expiry notices")
REPO_URL=$(ask "Git repository URL")
BRANCH=$(ask "Git branch or tag (default: main)")
BRANCH=${BRANCH:-main}
PORT=$(ask "Internal port number for the app (e.g. 3001)")
check_port "${PORT}"

color 34 "\n---- Collect environment variables ----"
ENV_FILE="/etc/${SUBDOMAIN}.env"
>"${ENV_FILE}"
while true; do
read -rp "Add an env var (key=value) or press [Enter] to stop: " KV || true
[[ -z "${KV}" ]] && break
echo "${KV}" >>"${ENV_FILE}"
done
chmod 640 "${ENV_FILE}"

# ---------- base packages ----------
color 34 "\nInstalling required packages (git, nginx, node, certbot)..."
apt-get update -qq
apt-get install -y -qq git nginx ufw python3-certbot-nginx curl gnupg ca-certificates > /dev/null

# Node.js (LTS) via NodeSource
if ! command -v node >/dev/null; then
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - &>/dev/null
apt-get install -y -qq nodejs > /dev/null
fi
npm install -g serve &>/dev/null || true

# ---------- clone & build repo ----------
APP_DIR="/opt/${FQDN}"
color 34 "\nCloning ${REPO_URL} → ${APP_DIR}..."
rm -rf "${APP_DIR}"
git clone --quiet --depth 1 --branch "${BRANCH}" "${REPO_URL}" "${APP_DIR}"
cd "${APP_DIR}"

color 34 "Installing dependencies & building Vite project..."
npm ci --silent
npm run build --silent

# ---------- systemd service ----------
SERVICE_NAME="${SUBDOMAIN}"
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
cat >"${SERVICE_FILE}" <<SERVICE
[Unit]
Description=${FQDN} demo app
After=network.target

[Service]
Type=simple
EnvironmentFile=${ENV_FILE}
WorkingDirectory=${APP_DIR}
ExecStart=/usr/bin/serve -s dist -l ${PORT}
Restart=always
User=www-data
Group=www-data

[Install]
WantedBy=multi-user.target
SERVICE

# (Re)load the unit and ensure it runs with the new port
systemctl daemon-reload
if systemctl is-active --quiet "${SERVICE_NAME}"; then
systemctl restart "${SERVICE_NAME}"
color 32 "systemd service ${SERVICE_NAME} restarted (now on port ${PORT})."
else
systemctl enable --now "${SERVICE_NAME}"
color 32 "systemd service ${SERVICE_NAME} started (port ${PORT})."
fi

Намирате ли за полезно?

  • Palm Fitness information

    The project is currently deployed at demo.automationaid.eu. It is uploaded to Sava Barbarov's GitHub...
  • Forbidden Knowledge

    Supabase MCP The Supabase MCP, as demonstrated in the YouTube video, offers more than just basic fun...
  • n8n System Message template

    Guide to n8n AI Agents - System Messages   Writing Tips Be Direct & Unambiguous: Use clea...
  • n8n backend update

    Предварителни С&...
  • Supabase KB

    Welcome to our comprehensive knowledge base, designed to provide you with valuable insights, tips, a...