mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
added docs for self hosters
Run app in 4650 port Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
@@ -6,6 +6,9 @@
|
|||||||
**Stack:** Node.js · Express · Sequelize (PostgreSQL) · JWT · Google OAuth 2.0 · Nodemailer
|
**Stack:** Node.js · Express · Sequelize (PostgreSQL) · JWT · Google OAuth 2.0 · Nodemailer
|
||||||
**Deployment** DigitalOcean Droplet (3 Droplets for API + S3 and Postgres)
|
**Deployment** DigitalOcean Droplet (3 Droplets for API + S3 and Postgres)
|
||||||
|
|
||||||
|
## Self-hosting
|
||||||
|
See [SELF_HOSTING.md](./SELF_HOSTING.md) for the full Docker Compose setup guide.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
Branchings and Tags (Backups)
|
Branchings and Tags (Backups)
|
||||||
```
|
```
|
||||||
|
|||||||
+193
@@ -0,0 +1,193 @@
|
|||||||
|
# Self-Hosting `new_starr` (Docker Compose) — Step-by-Step
|
||||||
|
|
||||||
|
This stack bundles everything: PostgreSQL, Valkey (Redis), Garage (S3), the API, and the
|
||||||
|
frontend. Battle-tested end-to-end on a completely fresh Debian machine on 2026-08-29 —
|
||||||
|
every gotcha below actually happened once and is now fixed or documented.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. What you need
|
||||||
|
|
||||||
|
- A Linux machine (Debian/Ubuntu commands below — adapt the package manager for others)
|
||||||
|
- Docker Engine + Compose plugin
|
||||||
|
- Node.js 22 + pnpm (only needed once, to build the frontend bundle)
|
||||||
|
- Git access to this repo
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Install Docker
|
||||||
|
|
||||||
|
**Check your actual distro first** — Docker has separate repos for Debian and Ubuntu,
|
||||||
|
and mixing them up 404s:
|
||||||
|
```bash
|
||||||
|
cat /etc/os-release # check ID (debian/ubuntu) and VERSION_CODENAME
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y ca-certificates curl gnupg
|
||||||
|
sudo install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
|
sudo chmod a+r /etc/apt/keyrings/docker.gpg
|
||||||
|
|
||||||
|
echo \
|
||||||
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
|
||||||
|
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
|
||||||
|
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||||
|
```
|
||||||
|
(Swap `debian` → `ubuntu` in both URLs if you're actually on Ubuntu. If your codename is
|
||||||
|
brand-new and Docker's repo 404s, fall back to the previous stable codename — e.g. use
|
||||||
|
`bookworm` instead of `trixie`.)
|
||||||
|
|
||||||
|
Let your user run Docker without `sudo`:
|
||||||
|
```bash
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
newgrp docker
|
||||||
|
docker compose version # sanity check
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Clone & install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone git@github.com:rgrgogu/new_starr.git
|
||||||
|
cd new_starr
|
||||||
|
corepack enable && corepack prepare pnpm@11.3.0 --activate
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Configure environment — **three** files, not two
|
||||||
|
|
||||||
|
### `apps/api/.env`
|
||||||
|
```bash
|
||||||
|
cp apps/api/.env-production apps/api/.env
|
||||||
|
```
|
||||||
|
Fill in every `CHANGE_ME`. For a **local bundled stack** (as opposed to CockroachDB
|
||||||
|
Cloud / managed S3), these specific values matter:
|
||||||
|
```env
|
||||||
|
DB_HOST=postgres
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_SSL=false # bundled Postgres has no TLS
|
||||||
|
CACHE_DRIVER=redis
|
||||||
|
REDIS_URL=redis://valkey:6379
|
||||||
|
S3_ENDPOINT=http://garage:3900
|
||||||
|
GARAGE_RPC_SECRET=<openssl rand -hex 32>
|
||||||
|
```
|
||||||
|
Generate every secret independently:
|
||||||
|
```bash
|
||||||
|
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `apps/web/.env`
|
||||||
|
```bash
|
||||||
|
cd apps/web && cp .env.example .env
|
||||||
|
```
|
||||||
|
Fill in `VITE_API_URL`, `VITE_APP_URL`, etc., then `cd ../..`.
|
||||||
|
|
||||||
|
### Root `new_starr/.env` — easy to miss, causes silent failures
|
||||||
|
`docker-compose.yml`'s bundled `postgres` service reads `${DB_NAME}`, `${DB_USER}`,
|
||||||
|
`${DB_PASSWORD}` from a **root-level** `.env` — NOT from `apps/api/.env`. Create it
|
||||||
|
separately, with **exactly the same values** as the DB block you just put in
|
||||||
|
`apps/api/.env`:
|
||||||
|
```env
|
||||||
|
DB_NAME=starr
|
||||||
|
DB_USER=starr
|
||||||
|
DB_PASSWORD=<same password as apps/api/.env>
|
||||||
|
```
|
||||||
|
⚠️ Postgres only reads these once, at first-ever container start, and bakes them into
|
||||||
|
its data volume. If the two files ever drift apart afterward, you'll get
|
||||||
|
`password authentication failed` even though everything "looks" configured — fix by
|
||||||
|
making `apps/api/.env` match what's actually in the volume (the root `.env` value at
|
||||||
|
the time Postgres first started), not the other way around.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Build the frontend bundle *before* building images
|
||||||
|
|
||||||
|
`apps/web/Dockerfile` only copies a pre-built `dist/` — it does not run the build itself:
|
||||||
|
```bash
|
||||||
|
pnpm --filter web build
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Bring the stack up
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d --build
|
||||||
|
docker compose ps # all 5 services should show Up/healthy
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. One-time Garage (S3) cluster init
|
||||||
|
|
||||||
|
Garage's image ships only a static binary — no shell — so this can't be scripted as a
|
||||||
|
container entrypoint; it's a manual one-time step:
|
||||||
|
```bash
|
||||||
|
docker compose exec garage /garage node id
|
||||||
|
```
|
||||||
|
Copy the ID (the part **before** the `@host:port`), then:
|
||||||
|
```bash
|
||||||
|
docker compose exec garage /garage layout assign <NODE_ID> -z dc1 -c 100G
|
||||||
|
docker compose exec garage /garage layout apply --version 1
|
||||||
|
docker compose exec garage /garage bucket create <S3_BUCKET>
|
||||||
|
docker compose exec garage /garage key import <S3_ACCESS_KEY> <S3_SECRET_KEY> -n starr-app --yes
|
||||||
|
docker compose exec garage /garage bucket allow <S3_BUCKET> --read --write --owner --key <S3_ACCESS_KEY>
|
||||||
|
```
|
||||||
|
(`S3_BUCKET`/`S3_ACCESS_KEY`/`S3_SECRET_KEY` are whatever you set in `apps/api/.env`.)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Run database migrations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose exec backend sequelize-cli db:migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Verify
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
|
- Frontend: **http://localhost:4650**
|
||||||
|
- Backend: http://localhost:3024/api
|
||||||
|
|
||||||
|
If both respond, you're done.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting — real errors hit while writing this guide
|
||||||
|
|
||||||
|
| Symptom | Cause | Fix |
|
||||||
|
|---|---|---|
|
||||||
|
| `apt` 404: `.../linux/ubuntu <codename> Release` not found | Docker repo added for the wrong distro (e.g. Ubuntu URL on a Debian box) | Match the URL to your real distro/codename from `/etc/os-release` |
|
||||||
|
| `permission denied ... docker.sock` | User not in the `docker` group | `sudo usermod -aG docker $USER && newgrp docker` |
|
||||||
|
| `WARN: "DB_NAME" variable is not set` (and similar) | Root `new_starr/.env` missing | Create it (see step 3) |
|
||||||
|
| `postgres` container stuck `Restarting` | `POSTGRES_PASSWORD` blank (same root `.env` issue) | Same fix as above |
|
||||||
|
| `exec: "/bin/sh": stat /bin/sh: no such file or directory` | Some images (like Garage's) ship no shell at all — never wrap their entrypoint in `/bin/sh` | Use the image's default command; do cluster setup via `docker exec <container> <binary>` directly (no shell needed) |
|
||||||
|
| Garage crash-loops: `rpc_secret value is missing` | `GARAGE_RPC_SECRET` not set in `apps/api/.env` | Set it, then `docker compose up -d --force-recreate garage` |
|
||||||
|
| `password authentication failed for user ...` | `apps/api/.env` and root `.env` DB passwords don't match exactly | Make them match; Postgres only honors whatever was set at first boot |
|
||||||
|
| Fixed a file but the same error keeps happening | Images bake in code at **build** time — there's no live volume mount | `docker compose up -d --build <service>` after any source change |
|
||||||
|
| `ERROR: Unknown constraint error` during migrate | Sequelize hides the real Postgres error behind this generic message | Run the raw SQL directly via `docker compose exec postgres psql -U <user> -d <db>` to see the actual cause |
|
||||||
|
| Migration uses `STRING` as a raw SQL type | CockroachDB alias, not valid in real Postgres | Already fixed in this repo (swapped to `TEXT`, which works on both) |
|
||||||
|
| A service vanishes from `docker compose ps` | A previous `up` was scoped to one service (e.g. `up -d --build backend`), which doesn't touch others | Run a plain `docker compose up -d` (no service name) to restore everything |
|
||||||
|
| Browser: "Unable to connect" | Either the container isn't actually running, or you're browsing from a different machine than the one running Docker | Check `docker compose ps` first; `localhost` only resolves to the machine Docker is on |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Frontend is served on **`:4650`**, not `:80` — change `frontend.ports` in
|
||||||
|
`docker-compose.yml` if you want a different port.
|
||||||
|
- Cluster init for Garage is intentionally manual (step 6) — the old automated
|
||||||
|
`garage-init.sh` approach was removed because it depended on a shell that doesn't
|
||||||
|
exist in the Garage image.
|
||||||
+1
-1
@@ -50,7 +50,7 @@ services:
|
|||||||
frontend:
|
frontend:
|
||||||
build: ./apps/web
|
build: ./apps/web
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "4650:80"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
# ── PostgreSQL ───────────────────────────────────────────────────────────────
|
# ── PostgreSQL ───────────────────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user