Serve several People

Let other People reach a Local Installation through your own proxy or tunnel, in Multi-User Mode.

A local installation can also serve other People: a household, or a small team, with SQLite. This is the multi-user mode. It follows from the Public Origin: an installation whose Public Origin host is not loopback is in the mode, and no other setting says so.

The daemon terminates no TLS, so the owner runs a proxy or tunnel of their own on the same machine. It holds the certificate, answers on a name that the other People open, and forwards to the daemon on loopback. Three setups follow: Caddy, Tailscale Serve and Cloudflare Tunnel. Each one forwards the WebSocket upgrade, sets X-Forwarded-Proto and X-Forwarded-For, and passes on the name that people open in Host. Those headers are also what tell the daemon that a request came through the proxy and not from the owner's own Client App, so the Client Credential and a byo Google Connection stay with the machine itself (ADR-0025).

Turn the mode on

  1. Set up one of the proxies or tunnels below, and open its name in a browser to check that Pagis answers.
  2. In the Administration Interface, open Settings, and turn on Multi-user mode under Network. A Client App set up for "Several people" opens this switch after the installation.
  3. Type the address people open as the Public Origin, such as https://pagis.example.net. It is an absolute https:// or http:// URL whose host is not loopback. Use https://: at an http:// address on another machine, the browser gives no microphone for dictation, a password crosses the network in clear text, and the Client App of another Person refuses to connect.
  4. Keep 127.0.0.1 as the Trusted Proxy. That is the address a proxy or tunnel on this machine reaches the daemon from. The daemon then believes its X-Forwarded-Proto, so the Session cookie carries Secure, and its X-Forwarded-For, so the sign-in rate limit counts each browser apart.
  5. Select Turn on and restart. The daemon writes the Public Origin and the Trusted Proxy to config.toml and starts again.

The switch keeps the Bind Address on loopback. A proxy or tunnel on the same machine reaches the daemon there, and so does the owner's Client App, while the plain-HTTP port stays off the network, so nobody reaches Pagis around the proxy's TLS.

The installation keeps its Client Credential, so the Client App on the machine stays signed in. The first-run route stays closed, because a credential exists. The Administrator creates the other People in the Administration Interface. To sign in from a browser on another machine, the owner sets their own address and password there too (ADR-0024).

Turn the mode off with the same switch and Turn off and restart. The daemon clears the Public Origin and the Trusted Proxy and binds loopback. With the mode off, the daemon answers only a request from a program on its own machine: it refuses every request that carries a proxy header, such as X-Forwarded-For, or a Host that is not a loopback name. A browser that opens a page gets a short page that says so, with status 403. A request under /api/, and every request that does not ask for HTML, gets the JSON error. The People who signed in from other machines keep their accounts and their Sessions, and they reach nothing until the mode is on again, also while the proxy or tunnel still runs. Stop the proxy or tunnel as well.

A server is always in the mode. Its deployment names the Public Origin in PAGIS_PUBLIC_ORIGIN, and the Administration Interface shows the mode with no switch.

What a Computer reaches here

A Local Installation has no egress rules. A daemon that runs as the owner cannot write the firewall of this computer or of the Docker Desktop or Colima VM, so Pagis does not install them. The Computer of each Agent, also of an Agent of another Person, therefore reaches the public internet, the LAN, and each service of this computer that listens on a network address. Under Docker Desktop or Colima it can possibly also reach the services that listen on this computer's loopback, through the host gateway. An HTTP or SSE Plugin server sends its requests from the daemon, so it also reaches the HTTP services on this computer's loopback (Reach). The Pagis product port still asks for a password or the Client Credential, and the control port of each other Computer still asks for its secret. A server installs the rules (What a Computer reaches).

Caddy

For a name that people reach over the internet or the LAN, with a DNS record that points at this machine and ports 80 and 443 open to it:

Caddyfile
{
	admin off
}

pagis.example.net {
	reverse_proxy 127.0.0.1:4400
}

Run it with caddy run --config Caddyfile. Caddy gets and renews the certificate, sets X-Forwarded-Proto, appends to X-Forwarded-For, keeps the Host that the browser sent, and passes a WebSocket upgrade through with no configuration. The Public Origin is https://pagis.example.net. admin off closes the admin API of Caddy, which listens on the loopback of this machine by default, where the daemon and each HTTP Plugin server also send requests.

Tailscale Serve

For People on the owner's tailnet, with MagicDNS and HTTPS certificates turned on for the tailnet:

tailscale serve --bg 4400

Tailscale serves https://<machine>.<tailnet>.ts.net to the tailnet and forwards to http://127.0.0.1:4400. It sets X-Forwarded-Proto to https and X-Forwarded-For to the tailnet address of the person's device, keeps the Host that the browser sent, and passes a WebSocket upgrade through. The Public Origin is the https:// address that tailscale serve status prints, such as https://owner-mac.tail1234.ts.net. tailscale serve reset stops it.

Cloudflare Tunnel

For a name on a domain whose DNS is on Cloudflare, with no port open on this machine:

cloudflared tunnel login
cloudflared tunnel create pagis
cloudflared tunnel route dns pagis pagis.example.net

Then write ~/.cloudflared/config.yml, with the tunnel UUID that create printed:

tunnel: <Tunnel-UUID>
credentials-file: /Users/owner/.cloudflared/<Tunnel-UUID>.json
ingress:
  - hostname: pagis.example.net
    service: http://127.0.0.1:4400
  - service: http_status:404

Run it with cloudflared tunnel run pagis. Cloudflare holds the certificate, sets X-Forwarded-Proto, appends the browser's address to X-Forwarded-For, and carries WebSockets; cloudflared keeps the Host that the browser sent. The Public Origin is https://pagis.example.net.

The live screen for other people

The live screen of a Computer does not go through the proxy or tunnel. A browser sends and receives it over UDP at the Media Relay's address, which is [screen] advertise_ip in config.toml, on one port of media_port_first to media_port_last (50000 to 50099 by default). A local installation advertises 127.0.0.1, so the mode alone keeps the live screen on this computer: People on other machines see "Live screen unavailable". The relay listens on every interface of this computer, so one setting and one firewall rule carry the screen to them. Each setup above names its own address:

  • Caddy on the LAN. Set advertise_ip to this computer's LAN address, such as 192.168.1.20, and allow the UDP range in this computer's firewall. For People on the internet, set the public address and forward the UDP range from the router to this computer.
  • Tailscale Serve. Set advertise_ip to this computer's tailnet address, which tailscale ip -4 prints, such as 100.101.102.103. The tailnet carries UDP, so no port is opened to the internet.
  • Cloudflare Tunnel. The tunnel carries no UDP. Put a TURN server in front of the relay (relay = "turn", the variant in Live screen), or advertise a public address and forward the UDP range to this computer.

For example, with Tailscale:

[screen]
advertise_ip = "100.101.102.103"

Restart Pagis after the change. PAGIS_SCREEN_ADVERTISE_IP sets the same address for one run.

In Settings, Multi-user mode names the address that the running daemon advertises. It says whether other machines reach the live screen, and for an address that is not loopback, the UDP range that the firewall must let through.

Edit on GitHub

On this page