99 lines
4.6 KiB
Markdown
99 lines
4.6 KiB
Markdown
# Arvan VPS — Deploy Guide
|
|
|
|
Battle-tested steps for deploying to the Arvan cloud server. Written after a
|
|
deploy where we hit every trap below — follow this and they won't bite again.
|
|
|
|
## Server facts
|
|
|
|
| Thing | Value |
|
|
|---|---|
|
|
| SSH host (inbound) | `94.101.187.12` |
|
|
| **Egress IP** (outbound — for API whitelists, e.g. Asian Metal) | **`31.171.101.234`** ⚠️ different from SSH IP |
|
|
| SSH user | `root` **only** (key auth) — `ubuntu` does NOT work |
|
|
| SSH key | `~/.ssh/yz_deploy_ed25519` (public key is in `root`'s `authorized_keys`) |
|
|
| Code on server | `/root/statista` — **plain copied tree, NOT a git repo** |
|
|
| Live config | `/root/statista/deploy/.env` (root-only, **untracked — never in git**) |
|
|
| Stack | `docker compose -f deploy/docker-compose.yml` → `nginx` + `frontend` (:3000) + `backend` (:8000) |
|
|
| Public URL | `http://94.101.187.12` (nginx on :80) |
|
|
|
|
## The deploy (copy-paste, run from your local repo)
|
|
|
|
```bash
|
|
KEY=~/.ssh/yz_deploy_ed25519
|
|
BR=deploy-vps-restructure # branch to deploy
|
|
|
|
# 1) ship the committed tree (NOT a git pull — server isn't a git repo).
|
|
# git archive only includes tracked files, so deploy/.env + data are untouched.
|
|
git archive --format=tar "$BR" | \
|
|
ssh -i "$KEY" root@94.101.187.12 'cd /root/statista && tar -xf -'
|
|
|
|
# 2) rebuild images + recreate containers
|
|
ssh -i "$KEY" root@94.101.187.12 \
|
|
'cd /root/statista && docker compose -f deploy/docker-compose.yml up -d --build'
|
|
|
|
# 3) ⚠️ ALWAYS restart nginx afterwards (see Trap #2)
|
|
ssh -i "$KEY" root@94.101.187.12 \
|
|
'cd /root/statista && docker compose -f deploy/docker-compose.yml restart nginx'
|
|
|
|
# 4) verify (all must be 200)
|
|
ssh -i "$KEY" root@94.101.187.12 \
|
|
'for p in / /manifest.webmanifest /sw.js /api/currency; do
|
|
echo "$p -> $(curl -s -o /dev/null -w "%{http_code}" http://localhost$p)"; done'
|
|
```
|
|
|
|
Commit + push first (`git push origin deploy-vps-restructure`) if you want the
|
|
GitHub copy current — but the archive deploys your **local** committed tree
|
|
regardless, so step 1 is the source of truth for the server.
|
|
|
|
## Traps we hit (and the fixes)
|
|
|
|
### Trap #1 — Server is NOT a git repo
|
|
`/root/statista` was copied (rsync/scp), not cloned. `git pull` fails with
|
|
"not a git repository". **Fix:** deploy with `git archive | ssh … tar -xf -`
|
|
(above). It overwrites only tracked files; untracked `deploy/.env`, the SQLite
|
|
DB, and `/data` reports are left alone.
|
|
|
|
### Trap #2 — nginx 502 after rebuild (stale upstream IP)
|
|
`up -d --build` recreates `frontend`/`backend` with **new Docker IPs**, but
|
|
nginx keeps running and caches the **old** IPs → every route returns **502**
|
|
even though the containers are healthy and listening. **Fix:** always
|
|
`docker compose restart nginx` as the last step. (Confirmed: frontend logs show
|
|
`Listening on :3000` while nginx still 502s — that's this, not an app bug.)
|
|
|
|
### Trap #3 — SSH access
|
|
- Only **`root` + key** works. `ubuntu` is rejected.
|
|
- **Password login is unreliable via Arvan's web console** — the noVNC keyboard
|
|
layout mistypes mixed-case/symbol passwords, so a *correct* password reads as
|
|
"wrong". Always SSH **from a real terminal**, not the web console. If you must
|
|
reset the password (panel) use **all-lowercase + digits** and **reboot** after
|
|
(resets often don't apply until restart).
|
|
- To grant a new machine access: append its public key to
|
|
`/root/.ssh/authorized_keys` (don't rebuild the server to inject keys).
|
|
|
|
### Trap #4 — never "Rebuild / reinstall OS"
|
|
Rebuild/reinstall **wipes the disk** (DB + reports gone) and can **change the
|
|
IP** (breaks API whitelists). Updates go through the deploy steps above —
|
|
**only ever `reboot`**, never rebuild. Reboots keep IP + data.
|
|
|
|
### Trap #5 — egress ≠ inbound IP
|
|
APIs that whitelist by IP (Asian Metal: "1 API = 1 IP") see the **egress IP
|
|
`31.171.101.234`**, not the SSH IP. Verify any time with:
|
|
`ssh -i $KEY root@94.101.187.12 'curl -s https://api.ipify.org'`
|
|
|
|
## Rollback
|
|
`up -d --build` keeps the previous images. If a deploy is bad:
|
|
```bash
|
|
ssh -i $KEY root@94.101.187.12 \
|
|
'cd /root/statista && docker compose -f deploy/docker-compose.yml down && \
|
|
docker compose -f deploy/docker-compose.yml up -d && \
|
|
docker compose -f deploy/docker-compose.yml restart nginx'
|
|
```
|
|
For a code rollback, `git archive` an earlier commit/tag in step 1, then rebuild.
|
|
|
|
## Health check anytime
|
|
```bash
|
|
ssh -i $KEY root@94.101.187.12 'docker compose -f /root/statista/deploy/docker-compose.yml ps'
|
|
ssh -i $KEY root@94.101.187.12 'docker logs deploy-frontend-1 --tail 20'
|
|
ssh -i $KEY root@94.101.187.12 'docker logs deploy-backend-1 --tail 20'
|
|
```
|