ipx-web: the page in its own container, behind Caddy (#203)
web/build.mjs builds a static site, web/dist, with the icons and typeface beside the pages; Dockerfile.web serves it with Caddy, which passes /api and /media to ipx on the same origin, so cookies, live updates and Cloudflare Access work as before. ipx serves no page any more: build.rs and every include_str! of the web files are gone, and its image is built without node. What ipx did to the page as it served it is kept another way. Caddy asks ipx before serving a page (forward_auth): /api/page-check sends a browser not signed in to /login and a non-admin away from /admin, and refuses them /admin.js; /api/login-check sends someone Access vouches for past the form; a page asked for with ?token= goes to /api/signin, which sets the cookie. The theme and the admin link, once written into the page per person, are set by web/boot.js in <head> from the theme cookie and the last visit, before the first frame, and /api/me brings the version and the account's theme from before. Caddy strips the Cf-Access-* headers from every peer but TUNNEL_PEER, the address cloudflared's requests come from, which is the boundary trusted_proxies drew; ipx then trusts only Caddy's address. The browser suite runs Caddy in front of its daemon, so it tests what production would run. Not deployed: production's cutover is on #203. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -29,11 +29,13 @@ The version is the workspace's, in the root `Cargo.toml`.
|
||||
| `web/admin.html` | The admin page's markup: server settings, accounts, the log. Sent to admins only | — |
|
||||
| `web/app.css` | The stylesheet both pages share | — |
|
||||
| `web/src/*.ts` | The page's script, one scope split across files, type-checked by `npx tsc` | — |
|
||||
| `web/build.mjs` | swc: strips the types into `app.js`/`login.js`, named in the page by a hash of their contents, and minifies | — |
|
||||
| `crates/ipx/build.rs` | Runs `web/build.mjs` into `OUT_DIR`, where `web.rs` `include_str!`s the result | — |
|
||||
| `web/build.mjs` | swc: strips the types into `app.js`/`admin.js`/`login.js`, named in the page by a hash of their contents, minifies, and writes the static site to `web/dist` | — |
|
||||
| `web/boot.js` | In `<head>`: the theme from its cookie, and an admin's link, before the first frame | — |
|
||||
| `web/Caddyfile` | `ipx-web`: serves `web/dist`, asks ipx before serving a page, passes `/api` and `/media` to ipx | — |
|
||||
|
||||
The page is compiled in, so **editing `web/index.html` or `web/src` needs a rebuild**, and a
|
||||
build needs node and `npm ci` run once.
|
||||
The page is a separate image, `ipx-web` (`Dockerfile.web`, #203), so **editing `web/` needs
|
||||
ipx-web rebuilt**, not ipx, and building it needs node and `npm ci` run once. ipx serves the API
|
||||
and the files, and no page.
|
||||
|
||||
## A scan
|
||||
|
||||
@@ -125,8 +127,8 @@ else a `401`. A feed's items and files (its entries, `download-latest`, `/api/en
|
||||
|
||||
| Route | |
|
||||
|---|---|
|
||||
| `GET /` | the app |
|
||||
| `GET /login`, `POST /api/login`, `POST /api/logout`, `GET /api/me` | sign-in |
|
||||
| `GET /api/page-check`, `GET /api/login-check`, `GET /api/signin` | for Caddy (#203): whether the visitor may have the page in `X-Forwarded-Uri` (`204`), or where to send them; signing in with `?token=` |
|
||||
| `POST /api/login`, `POST /api/logout`, `GET /api/me` | sign-in; `/api/me` also gives the version and the account's theme from before |
|
||||
| `GET /api/feeds`, `POST /api/feeds` | your subscriptions; subscribe |
|
||||
| `PATCH /api/feeds/{id}`, `DELETE /api/feeds/{id}` | your settings or (admin) the feed's; unsubscribe |
|
||||
| `GET /api/feeds/{id}/entries` | paged, filtered, searchable, sortable (`sort` = kept, title, feed, type, size or published; `dir` = asc or desc) |
|
||||
|
||||
10
docs/sso.md
10
docs/sso.md
@@ -84,6 +84,16 @@ stays `192.168.64.1` when the network is recreated. It was `192.168.16.1`, `cont
|
||||
ipx was part of the `content` project. If the subnet is ever changed, update `trusted_proxies` to
|
||||
match.
|
||||
|
||||
### Behind ipx-web (#203)
|
||||
|
||||
With the page served by `ipx-web` (Caddy), cloudflared reaches Caddy instead, still through the
|
||||
host's port 8099, so its requests still arrive from `192.168.64.1`, at Caddy now. Caddy passes the
|
||||
`Cf-Access-*` headers on only from that address (`TUNNEL_PEER`) and strips them from everyone else,
|
||||
the boundary `trusted_proxies` drew before. ipx then sees every request come from Caddy, so
|
||||
`trusted_proxies` names Caddy's address on `ipx_default`, pinned in the compose file
|
||||
(`192.168.64.10`), instead of the gateway. The token check is unchanged: a header Caddy passes on
|
||||
still needs a valid `Cf-Access-Jwt-Assertion`.
|
||||
|
||||
### Names
|
||||
|
||||
The username is the email address, lower-cased: `rays@sdf1.net`. To sign in at `/login` with a
|
||||
|
||||
Reference in New Issue
Block a user