docs/sso.md: the sign-in setup ipodderx.sdf1.net really runs
Authentik is Cloudflare Access's OpenID Connect identity provider, not something in the request path, and the tunnel's requests reach ipx from the content_default gateway, 192.168.16.1, not 127.0.0.1. The page is rewritten from what was measured, with checks for both the trusted and the refused path, and docs/history.md records every change made to get there with how to undo it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TAC7sLVqfKmY6rsTLXzNgk
This commit is contained in:
@@ -28,6 +28,9 @@ The long form, with what was wrong before and how it was found, is in
|
||||
|
||||
- Show notes that the podcast's host cut off in the middle of a tag no longer open with a scrap of
|
||||
HTML: the item's other copy of its notes is shown instead. Daily Meditation Podcast had 57.
|
||||
- The sign-in guide, `docs/sso.md`, describes the setup ipodderx.sdf1.net really runs: Authentik as
|
||||
Cloudflare Access's identity provider, and how to find the address ipx has to trust. It had never
|
||||
been checked against a real setup, and pointed at the wrong address.
|
||||
|
||||
## [0.5.1] - 2026-09-12
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ Arcane project `content`: `/mnt/fast/arcane/projects/content/compose.yaml`. That
|
||||
| Database | `/mnt/user/ipodderx/state.db` | `/data/state.db` |
|
||||
| Downloads | `/mnt/user/ipodderx/downloads` | `/downloads` |
|
||||
| Web UI | `192.168.1.130:8099`, also `ipodderx.sdf1.net` via a Cloudflare tunnel | `0.0.0.0:8099` |
|
||||
| Sign-in via the tunnel | Cloudflare Access app `ipodderx`, with Authentik as its identity provider; see [docs/sso.md](docs/sso.md) | trusts `Cf-Access-Authenticated-User-Email` from `192.168.16.1`, the `content_default` gateway |
|
||||
|
||||
Deploying a change is: build and push the image, then pull it and recreate the container.
|
||||
|
||||
|
||||
@@ -6,6 +6,46 @@ reasoning lives. New write-ups go at the top.
|
||||
|
||||
See [README.md](../README.md) for what the thing is.
|
||||
|
||||
## 2026-09-12 — Signing in through Authentik, for real
|
||||
|
||||
Ray could not get Authentik's sign-in to reach ipx, following `docs/sso.md`, which had been written
|
||||
without ever being tried. Looking at the Cloudflare account through its API showed that side was
|
||||
already complete. Authentik is Zero Trust's OpenID Connect identity provider; the Access application
|
||||
`ipodderx` allows only it and a list of five addresses; the tunnel `rays-unraid` routes
|
||||
`ipodderx.sdf1.net` to `192.168.1.130:8099`; DNS is a proxied CNAME to the tunnel. Access's log
|
||||
showed `rays@sdf1.net` signing in through it. Nothing on Cloudflare was changed, so no other site
|
||||
was touched.
|
||||
|
||||
The gaps were all at ipx's end: `trusted_header` was empty, `trusted_proxies` held only loopback,
|
||||
and the account was called `rays` while the header carries `rays@sdf1.net`.
|
||||
|
||||
Finding the address to trust took the most time. The page said `127.0.0.1`, but `cloudflared` runs in
|
||||
its own container and reaches ipx through the host's published port. ipx logs no peer addresses, so
|
||||
the address was read from `/proc/net/tcp` inside the ipx container: `192.168.16.1`, the gateway of
|
||||
`content_default`, where Docker's masquerade puts traffic crossing from another bridge. A request
|
||||
from Tower's own shell arrived as `192.168.1.130` instead, and a throwaway `busybox` on the default
|
||||
bridge as `192.168.16.1`: the first was refused with the header, the second believed. LAN machines
|
||||
keep their own addresses, since Docker forwards published ports with iptables (the userland proxy
|
||||
only handles loopback).
|
||||
|
||||
Every change, in order, with how to undo it:
|
||||
|
||||
1. **Code**, commit `586d2c0`: `ipx user rename`, deployed. Revert the commit and redeploy to
|
||||
remove it; nothing depends on it once used.
|
||||
2. **Account**: `docker exec iPodderX ipx user rename rays rays@sdf1.net`. Same id, so its feeds,
|
||||
read state, password and admin rights stayed. Undo: `docker exec iPodderX ipx user rename
|
||||
rays@sdf1.net rays`. Signing in at `/login` now takes the new name.
|
||||
3. **Config**, `/mnt/fast/appdata/ipodderx/config.toml`, `[web]`: `trusted_header` from `""` to
|
||||
`"Cf-Access-Authenticated-User-Email"`, and `"192.168.16.1"` added to `trusted_proxies`. The
|
||||
file as it was is `config.toml.2026-09-12-sso.bak` beside it. Undo: copy the backup back and
|
||||
`docker compose -f /mnt/fast/arcane/projects/content/compose.yaml restart ipodderx`.
|
||||
4. **Cloudflare, Authentik, Docker networks and other containers**: unchanged. The `busybox` test
|
||||
container was removed when it exited, and its image afterwards.
|
||||
|
||||
What the address trusts is any container on Tower that connects through the host's port, not only
|
||||
`cloudflared`. Verifying Cloudflare's signed `Cf-Access-Jwt-Assertion` would remove that, and is
|
||||
the upgrade if it matters.
|
||||
|
||||
## 2026-09-12 — Trimming the state database
|
||||
|
||||
An audit of the database layer, with a read-only copy of production to check it against. The
|
||||
|
||||
288
docs/sso.md
288
docs/sso.md
@@ -1,9 +1,8 @@
|
||||
# Signing in through Cloudflare Zero Trust or Authentik
|
||||
# Signing in through Cloudflare Access and Authentik
|
||||
|
||||
ipx can take the signed-in identity from whatever sits in front of it, instead of asking for a
|
||||
password itself. Both products below do the same thing in the end: they authenticate the person and
|
||||
pass the result to the origin in a **header**. ipx reads that header, finds (or creates) the
|
||||
matching account, and gets on with it.
|
||||
password itself. The proxy authenticates the person and passes the result to ipx in a **header**;
|
||||
ipx reads it, finds (or creates) the matching account, and gets on with it.
|
||||
|
||||
Read [How this is secured](#how-this-is-secured) before exposing anything. The short version: a
|
||||
header is worth exactly as much as the hop that set it, so ipx only believes one from an address you
|
||||
@@ -11,195 +10,152 @@ list.
|
||||
|
||||
---
|
||||
|
||||
## The ipx side (both setups)
|
||||
## How ipodderx.sdf1.net does it
|
||||
|
||||
Checked end to end on 2026-09-12. An earlier version of this page had never been tried against a
|
||||
real setup and pointed at the wrong address.
|
||||
|
||||
```
|
||||
browser ─► Cloudflare Access, app "ipodderx" ─── sign in ───► Authentik (OpenID Connect)
|
||||
─► tunnel "rays-unraid" (the cloudflared container on Tower)
|
||||
─► http://192.168.1.130:8099 ─► ipx
|
||||
```
|
||||
|
||||
Authentik is not in the request path. It is the identity provider Cloudflare Access asks. Access
|
||||
then adds `Cf-Access-Authenticated-User-Email`, the email address Authentik gave it, to every
|
||||
request it forwards through the tunnel, and ipx signs that person in.
|
||||
|
||||
| Piece | Where | Setting |
|
||||
|---|---|---|
|
||||
| Identity provider | Zero Trust → Settings → Authentication | `Authentik`, OpenID Connect; scopes `openid email profile` |
|
||||
| Access application | Zero Trust → Access → Applications → `ipodderx` | Domain `ipodderx.sdf1.net`; identity providers: Authentik only, with instant auth; session 730h; policy *Require Login* allows a list of email addresses |
|
||||
| Tunnel route | Zero Trust → Networks → Tunnels → `rays-unraid` → Public hostnames | `ipodderx.sdf1.net` → HTTP `192.168.1.130:8099` |
|
||||
| DNS | `sdf1.net` | `ipodderx` CNAME to the tunnel, proxied |
|
||||
| ipx | `/mnt/fast/appdata/ipodderx/config.toml`, `[web]` | below |
|
||||
|
||||
```toml
|
||||
[web]
|
||||
enabled = true
|
||||
bind = "0.0.0.0:8099"
|
||||
token = "…" # keep it: it is the admin, used by the healthcheck
|
||||
|
||||
# The header your proxy sets. Empty (the default) disables this whole path.
|
||||
trusted_header = "Cf-Access-Authenticated-User-Email" # Authentik: "X-authentik-username"
|
||||
|
||||
# Addresses allowed to assert that header -- the proxy, and nothing else.
|
||||
trusted_proxies = ["127.0.0.1", "::1"]
|
||||
|
||||
# Create an account the first time the proxy vouches for a name ipx has not seen.
|
||||
bind = "0.0.0.0:8099"
|
||||
trusted_header = "Cf-Access-Authenticated-User-Email"
|
||||
trusted_proxies = ["127.0.0.1", "::1", "192.168.16.1"]
|
||||
auto_create_users = true
|
||||
|
||||
session_days = 30
|
||||
```
|
||||
|
||||
Restart the daemon after editing. Accounts made this way have **no password**: they can only ever
|
||||
arrive through the proxy. `ipx user list` marks them `proxy only`.
|
||||
Restart ipx after editing it: `docker compose -f /mnt/fast/arcane/projects/content/compose.yaml
|
||||
restart ipodderx`.
|
||||
|
||||
The first account created is an admin. Every later one is an ordinary user, and an ordinary user
|
||||
cannot change global settings, a feed's URL or folder, or how often feeds are scanned: the API
|
||||
refuses those with a `403`, not just the UI. Everything else about a feed (which items they want,
|
||||
whether to fetch them, how many at a time) is theirs alone; see [users.md](users.md).
|
||||
### What was missing
|
||||
|
||||
Somebody arriving through the proxy for the first time starts with **no feeds**, because
|
||||
subscriptions are per person. Adding a feed someone else already reads costs no second fetch and no
|
||||
second copy on disk.
|
||||
Cloudflare and Authentik were already right. Three things on the ipx side were not:
|
||||
|
||||
Promote someone with:
|
||||
1. **`trusted_header` was empty**, which switches the whole proxy path off. ipx ignored the header
|
||||
and asked for a password.
|
||||
2. **`trusted_proxies` listed only `127.0.0.1`.** The tunnel's requests do not come from there;
|
||||
see the next section.
|
||||
3. **The account had the wrong name.** It was made by hand as `rays`, but the header carries
|
||||
`rays@sdf1.net`. With `auto_create_users` on, the first visit would have made a second, empty
|
||||
account. `ipx user rename rays rays@sdf1.net` fixed that without losing anything.
|
||||
|
||||
### The address to trust, and why it is 192.168.16.1
|
||||
|
||||
`cloudflared` runs in its own container and reaches ipx through the host's published port. Docker
|
||||
(iptables firewall backend) masquerades traffic between its bridge networks, so the tunnel's
|
||||
requests arrive from the **gateway of ipx's own network**, `content_default`:
|
||||
|
||||
```sh
|
||||
ipx user list
|
||||
echo -n 'a good password' | ipx user passwd <name> # optional: also lets them sign in directly
|
||||
docker network inspect content_default -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}'
|
||||
```
|
||||
|
||||
Local sign-in at `/login` keeps working alongside all of this, which is how you get in from the LAN
|
||||
when the tunnel is down. So does the shared `[web] token`, which signs in as the admin: that is
|
||||
what the Docker healthcheck uses, and the way back in if you lock yourself out. A brand new database
|
||||
starts with **admin / ipodderx** — change it.
|
||||
That was measured, not assumed. ipx does not log where a request came from, so the addresses were
|
||||
read from the kernel's connection table inside the container while the site was open. (`/proc/net/tcp`
|
||||
lists them in hex.)
|
||||
|
||||
If the `content` project's network is ever recreated, its gateway can change. Check it again, and
|
||||
update `trusted_proxies` to match.
|
||||
|
||||
### Names
|
||||
|
||||
The username is the email address, lower-cased: `rays@sdf1.net`. To sign in at `/login` with a
|
||||
password from the LAN, use that name too.
|
||||
|
||||
To let someone else in, add their address to the Access policy; they need an Authentik account with
|
||||
that email. With `auto_create_users = true` they get an ipx account on their first visit, as an
|
||||
ordinary user with no feeds. An account made before the proxy can be given the name the proxy will
|
||||
send:
|
||||
|
||||
```sh
|
||||
docker exec iPodderX ipx user rename <old name> <email address>
|
||||
```
|
||||
|
||||
### Check it
|
||||
|
||||
```sh
|
||||
# From Tower itself: not a trusted address, so the header is ignored.
|
||||
curl -s -H 'Accept: application/json' -H 'Cf-Access-Authenticated-User-Email: rays@sdf1.net' \
|
||||
http://192.168.1.130:8099/api/me # -> sign in
|
||||
|
||||
# From a container on a Docker bridge, as cloudflared is: believed.
|
||||
docker run --rm --network bridge mirror.gcr.io/library/busybox wget -qO- \
|
||||
--header 'Accept: application/json' --header 'Cf-Access-Authenticated-User-Email: rays@sdf1.net' \
|
||||
http://192.168.1.130:8099/api/me # -> {"admin":true,"name":"rays@sdf1.net"}
|
||||
```
|
||||
|
||||
Then open `https://ipodderx.sdf1.net` in a private window. Authentik should ask who you are, and
|
||||
ipx should show `rays@sdf1.net` in the sidebar footer without asking for a password.
|
||||
|
||||
---
|
||||
|
||||
## Cloudflare Zero Trust
|
||||
## The ipx settings
|
||||
|
||||
This is what runs `ipodderx.sdf1.net`: a `cloudflared` tunnel to the origin, with an Access
|
||||
application in front of it. Cloudflare authenticates the visitor and adds
|
||||
`Cf-Access-Authenticated-User-Email` to every request it forwards.
|
||||
|
||||
### 1. The tunnel
|
||||
|
||||
In **Zero Trust → Networks → Tunnels**, either use the existing tunnel or create one, then add a
|
||||
public hostname:
|
||||
|
||||
| Field | Value |
|
||||
| Key | What it does |
|
||||
|---|---|
|
||||
| Subdomain / domain | `ipodderx` / `sdf1.net` |
|
||||
| Type | HTTP |
|
||||
| URL | `localhost:8099` (or the LAN address of the box) |
|
||||
| `trusted_header` | The header the proxy sets. Empty, the default, turns the proxy path off. |
|
||||
| `trusted_proxies` | The addresses allowed to set it. Nothing else is believed. |
|
||||
| `auto_create_users` | Make an account the first time the proxy vouches for a name ipx has not seen. |
|
||||
| `session_days` | How long a password sign-in lasts without use. |
|
||||
|
||||
Use `localhost` when `cloudflared` runs on the same machine as ipx — that keeps the origin request
|
||||
coming from `127.0.0.1`, which is already in `trusted_proxies`. If `cloudflared` runs elsewhere (its
|
||||
own container, another host), put **its** address in `trusted_proxies` instead, and make sure
|
||||
nothing else can reach port 8099.
|
||||
The first account ever created is an admin. Every later one is an ordinary user, who cannot change
|
||||
global settings, a feed's URL or folder, or how often feeds are scanned: the API refuses those with
|
||||
a `403`, not just the UI. Everything else about a feed is theirs alone; see [users.md](users.md).
|
||||
|
||||
### 2. The Access application
|
||||
|
||||
**Zero Trust → Access → Applications → Add an application → Self-hosted**:
|
||||
|
||||
- Application domain: `ipodderx.sdf1.net`
|
||||
- Session duration: whatever suits; ipx keeps its own 30-day session on top.
|
||||
- Add a policy — *Allow*, with a rule such as `Emails` → your address, or `Emails ending in` →
|
||||
your domain. Anyone this policy admits gets an ipx account when `auto_create_users` is on, so keep
|
||||
the policy as narrow as the people you actually want reading your feeds.
|
||||
|
||||
### 3. Point ipx at the header
|
||||
|
||||
```toml
|
||||
trusted_header = "Cf-Access-Authenticated-User-Email"
|
||||
trusted_proxies = ["127.0.0.1", "::1"]
|
||||
```
|
||||
|
||||
The username becomes the email address, lower-cased (`ray@example.com`). That is what shows in the
|
||||
sidebar and what `ipx user list` prints.
|
||||
|
||||
### 4. Check it
|
||||
|
||||
```sh
|
||||
# From the box itself: no header, no session -> the sign-in page.
|
||||
curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' -H 'Accept: text/html' http://127.0.0.1:8099/
|
||||
|
||||
# Pretending to be the tunnel (only works because 127.0.0.1 is trusted):
|
||||
curl -s -H 'Cf-Access-Authenticated-User-Email: you@example.com' http://127.0.0.1:8099/api/me
|
||||
```
|
||||
|
||||
Then load `https://ipodderx.sdf1.net` in a browser: Cloudflare should ask who you are, and ipx
|
||||
should show your address in the sidebar footer without ever asking for a password.
|
||||
Local sign-in at `/login` keeps working alongside the proxy, which is how you get in from the LAN
|
||||
when the tunnel is down. So does the shared `[web] token`, which signs in as the admin and is the
|
||||
way back in if you lock yourself out. A brand new database starts with **admin / ipodderx**;
|
||||
change it.
|
||||
|
||||
---
|
||||
|
||||
## Authentik
|
||||
## Authentik in the request path instead
|
||||
|
||||
Authentik does this with a **Proxy Provider** plus an **outpost**, which sits in the request path and
|
||||
adds `X-authentik-username` (also `X-authentik-email`, `X-authentik-name`, `X-authentik-groups`).
|
||||
Not what ipodderx.sdf1.net uses, and **not verified**. Authentik can also sit in front of ipx
|
||||
itself, with a **Proxy Provider** and an **outpost** that adds `X-authentik-username`:
|
||||
|
||||
### 1. Provider
|
||||
|
||||
**Applications → Providers → Create → Proxy Provider**:
|
||||
|
||||
- Name: `ipx`
|
||||
- Authorization flow: your usual (`default-provider-authorization-implicit-consent`)
|
||||
- Mode: **Forward auth (single application)** if an existing reverse proxy fronts ipx, or
|
||||
**Proxy** to let the outpost talk to ipx directly.
|
||||
- External host: `https://ipodderx.example.net`
|
||||
- Internal host (Proxy mode): `http://<ip of the ipx box>:8099`
|
||||
|
||||
### 2. Application and outpost
|
||||
|
||||
**Applications → Create**, bind it to that provider, and give it a policy so only the people you
|
||||
mean are let through. Then add the provider to an outpost (**Applications → Outposts**, the embedded
|
||||
one is fine).
|
||||
|
||||
### 3. Forward auth, if you use nginx/SWAG in front
|
||||
|
||||
In the server block for ipx:
|
||||
|
||||
```nginx
|
||||
location /outpost.goauthentik.io {
|
||||
proxy_pass http://authentik-server:9000/outpost.goauthentik.io;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
||||
}
|
||||
|
||||
location / {
|
||||
auth_request /outpost.goauthentik.io/auth/nginx;
|
||||
error_page 401 = @goauthentik_proxy_signin;
|
||||
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
|
||||
# This is the line that matters to ipx.
|
||||
auth_request_set $authentik_username $upstream_http_x_authentik_username;
|
||||
proxy_set_header X-authentik-username $authentik_username;
|
||||
|
||||
proxy_pass http://ipx:8099;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Point ipx at the header
|
||||
|
||||
```toml
|
||||
trusted_header = "X-authentik-username"
|
||||
trusted_proxies = ["172.18.0.5"] # the outpost or nginx container, NOT a whole subnet
|
||||
```
|
||||
|
||||
Usernames arrive as Authentik knows them (`ray`), lower-cased.
|
||||
- Applications → Providers → Create → Proxy Provider; mode **Proxy** (the outpost talks to ipx) or
|
||||
**Forward auth** (an existing reverse proxy asks the outpost).
|
||||
- Applications → Create, bound to that provider, with a policy; add the provider to an outpost.
|
||||
- In ipx: `trusted_header = "X-authentik-username"`, and the outpost's or reverse proxy's address
|
||||
in `trusted_proxies`. Measure that address as above rather than guessing it.
|
||||
|
||||
---
|
||||
|
||||
## How this is secured
|
||||
|
||||
**The header is only believed from `trusted_proxies`.** Every other source is ignored, and the
|
||||
request falls through to a session cookie or the shared token. This is the whole security boundary,
|
||||
so:
|
||||
request falls through to a session cookie or the shared token. That is the whole security boundary.
|
||||
|
||||
- List the **proxy's own address**, not a range. `["127.0.0.1"]` when the tunnel runs beside ipx;
|
||||
the container's IP when it does not.
|
||||
- Never list a LAN subnet. Anyone on your network could then send
|
||||
`Cf-Access-Authenticated-User-Email: admin@…` and be your admin.
|
||||
- Make sure the origin port is not reachable *around* the proxy by anyone you would not admit
|
||||
through it. If it is, bind ipx to `127.0.0.1` and let only the proxy reach it.
|
||||
With the tunnel reaching ipx through the host's port, `192.168.16.1` means **any container on Tower
|
||||
that connects to `192.168.1.130:8099`**, not only `cloudflared`. Machines on the LAN, and Tower
|
||||
itself, arrive under their own addresses and cannot set the header; the checks above show both
|
||||
sides. Never list a LAN address or range: anyone there could then send
|
||||
`Cf-Access-Authenticated-User-Email: rays@sdf1.net` and be you.
|
||||
|
||||
Verify the refusal, don't assume it — set `trusted_proxies = ["10.9.9.9"]` briefly and confirm a
|
||||
header from your machine gets a `401`:
|
||||
**What ipx does not do:** it does not verify Cloudflare's signed `Cf-Access-Jwt-Assertion`. It
|
||||
trusts the hop. Verifying the signature would make the containers on Tower irrelevant to the
|
||||
boundary, and is the upgrade if that ever matters.
|
||||
|
||||
```sh
|
||||
curl -s -o /dev/null -w '%{http_code}\n' \
|
||||
-H 'Cf-Access-Authenticated-User-Email: someone@example.com' http://127.0.0.1:8099/api/me
|
||||
```
|
||||
|
||||
**What ipx does not do:** it does not verify Cloudflare's `Cf-Access-Jwt-Assertion` signature or
|
||||
Authentik's session. It trusts the hop. That is a deliberate trade — it keeps the configuration to
|
||||
three lines — and it is sound exactly as long as the point above holds.
|
||||
|
||||
**Turning it off:** clear `trusted_header`. Existing proxy-only accounts stay, but nobody can sign
|
||||
**Turning it off:** clear `trusted_header` and restart. Proxy-made accounts stay, but nobody can sign
|
||||
in with them until they are given a password (`ipx user passwd <name>`).
|
||||
|
||||
---
|
||||
@@ -207,22 +163,20 @@ in with them until they are given a password (`ipx user passwd <name>`).
|
||||
## Everyday administration
|
||||
|
||||
```sh
|
||||
ipx user list # who exists, and how each one signs in
|
||||
ipx user list # who exists, how each signs in, and when
|
||||
echo -n 'secret123' | ipx user add sam # local account, password on stdin
|
||||
ipx user add sam --no-password # proxy-only account, created ahead of time
|
||||
ipx user add sam@example.com --no-password # proxy-only account, made ahead of time
|
||||
ipx user rename sam sam@example.com # give an account the name the proxy sends
|
||||
echo -n 'newsecret' | ipx user passwd sam # change a password
|
||||
ipx user rm sam # remove the account
|
||||
```
|
||||
|
||||
Set `auto_create_users = false` once everyone who should have an account has one. After that the
|
||||
proxy vouching for an unknown name is logged and refused, rather than quietly making an account.
|
||||
Pre-create people instead with `ipx user add <name> --no-password`, using exactly the name the
|
||||
header will carry (Cloudflare sends the email address, lower-cased).
|
||||
In the container, put `docker exec iPodderX` in front, and `docker exec -i iPodderX` for the ones
|
||||
that read a password.
|
||||
|
||||
Scanning intervals, the disk quota, retention, the download folder and a feed's URL are
|
||||
**admin-only**: the Settings button is hidden for everyone else, and the API refuses the change even
|
||||
if the request is made by hand. Everyone controls their own keywords, auto-download, explicit
|
||||
setting and per-scan cap, along with their own read state and which feeds they see.
|
||||
Set `auto_create_users = false` once everyone who should have an account has one. After that the
|
||||
proxy vouching for an unknown name is logged and refused. Make people ahead of time instead, with
|
||||
the exact name the header will carry.
|
||||
|
||||
See also [users.md](users.md) for what several people share, [configuration.md](configuration.md)
|
||||
for every `[web]` key, and [cli.md](cli.md) for the `ipx user` commands.
|
||||
|
||||
Reference in New Issue
Block a user