Worldshaper/docs/VPS_DEPLOYMENT.md
2026-06-26 18:18:14 -04:00

255 lines
5.9 KiB
Markdown

# VPS Deployment
This project is much easier to manage if we stop treating your desktop folder as the "deployment artifact" and instead treat the app like a normal repository with a normal deploy target.
## Recommended Setup
Use three directories on the VPS:
```txt
/srv/content-editor-v2/
repo.git/ # bare git repo, receives pushes
app/ # checked out working tree, built + run from here
shared/
content/ # persistent content, survives redeploys
```
Why this shape works:
- `repo.git` is the deployment remote.
- `app/` is the live checkout your process manager runs.
- `shared/content/` keeps your authored data outside the release tree.
That means redeploying code does not overwrite your content.
## Best Fit For This Project
This app is not just a static front-end build. It also has:
- `server.js` for the API
- `content/` for writable data
- `docs/` for wiki assets
- `dist/` for the built front-end
Because of that, the cleanest production model is:
1. Run `server.js` on the VPS from a stable app directory.
2. Let `server.js` serve `dist/` and `/wiki`.
3. Put Nginx or your hosting panel in front of it as a reverse proxy.
That is better than manually uploading a folder to a public web root.
## One-Time VPS Setup
Run these on the VPS.
### 1. Create directories
```bash
sudo mkdir -p /srv/content-editor-v2/repo.git
sudo mkdir -p /srv/content-editor-v2/app
sudo mkdir -p /srv/content-editor-v2/shared/content
```
### 2. Initialize the bare repo
```bash
cd /srv/content-editor-v2/repo.git
git init --bare
```
### 3. Create the live checkout
```bash
git --work-tree=/srv/content-editor-v2/app --git-dir=/srv/content-editor-v2/repo.git checkout -f
```
If this is the first time and there is no pushed branch yet, that checkout will not fully populate until the first push.
### 4. Keep content outside the app tree
This project already supports `CONTENT_ROOT`.
Production should use:
```bash
export CONTENT_ROOT=/srv/content-editor-v2/shared/content
```
If you already have good content locally, copy it once:
```bash
cp -R /srv/content-editor-v2/app/content/. /srv/content-editor-v2/shared/content/
```
### 5. Install Node dependencies in the live app dir
```bash
cd /srv/content-editor-v2/app
npm install
```
### 6. Add a process manager
PM2 is the easiest option:
```bash
npm install -g pm2
```
Then start the app:
```bash
cd /srv/content-editor-v2/app
CONTENT_ROOT=/srv/content-editor-v2/shared/content PORT=5180 pm2 start server.js --name content-editor-v2
pm2 save
```
## Automatic Deploy On Push
The cleanest version is a `post-receive` hook in the bare repo.
Create:
```txt
/srv/content-editor-v2/repo.git/hooks/post-receive
```
Use this:
```bash
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="/srv/content-editor-v2/app"
GIT_DIR="/srv/content-editor-v2/repo.git"
CONTENT_ROOT="/srv/content-editor-v2/shared/content"
PORT="5180"
echo "[deploy] checking out latest code"
git --work-tree="$APP_DIR" --git-dir="$GIT_DIR" checkout -f
cd "$APP_DIR"
echo "[deploy] installing dependencies"
npm install
echo "[deploy] validating content"
npm run validate:content
echo "[deploy] building"
npm run build
echo "[deploy] reloading app"
CONTENT_ROOT="$CONTENT_ROOT" PORT="$PORT" pm2 restart content-editor-v2 || \
CONTENT_ROOT="$CONTENT_ROOT" PORT="$PORT" pm2 start server.js --name content-editor-v2
```
Make it executable:
```bash
chmod +x /srv/content-editor-v2/repo.git/hooks/post-receive
```
## Local Machine Setup
On your home computer, initialize git in this project if you have not already:
```powershell
git init
git add .
git commit -m "Initial project import"
```
Add the VPS as a remote:
```powershell
git remote add vps ssh://YOUR_USER@YOUR_HOST:/srv/content-editor-v2/repo.git
```
Then deploy with:
```powershell
git push vps master
```
Or `main`, if that is your branch name.
## Windows-Friendly Deploy Helper
This repo includes a PowerShell helper:
```powershell
.\scripts\deploy-vps.ps1 -Remote vps -Branch master
```
What it does:
1. Runs `npm run validate:content`
2. Runs `npm run build`
3. Pushes your branch to the chosen remote
That means your local build fails before a bad deploy reaches the server.
## Reverse Proxy
If your VPS uses Nginx, proxy your public domain to the Node app:
```nginx
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:5180;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
## If You Really Need A Separate Hosted Directory
If your panel requires a specific public directory, there are two workable options:
### Option A: still run Node, proxy to it
Best option. Keep the app in `/srv/content-editor-v2/app` and point the panel or reverse proxy at the Node port.
### Option B: copy only `dist/` into a public web root
This works only if you separate the API and front-end hosting model. For this project today, that is not the clean default because `server.js` also serves static files and wiki docs.
## Recommended Workflow
Day to day:
1. Work locally in a normal git repo.
2. Commit changes.
3. Run `.\scripts\deploy-vps.ps1`.
4. Let the VPS hook pull, build, validate, and restart.
That replaces:
- random desktop folder
- manual upload
- dragging files through a VPS file manager
- wondering what version is actually live
## What I Recommend You Do Next
1. Initialize this folder as a git repo.
2. Set up the bare repo + app + shared content structure on the VPS.
3. Put the `post-receive` hook in place.
4. Start the app under PM2.
5. Switch deployment to `git push vps <branch>`.
Once you want, we can also add:
- a production `.env` loader
- branch-based staging vs production deploys
- backup/restore scripts for `content/`
- a one-command VPS bootstrap script