# Deploy to DigitalOcean (4 GB droplet)

Single path to run **Boundary Commission** on a DigitalOcean Ubuntu droplet: **4 GB Memory / 2 vCPUs / 120 GB Disk** (e.g. `ubuntu-s-2vcpu-4gb-120gb-intel-fra1-01`).

Stack: **Next.js (standalone)** on port 3000, **FastAPI (Gunicorn)** on 8001, **nginx** on 80 proxying `/` → Next.js and `/api/` → FastAPI. MySQL for auth and landing content.

---

## 1. Droplet and SSH

- Create an Ubuntu 22.04 (or 24.04) droplet, 4 GB RAM / 2 vCPUs.
- SSH as root: `ssh root@YOUR_DROPLET_IP`.

---

## 2. One-time server setup

```bash
# System
apt-get update && apt-get upgrade -y

# Node.js 20 (required for Next.js 16)
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs

# Or use the project script:
# bash /var/www/boundary-fastapiandnextjs/scripts/install_node20_ubuntu.sh

# Python 3, nginx, MySQL client, git
apt-get install -y python3 python3-venv python3-pip nginx mysql-client git
```

---

## 3. App directory and repo

```bash
mkdir -p /var/www
cd /var/www
git clone https://github.com/YOUR_ORG/boundary-fastapiandnextjs.git
cd boundary-fastapiandnextjs
```

(Replace with your repo URL; or upload the code via scp/rsync.)

---

## 4. Python backend (FastAPI)

```bash
cd /var/www/boundary-fastapiandnextjs
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
./venv/bin/pip install gunicorn "uvicorn[standard]"
```

Copy env and set secrets and DB:

```bash
cp .env.example .env
# Edit .env: AUTH_SECRET_KEY, MySQL (DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME)
nano .env
```

Create MySQL database and user, then run landing migration:

```bash
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS your_db; CREATE USER IF NOT EXISTS 'your_user'@'localhost' IDENTIFIED BY 'your_password'; GRANT ALL ON your_db.* TO 'your_user'@'localhost'; FLUSH PRIVILEGES;"
mysql -u your_user -p your_db < scripts/sql/landing_content_tables.sql
```

Install and start FastAPI (Gunicorn uses `aumentum_api:app`):

```bash
sudo cp scripts/fastapi.service /etc/systemd/system/fastapi.service
sudo systemctl daemon-reload
sudo systemctl enable fastapi
sudo systemctl start fastapi
sudo systemctl status fastapi
# Landing check: curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8001/landing  → 200
```

---

## 5. Next.js frontend (standalone)

**Recommended (build on your machine, 4GB droplet stays light):**

On your **local** machine (from repo root):

```bash
bash scripts/build_nextjs_artifact.sh
scp nextjs-standalone.tar.gz root@YOUR_DROPLET_IP:/var/www/boundary-fastapiandnextjs/
```

On the **server**:

```bash
cd /var/www/boundary-fastapiandnextjs
sudo bash scripts/unpack_and_start_nextjs.sh
```

This unpacks the standalone into `plagis-nextjs/.next/standalone`, installs `nextjs.service` (runs `node server.js`), and restarts the nextjs service.

**Optional – build on server** (uses more RAM; add swap if needed):

```bash
cd /var/www/boundary-fastapiandnextjs/plagis-nextjs
npm ci
# Optional: increase Node heap if OOM
# export NODE_OPTIONS="--max-old-space-size=3072"
npm run build
cd /var/www/boundary-fastapiandnextjs
sudo bash scripts/deploy_nextjs_production.sh
```

---

## 6. Nginx

```bash
cd /var/www/boundary-fastapiandnextjs
sudo bash scripts/deploy_nginx_504_fix.sh
```

This copies `nginx/aumentum.conf` to `/etc/nginx/sites-available/boundary`, enables it, disables default, and reloads nginx. The config proxies `/` → 127.0.0.1:3000 and `/api/` → 127.0.0.1:8001 (rewriting `/api/...` to `...`).

To use your droplet IP or domain, edit the config and set `server_name` (e.g. `server_name 209.38.212.129 your_domain.com;`). Use `127.0.0.1` (not `localhost`) in `proxy_pass` for reliability: `proxy_pass http://127.0.0.1:3000;` and `proxy_pass http://127.0.0.1:8001;`.

---

## 7. Verify

```bash
sudo bash scripts/check_502_upstreams.sh
bash scripts/test_landing.sh
```

In the browser: `http://YOUR_DROPLET_IP/` (landing) and `http://YOUR_DROPLET_IP/login`.

---

## 8. Service summary

| Service   | Unit file              | Port | Purpose                    |
|----------|------------------------|------|----------------------------|
| nextjs   | `scripts/nextjs.service` | 3000 | Next.js standalone server  |
| fastapi  | `scripts/fastapi.service` | 8001 | FastAPI (Gunicorn)         |
| nginx    | system nginx           | 80   | Reverse proxy              |

- **Next.js:** must run **standalone** (`node server.js` from `plagis-nextjs/.next/standalone`). Do not use `npm start` / `next start` on this build.
- **FastAPI:** must use **`aumentum_api:app`** in the unit (not `main:app`).

---

## 9. Troubleshooting

- **nextjs exits with status=203/EXEC**  
  systemd could not run the start command. Two common causes:  
  1. **Node not found** – You use **nvm** so node is at e.g. `/root/.nvm/versions/node/v20.20.0/bin/node`, not `/usr/bin/node`. Run **`sudo bash scripts/install_nextjs_service.sh`** once: it detects node (including nvm) and writes the correct `ExecStart` into the unit. Then `sudo systemctl start nextjs`.  
  2. **Standalone missing** – The service runs from `plagis-nextjs/.next/standalone`. That directory must exist and contain `server.js`. Build locally with `scripts/build_nextjs_artifact.sh`, upload `nextjs-standalone.tar.gz`, then on the server run `sudo bash scripts/unpack_and_start_nextjs.sh` (that script now runs `install_nextjs_service.sh` so the node path stays correct). Check with: `ls -la /var/www/boundary-fastapiandnextjs/plagis-nextjs/.next/standalone/server.js`.

- **502 on /**  
  Next.js not running. Fix 203/EXEC as above if present; otherwise ensure the standalone is deployed and the unit uses `node server.js` from `.../plagis-nextjs/.next/standalone`.

- **502 on /api/landing**  
  FastAPI down or wrong app. Start: `sudo systemctl start fastapi`. If logs show `No module named 'main'`, re-copy `scripts/fastapi.service` and `sudo systemctl daemon-reload && sudo systemctl restart fastapi`.

- **404 on /api/landing**  
  Nginx not proxying `/api/` to FastAPI. Use `scripts/deploy_nginx_504_fix.sh` or ensure a `location /api/` block proxies to `http://127.0.0.1:8001` with `rewrite ^/api/(.*) /$1 break;`.

- **Next.js repeatedly killed (OOM)**  
  Use standalone only; optionally set `MemoryMax=1536M` in `nextjs.service` to limit Node and avoid killing other processes.

- **Landing 404/500 from API**  
  Run landing migration: `mysql -u USER -p DB < scripts/sql/landing_content_tables.sql`.

- **404 for /_next/static/chunks/* (CSS/JS)**  
  The standalone server needs `.next/static` inside `plagis-nextjs/.next/standalone/.next/`. If you built on the server, run `sudo bash scripts/fix_nextjs_static.sh` (it copies `.next/static` into standalone and restarts nextjs). If you only ever unpacked a tarball, the tarball may have been built without that copy step: rebuild locally with `scripts/build_nextjs_artifact.sh` (which copies static into standalone), upload the new tarball, and run `unpack_and_start_nextjs.sh` again.

See also main [README](../README.md) “Production: 502 Bad Gateway or 404” and `scripts/check_502_upstreams.sh`.
