-
Notifications
You must be signed in to change notification settings - Fork 0
App Server Setup
The rs-app.richardkentgates.com server hosts the PWA web app, versioned app snapshots, Linux desktop packages (.deb), and the deploy webhook used by GitHub Actions CI. This page documents how to rebuild it from scratch on a fresh VPS.
This page is for disaster recovery. You should not need it under normal circumstances — the server stays up and CI handles all updates.
| URL path | What it serves |
|---|---|
/ |
PWA web app (current version) — app.js, app.css, index.html, etc. |
/1.x.y/ |
Versioned app snapshots — older plugin versions load their matching app here |
/desktop/ |
Linux .deb packages (amd64 + arm64) and Tauri update.json manifest |
/_deploy/ |
PHP webhook called by CI on every release tag to trigger a web app update |
The deployment flow on every version tag:
- GitHub Actions builds the plugin ZIP and two
.debpackages (amd64, arm64). - The
build-desktopCI job pushes the.debfiles directly to the server via SSH (scp) and writesdesktop/update.json. - The
buildCI job commits versioned app snapshots todocs/app/<version>/on themainbranch. - The
ping-deployCI job callsPOST /_deploy/with a secret token. The PHP webhook verifies the token and fires/usr/local/bin/rsa-app-updateasynchronously. - The update script sparse-clones
docs/app/from the latest GitHub release tag and rsyncs it to/var/www/rs-app/.
| Property | Value |
|---|---|
| Provider | Google Cloud Platform (Compute Engine) |
| Machine type | e2-micro (or equivalent — 1 vCPU, 1 GB RAM) |
| OS | Debian 12 (bookworm) |
| IP | 104.197.231.120 |
| OS user | richardkentgates |
| Web root | /var/www/rs-app/ |
| Web server | Apache 2.4 + PHP 8.2 (mod_php) |
| TLS | Let's Encrypt (certbot, auto-renews) |
These must be set at Repository → Settings → Secrets and variables → Actions before CI can deploy to the server.
| Secret name | What it is | Where it comes from |
|---|---|---|
APP_SERVER_SSH_KEY |
ED25519 private key for SSH access to richardkentgates@<server>
|
Printed by the setup script |
DEPLOY_WEBHOOK_TOKEN |
32-byte hex token verified by the /_deploy/ webhook |
Contents of /etc/rsa-webhook-token on the server — printed by the setup script |
TAURI_SIGNING_PRIVATE_KEY |
Tauri code-signing key for .deb update signatures |
Existing secret — carry over from the old repo/server |
Follow these steps in order to bring a replacement server online.
Create a new Debian 12 instance on Google Cloud (or any provider). Minimum spec: 1 vCPU, 1 GB RAM, 10 GB disk. Note the external IP address.
On Google Cloud: **Compute Engine → VM instances → Create instance**.
Machine type `e2-micro` qualifies for the free tier in `us-central1`.
Choose **Debian 12** as the boot disk. Allow HTTP and HTTPS traffic in the firewall settings.
The setup script will create the richardkentgates user if it doesn't exist, but you need to SSH in first. On Google Cloud the default SSH user depends on your Google account; run as root or via sudo:
# On the new server — create the user if it doesn't exist yet
sudo adduser --disabled-password --gecos "" richardkentgates
sudo usermod -aG sudo richardkentgates
Update the A record for rs-app.richardkentgates.com to the new server's IP address. Let's Encrypt will fail if DNS does not resolve correctly.
Verify propagation before continuing:
dig +short rs-app.richardkentgates.com
# should return the new server IP
SSH into the new server as root (or a sudo-capable user), then:
git clone https://github.com/richardkentgates/rich-statistics.git
cd rich-statistics
sudo bash bin/setup-app-server.sh --email you@example.com
The script accepts the following options:
| Option | Default | Description |
|---|---|---|
--domain |
rs-app.richardkentgates.com |
FQDN to configure Apache and certbot for |
--email |
required for SSL | Let's Encrypt registration address |
--user |
richardkentgates |
OS user who owns /var/www/rs-app
|
--skip-ssl |
off | Skip certbot — use this if DNS isn't ready yet; run sudo certbot --apache -d <domain> later |
--skip-deploy |
off | Skip the initial rsa-app-update run |
The script will:
- Install Apache 2.4, PHP 8.2, certbot, git, rsync, fail2ban, ufw
- Enable Apache modules:
rewrite,headers,ssl,php8.2 - Create
/var/www/rs-app/with the correct ownership and subdirectory structure - Deploy the webhook handler to
/var/www/rs-app/_deploy/index.php - Generate a random 32-byte deploy token and store it at
/etc/rsa-webhook-token - Install the update script to
/usr/local/bin/rsa-app-update - Configure sudoers so
www-datacan run the update script - Write the Apache virtual-host config and obtain a Let's Encrypt certificate
- Generate a fresh ED25519 SSH keypair for CI and add the public key to
~/.ssh/authorized_keys - Run an initial deploy to pull the current app files from GitHub
- Print the
DEPLOY_WEBHOOK_TOKENandAPP_SERVER_SSH_KEYvalues for GitHub
At the end of the setup script, two secret values are printed to stdout. Copy them into GitHub:
Repository → Settings → Secrets and variables → Actions
-
Update (or create)
APP_SERVER_SSH_KEYwith the new ED25519 private key. -
Update (or create)
DEPLOY_WEBHOOK_TOKENwith the token string.The old server's token and SSH key will no longer work once you update these secrets. Make sure the new server is fully up and serving traffic before cutting over.
# App is reachable over HTTPS
curl -I https://rs-app.richardkentgates.com/
# .deb files are accessible
curl -I https://rs-app.richardkentgates.com/desktop/rich-statistics-linux-amd64.deb
# Tauri update manifest is valid JSON
curl -s https://rs-app.richardkentgates.com/desktop/update.json | python3 -m json.tool
# Webhook returns 405 on GET (method not allowed — correct)
curl -I https://rs-app.richardkentgates.com/_deploy/
If you want to push the current version's .deb files and run the full CI pipeline against the new server, re-push the latest tag:
git fetch --tags
LATEST=$(git describe --tags $(git rev-list --tags --max-count=1))
git tag -d "${LATEST}" && git push origin ":refs/tags/${LATEST}"
git tag "${LATEST}" && git push origin "${LATEST}"
Re-pushing a tag re-runs the full `build-release` workflow, which builds the plugin ZIP, both `.deb` packages, and creates a new GitHub Release. Only do this if you actually need fresh `.deb` files or want to test the new server end-to-end.
/var/www/rs-app/
├── .deployed-version # tag of the last successful deploy, e.g. "v1.4.2"
├── app.js # current PWA JavaScript
├── app.css # current PWA styles
├── index.html # PWA entry point
├── config.js # PWA configuration (site URL list is user-specific)
├── sw.js # service worker
├── manifest.json # PWA manifest
├── chart.min.js # bundled Chart.js 4.x
├── versions.json # ordered list of all deployed version tags
├── icons/ # PWA icon set
├── 1.3.0/ # versioned snapshot (immutable, 1-year cache)
├── 1.4.0/ # …
├── 1.4.1/
├── 1.4.2/
├── desktop/
│ ├── rich-statistics-linux-amd64.deb
│ ├── rich-statistics-linux-amd64.deb.sig
│ ├── rich-statistics-linux-arm64.deb
│ ├── rich-statistics-linux-arm64.deb.sig
│ └── update.json # Tauri auto-update manifest
└── _deploy/
└── index.php # deploy webhook (from bin/server-webhook.php)
/etc/rsa-webhook-token # shared secret (root:www-data, mode 640)
/etc/sudoers.d/rsa-app-update
/usr/local/bin/rsa-app-update # deploy script (from bin/server-update-webapp.sh)
/etc/letsencrypt/ # certbot managed — do not touch manually
/etc/apache2/sites-available/rs-app.conf
/etc/apache2/sites-available/rs-app-le-ssl.conf # written by certbot
/var/log/apache2/rs-app-*.log
/var/log/rsa-deploy.log # output of rsa-app-update runs
The X-Deploy-Token header doesn't match /etc/rsa-webhook-token. Check that the DEPLOY_WEBHOOK_TOKEN GitHub secret matches the file exactly (no trailing newline).
cat /etc/rsa-webhook-token # value on the server (no newline after hex string)
The update script runs asynchronously — check the deploy log:
tail -50 /var/log/rsa-deploy.log
Common causes:
-
sudopermission missing — verify/etc/sudoers.d/rsa-app-updateexists and is440. -
gitorrsyncnot installed — runsudo apt-get install git rsync. - GitHub API rate limit — check
curl -sf https://api.github.com/repos/richardkentgates/rich-statistics/tags.
Certbot installs a systemd timer that auto-renews. Check it:
sudo systemctl status certbot.timer
sudo certbot renew --dry-run
The build-desktop CI job uploads .deb files directly via SSH (not via the webhook). If the job failed, the files won't be on the server. Check the GitHub Actions run for the tag and re-run the build-desktop job if needed.
Re-run the update script at any time as the server user:
sudo -u richardkentgates /usr/local/bin/rsa-app-update
These files in the repository are the authoritative source for the server-side components. The setup script installs them to the right places — do not edit them directly on the server.
| Repo path | Installed to | Purpose |
|---|---|---|
bin/setup-app-server.sh |
run once on new server | Full server provisioning script |
bin/server-webhook.php |
/var/www/rs-app/_deploy/index.php |
Deploy webhook handler |
bin/server-update-webapp.sh |
/usr/local/bin/rsa-app-update |
Web app update script (called by webhook) |
- Home
- Release Tracks — Branch structure, promotion flows
- CI/CD Reference — Workflows, Freemius, deployment
- App Server Setup — Server infrastructure
- Code Map — Project structure