# Deployment Step-by-step for the backend (Docker + Traefik) and the Bromite userscript. Assumes you already run Traefik in Docker with a working HTTPS entrypoint and an ACME/cert resolver, and control a domain. --- ## 0. Prerequisites - Docker + Docker Compose on the server. - A Traefik instance watching a Docker network (default name assumed: `proxy`). - DNS: an `A`/`AAAA` record for `manga-api.` pointing at the server. - The repo copied to the server, e.g. `/opt/mangabm/` (needs `backend/`, `docker-compose.yml`, `docker-compose.prod.yml`, `.env.example`). Confirm the Traefik network exists (create if not): ```bash docker network ls | grep proxy || docker network create proxy ``` --- ## 1. Configure `.env` ```bash cd /opt/mangabm cp .env.example .env ``` Edit `.env`: ```ini # Required — long random secret, also goes in the userscript. API_TOKEN= # CORS allowlist — leave as-is unless a site changes hostname. ALLOWED_ORIGINS=https://asuracomic.net,https://asurascans.com,https://demonicscans.org # Required for the Traefik override. MANGA_API_HOST=manga-api.violetcrown.my.id # Only if your Traefik setup differs from these defaults: # PROXY_NETWORK=proxy # TRAEFIK_ENTRYPOINT=websecure # TRAEFIK_CERTRESOLVER=le ``` Generate + insert the token in one line: ```bash sed -i "s|^API_TOKEN=.*|API_TOKEN=$(openssl rand -hex 32)|" .env grep -E '^API_TOKEN=' .env # copy this — the userscript needs the same value ``` > Match `TRAEFIK_ENTRYPOINT` / `TRAEFIK_CERTRESOLVER` to your Traefik's actual > names (check your Traefik static config — common alternatives: `https`, > `myresolver`, `cloudflare`). Wrong names = no certificate issued. --- ## 1b. Web UI The browser UI is served by the same container on a second hostname. 1. Add a DNS `A`/`AAAA` record for `manga.` pointing at the server — the same address as `manga-api.`. 2. Set both variables in `.env`: ```ini MANGA_WEB_HOST=manga.violetcrown.my.id WEB_PASSWORD= ``` Generate and insert in one line: ```bash sed -i "s|^WEB_PASSWORD=.*|WEB_PASSWORD=$(openssl rand -base64 18)|" .env grep -E '^WEB_PASSWORD=' .env # this is what you type into the site ``` 3. Redeploy and check: ```bash docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build curl -s -o /dev/null -w '%{http_code}\n' https://manga.violetcrown.my.id/ ``` Expected `200`, serving the login page. Leaving `WEB_PASSWORD` unset is safe: the web routes are not registered and `/` returns 404. The userscript's API on `MANGA_API_HOST` is unaffected either way. Sessions are signed with a key derived from `API_TOKEN`, so rotating the token logs every browser out. The session cookie lasts 60 days. --- ## 2. Build + start ```bash docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build ``` This merges the base file (build/image/env/volume) with the prod override (no host port, Traefik network + router labels). Always pass **both** `-f` flags — the prod file is not standalone. Check it's up and healthy: ```bash docker compose -f docker-compose.yml -f docker-compose.prod.yml ps docker logs manga-api --tail 20 # expect: "listening on :8080 ..." ``` --- ## 3. Verify over HTTPS Give Traefik a few seconds to issue the cert, then: ```bash # Health (no auth) — must be valid TLS, no cert warning. curl -s https://manga-api.violetcrown.my.id/healthz # -> ok # Auth enforced. curl -s -o /dev/null -w '%{http_code}\n' \ https://manga-api.violetcrown.my.id/bookmarks # -> 401 TOKEN=$(grep -E '^API_TOKEN=' .env | cut -d= -f2) curl -s -H "Authorization: Bearer $TOKEN" \ https://manga-api.violetcrown.my.id/bookmarks # -> [] # CORS preflight from a real site origin. curl -s -i -X OPTIONS \ -H 'Origin: https://asurascans.com' \ -H 'Access-Control-Request-Method: PUT' \ https://manga-api.violetcrown.my.id/bookmarks/x | grep -i access-control # -> Access-Control-Allow-Origin: https://asurascans.com (+ Methods/Headers) ``` All four must pass. Valid TLS is non-negotiable — the manga sites are HTTPS, so a bad cert makes the browser block the userscript's `fetch()` (mixed content). --- ## 4. Configure the userscript Edit the config block at the top of `userscript/manga-bookmark.user.js`: ```js const API_BASE = "https://manga-api.yourdomain.com"; // no trailing slash const API_TOKEN = ""; ``` The token sits in the userscript's isolated world — the manga sites' JS can't read it. --- ## 5. Install on Bromite 1. Bromite → **Settings → User scripts** → enable (accept the permission prompt). 2. Put the edited `manga-bookmark.user.js` on the device (save the file, or open its raw URL). Bromite detects `.user.js` and offers to install. 3. Confirm install — the `@match` list covers both sites. 4. Open a series on asurascans.com or demonicscans.org → a 📑 button appears bottom-right → tap → **+ Bookmark this**. Optional desktop test: the script is `GM_*`-free, so the same file installs in Tampermonkey/Violentmonkey for quick checks before going mobile. --- ## 6. Smoke-test the full loop 1. Bookmark a series on Asura. 2. `curl -s -H "Authorization: Bearer $TOKEN" https://manga-api.yourdomain.com/bookmarks` on the server — the series should appear. 3. Open a chapter of that series — reopen the panel; last-read updates to that chapter (auto, never regresses on older chapters). 4. Open Demonic, open the panel — the Asura bookmark shows there too (shared store, cross-site unified list). --- ## Updating Pull new code, then rebuild: ```bash docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build ``` SQLite data persists in the named volume `bookmarks-data` across rebuilds. --- ## Troubleshooting | Symptom | Likely cause / fix | |---------|--------------------| | No cert / TLS error at the domain | `TRAEFIK_ENTRYPOINT` or `TRAEFIK_CERTRESOLVER` name wrong; or DNS not resolving yet. Check `docker logs `. | | 404 from Traefik | Service not on the `proxy` network, or `MANGA_API_HOST` mismatch. Confirm `docker network inspect proxy` lists `manga-api`. | | `fetch` fails in the userscript, `curl` works | Origin missing from `ALLOWED_ORIGINS`, or mixed content (backend not HTTPS). | | 401 with the right token | Trailing space/newline in `API_TOKEN`; regenerate and restart. | | Panel button absent | URL didn't match an adapter, or user scripts disabled in Bromite. | | `compose ... config` errors about `API_TOKEN` | Run compose from the dir with `.env`, or export the vars. | Backend config reference and endpoint list: see `README.md`.