commit 73b2170520dfbd70416755ad0d1171bb435b80fd
parent 342bdebc4947df5a2c39a7e961362dcd1f8a2afc
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 31 May 2026 12:38:04 +0200
write README
Diffstat:
| M | README | | | 188 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 188 insertions(+), 0 deletions(-)
diff --git a/README b/README
@@ -0,0 +1,188 @@
+Paivana
+=======
+
+Paivana is an HTTP reverse proxy that gates access to a target website
+behind a GNU Taler payment. Unpaid visitors receive a paywall page
+where they can pay using a GNU Taler wallet; once payment is confirmed
+the request is forwarded transparently to the configured upstream
+server.
+
+The sole binary is `paivana-httpd`.
+
+
+How it works
+------------
+
+0. `paivana-httpd` learns prices from the Paivana templates configured
+ in the taler-merchant-backend. Paivana templates include a regular
+ expression which determines the set of pages the template applies to.
+1. An HTTP client accesses a page at `paivana-httpd`.
+2. If the paywall is enabled for the respective URL and no valid access
+ cookie is present, `paivana-httpd` renders a static paywall HTML page
+ (customizable Mustache template) referencing the payment template.
+ The page includes a "Paivana" HTTP header to also facilitate agentic
+ payments.
+3. The browser computes a unique payment identifier and
+ renders a dynamic payment request (taler:// QR code
+ or link) and long-polls the taler-merchant-backend awaiting
+ completion of the payment.
+4. The user instructs their Taler wallet to complete the payment.
+5. The browser notices that the payment is complete and calls back to
+ `POST /.well-known/paivana` (provided by `paivana-httpd`)
+ with a reference to the unique payment identifier.
+6. `paivana-httpd` verifies the payment with the merchant, sets
+ an HMAC access cookie, and redirects the browser to the original URL.
+7. Requests with a valid cookie are forwarded to the upstream server
+ via libcurl and the response is streamed back.
+
+The cookie is an HMAC over `(expiration time, website, client address)` keyed by a
+`paivana_secret` derived from the configured `SECRET`. If `SECRET` is absent,
+a random nonce is used and cookies do not survive a restart of `paivana-httpd`
+
+
+Dependencies
+------------
+
+- GNUnet (libgnunetutil, libgnunetcurl)
+- libmicrohttpd
+- libcurl >= 7.34.0
+- libjansson
+- libgcrypt >= 1.6.1
+- zlib
+- GNU Taler: libtalerutil, libtalermerchant, libtalerexchange,
+ libtalermhd, libtalertemplating
+
+
+Build
+-----
+
+The project uses Meson but supports a GNU build process.
+
+ ./bootstrap
+ ./configure --prefix=$TARGET
+ make
+ sudo make install
+
+
+Configuration
+-------------
+
+Paivana reads an INI-style `.conf` file. The only section used is
+`[paivana]`. A minimal working configuration:
+
+ [paivana]
+ DESTINATION_BASE_URL = https://example.com/
+ MERCHANT_BACKEND_URL = https://backend.demo.taler.net/instances/sandbox/
+ MERCHANT_ACCESS_TOKEN = secret-token:sandbox
+ SERVE = tcp
+ PORT = 9967
+
+### Required keys
+
+ Key Description
+ ---------------------- -----------------------------------------------------
+ DESTINATION_BASE_URL Upstream server to proxy to once payment is confirmed.
+ MERCHANT_BACKEND_URL Base URL of the Taler merchant backend.
+ MERCHANT_ACCESS_TOKEN Bearer token for all calls to the merchant backend.
+
+### Optional keys
+
+ Key Description
+ -------- ---------------------------------------------------------------
+ BASE_URL Public base URL of Paivana. Derived from request headers
+ (X-Forwarded-Host / Host / X-Forwarded-Port) if absent.
+ SECRET Stable secret for cookie MAC and Paivana ID derivation.
+ A random nonce is generated on every startup if absent.
+ SERVE `tcp` (default) or `unix` (Unix-domain socket) or `systemd`
+ (systemd socket activation).
+ PORT TCP port, used when SERVE = tcp.
+ BIND_TO IP address to bind to; dual-stack wildcard if absent.
+ UNIXPATH UNIX path do bind to, used when SERVE = unix.
+
+
+Running
+-------
+
+$ paivana-httpd -c /etc/paivana/paivana.conf
+
+Pass `-n` / `--no-payment` to bypass the paywall entirely (pure reverse
+proxy, useful for testing upstream plumbing).
+
+The daemon does not serve requests until it has fetched paywall templates
+from the merchant backend. If template loading fails, startup is aborted.
+
+
+Deployment behind a reverse proxy
+----------------------------------
+
+The recommended production setup runs Paivana over a Unix socket and
+places nginx or Apache in front for TLS termination.
+
+nginx (`/etc/nginx/sites-available/paivana`):
+
+ server {
+ listen 443 ssl;
+ server_name example.com;
+
+ location / {
+ proxy_pass http://unix:/run/paivana/httpd/paivana-http.sock;
+ proxy_set_header Host $host;
+ }
+ }
+
+Apache (requires mod_proxy and mod_proxy_http):
+
+ <Location "/">
+ ProxyPass "unix:/var/lib/paivana/httpd/paivana.sock|http://example.com/"
+ </Location>
+
+Set `BASE_URL` in the configuration file to the public HTTPS URL so
+that redirects and cookie domains are correct.
+
+
+Source layout
+-------------
+
+ src/backend/ Main binary and all subsystems
+ paivana-httpd.c Entry point, scheduler, global state, shutdown
+ paivana-httpd_reverse.c Request-proxying state machine (core)
+ paivana-httpd_pay.c POST /.well-known/paivana handler
+ paivana-httpd_cookie.c HMAC access-cookie logic
+ paivana-httpd_templates.c Paywall template loading and rendering
+ paivana-httpd_helper.c Client IP / base URL helpers
+ paivana-httpd_daemon.c MHD daemon startup
+ paivana_pd.c GNUnet project-data descriptor
+ src/include/platform.h GNUnet-style platform header (include first)
+ src/tests/ Automated reverse-proxy tests
+ contrib/paywall.en.must Default Mustache paywall template
+ doc/prebuilt/ Git submodule: taler-docs (man pages)
+
+
+Architecture notes
+------------------
+
+Single-threaded event loop: GNUnet scheduler drives both inbound HTTP
+(libmicrohttpd) and outbound requests (libgnunetcurl / libcurl multi).
+Running multiple `paivana-httpd` processes on the same port is
+supported as the main way to scale-up the system.
+
+Requests and responses are currently not streamed in the reverse
+proxy; as a result, uploads and downloads are currently hard-capped by
+the implementation at 40 MiB. Lower limits for the upload may be
+configured.
+
+The MHD daemon is not started until paywall templates have been fetched
+from the merchant backend asynchronously.
+
+
+License
+-------
+
+GNU Affero General Public License version 3 or later.
+See COPYING for the full text.
+
+
+Bug reports
+-----------
+
+Please report bugs at https://bugs.taler.net/.