commit 8dff335c269adf4b4d7fc0c9ea5e75f098f0801e
parent 678c99c753a2a93ab3bcfc4920cd70edff6281c0
Author: Christian Grothoff <christian@grothoff.org>
Date: Mon, 25 May 2026 17:13:44 +0200
split up major paivana chapters
Diffstat:
5 files changed, 636 insertions(+), 575 deletions(-)
diff --git a/drupal-paivana-manual.rst b/drupal-paivana-manual.rst
@@ -0,0 +1,27 @@
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2026 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 2.1, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+
+.. _drupal-paivana:
+
+Drupal integration
+==================
+
+This chapter documents the installation and operation of the
+Drupal Paivana module.
+
+FIXME!
diff --git a/index.rst b/index.rst
@@ -68,6 +68,7 @@ and overall usage of the different Taler components in text and video formats.
taler-merchant-manual
taler-merchant-pos-terminal
+ taler-paivana-manual
.. toctree::
:maxdepth: 1
@@ -136,4 +137,3 @@ and overall usage of the different Taler components in text and video formats.
:caption: Other
genindex
-
diff --git a/paivana-httpd-manual.rst b/paivana-httpd-manual.rst
@@ -0,0 +1,575 @@
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2026 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 2.1, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+
+.. _Paivana-httpd:
+
+Paivana-httpd
+=============
+
+This chapter documents the installation and operation of the Paivana
+reverse proxy ``paivana-httpd``. The reverse proxy sits between the
+public Internet and an upstream Web service, intercepting requests
+that have not yet been paid for and presenting the client with a
+GNU Taler paywall. Once a payment has been confirmed by the
+configured GNU Taler merchant backend, ``paivana-httpd`` forwards
+subsequent requests of that client to the upstream service.
+
+The full list of command-line options is documented in
+:manpage:`paivana-httpd(1)`; the configuration file is
+documented in :manpage:`paivana.conf(5)`.
+
+
+Architecture overview
+---------------------
+
+``paivana-httpd`` does not implement any payment logic of its own.
+Instead, every Paivana deployment combines three components:
+
+1. **The upstream web service.** This is the existing HTTP service
+ whose content should be sold (a static website, a cgit service,
+ a REST API, …). It does not need to be modified to
+ work with Paivana.
+2. **A GNU Taler merchant backend** (``taler-merchant-httpd``). The
+ merchant backend manages templates, creates orders, talks to one
+ or more Taler exchanges, and ultimately reports back whether a
+ given order has been paid. See the
+ :ref:`Taler Merchant Backend Operator Manual
+ <taler-merchant-backend-operator-manual>` for full details.
+3. **``paivana-httpd`` itself.** This is the reverse proxy that
+ gates the upstream service. It reads a single
+ :ref:`paivana.conf <Paivana-Configuration>` configuration file
+ that points at both the merchant backend and the upstream
+ service.
+
+Typically a TLS-terminating reverse proxy (Nginx or Apache) is
+deployed in front of ``paivana-httpd`` to handle HTTPS and to route
+multiple virtual hosts; see :ref:`Paivana-ReverseProxy` below.
+
+In normal operation the request flow is:
+
+::
+
+ client ──▶ Nginx/Apache (TLS) ──▶ paivana-httpd ──▶ upstream
+ │
+ ▼
+ taler-merchant-httpd
+ │
+ ▼
+ Taler exchange
+
+
+Installation
+------------
+
+Installing from source
+^^^^^^^^^^^^^^^^^^^^^^
+
+The package sources can be found in our
+`download directory <http://ftpmirror.gnu.org/taler/>`__.
+
+GNU Taler components follow the ``MAJOR.MINOR.MICRO`` version
+scheme. The general rule for compatibility is that ``MAJOR`` and
+``MINOR`` must match across components; exceptions are noted in the
+release notes. For example, ``paivana-httpd`` 1.6.x is expected to
+work with ``taler-merchant-httpd`` 1.6.x. A ``MAJOR`` version of 0
+indicates experimental development; in that case you should always
+run the *latest* releases of every component together.
+
+The following packages must be installed before compiling
+``paivana-httpd``:
+
+- GNUnet (``libgnunetutil``) matching the Taler release
+- GNU Taler exchange libraries (``libtalerexchange``,
+ ``libtalerutil``)
+- GNU Taler merchant client library (``libtalermerchant``)
+- GNU Taler HTTP daemon helpers (``libtalermhd``,
+ ``libtalertemplating``)
+- libmicrohttpd, libcurl, libjansson, libgcrypt, zlib
+
+Build and install with:
+
+.. code-block:: shell-session
+
+ $ ./bootstrap
+ $ ./configure --prefix=$PREFIX
+ $ make
+ $ sudo make install
+
+
+Installing the binary packages on Debian
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. include:: frags/installing-debian.rst
+
+To install ``paivana-httpd`` you can now simply run:
+
+.. code-block:: shell-session
+
+ # apt install paivana-httpd
+
+The package does not perform any deployment-specific configuration
+work; it only sets up the ``paivana-httpd`` system user, the systemd
+service and socket units, and installs example configuration
+snippets for Nginx and Apache under ``/etc/nginx/sites-available/``
+and ``/etc/apache2/sites-available/``. You still must configure the
+HTTP request routing and the Paivana templates as described below.
+
+
+Installing the binary packages on Ubuntu
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. include:: frags/installing-ubuntu.rst
+
+To install ``paivana-httpd``, run:
+
+.. code-block:: shell-session
+
+ # apt install paivana-httpd
+
+As on Debian, the package does not perform any deployment-specific
+configuration work.
+
+
+.. _Paivana-Configuration:
+
+Configuring paivana-httpd
+-------------------------
+
+The main configuration file is ``/etc/paivana/paivana.conf``. Its
+syntax follows the standard GNUnet configuration file format and is
+documented in full in :manpage:`paivana.conf(5)`. Default values
+shipped with the package live under
+``/usr/share/paivana/config.d/``; values in ``paivana.conf``
+override those defaults.
+
+All Paivana-specific keys live in the ``[paivana]`` section. At a
+minimum, the file must specify three things:
+
+- where ``paivana-httpd`` should listen for incoming requests
+ (``SERVE``, ``UNIXPATH`` / ``PORT``);
+- where it should forward paid requests to
+ (``DESTINATION_BASE_URL``);
+- how it should reach the merchant backend
+ (``MERCHANT_BACKEND_URL`` and ``MERCHANT_ACCESS_TOKEN``).
+
+A typical configuration that listens on a UNIX domain socket
+managed by systemd and forwards to a local upstream server looks
+like this:
+
+.. code-block:: ini
+
+ [paivana]
+ # Listen on the socket provided by paivana-httpd.socket.
+ SERVE = unix
+ UNIXPATH = /run/paivana/httpd/paivana-http.sock
+ UNIXPATH_MODE = 660
+
+ # Public base URL of this paywall as seen by clients.
+ # Used when the Host/X-Forwarded-Host headers are unavailable.
+ BASE_URL = https://paywall.example.com/
+
+ # Upstream service that gets proxied after payment.
+ DESTINATION_BASE_URL = http://127.0.0.1:8080/
+
+ # Merchant backend used to create and verify orders.
+ MERCHANT_BACKEND_URL = http://localhost:9966/
+ MERCHANT_ACCESS_TOKEN = secret-token:CHANGE-ME
+
+ # Stable secret used to MAC the access cookie.
+ # If unset, a random value is generated at every startup,
+ # invalidating all previously issued cookies.
+ SECRET = please-change-this-to-a-long-random-value
+
+ # Resources that should never trigger the paywall, e.g.
+ # logos, stylesheets or favicons.
+ WHITELIST = ^/(favicon\.ico|assets/.*|robots\.txt)$
+
+The exhaustive list of supported keys (``SERVE``, ``PORT``,
+``BIND_TO``, ``UNIXPATH``, ``UNIXPATH_MODE``, ``BASE_URL``,
+``DESTINATION_BASE_URL``, ``MERCHANT_BACKEND_URL``,
+``MERCHANT_BACKEND_UNIX_PATH``, ``MERCHANT_ACCESS_TOKEN``,
+``SECRET``, ``WHITELIST``) is documented in
+:manpage:`paivana.conf(5)`.
+
+If you reach the merchant backend over a UNIX domain socket on the
+same host (recommended for a single-machine deployment), replace
+the ``MERCHANT_BACKEND_URL`` block with:
+
+.. code-block:: ini
+
+ MERCHANT_BACKEND_URL = http://localhost/
+ MERCHANT_BACKEND_UNIX_PATH = /run/taler-merchant/merchant.sock
+
+.. note::
+
+ ``MERCHANT_ACCESS_TOKEN`` and ``SECRET`` are sensitive values.
+ Make sure ``paivana.conf`` is only readable by the
+ ``paivana-httpd`` user. The Debian package installs the file
+ accordingly.
+
+When ``paivana-httpd`` runs behind a trusted reverse proxy
+(Nginx/Apache), pass ``-f`` / ``--respect-forwarded-headers`` in the
+systemd unit's ``ExecStart=`` so the real client address is taken
+from ``X-Forwarded-For``. See :manpage:`paivana-httpd(1)` for the
+remaining command-line flags (in particular ``-g`` to require only
+a single payment per site and ``-n`` to disable the paywall for
+debugging).
+
+
+Starting and stopping the service
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The Debian/Ubuntu package ships a socket-activated systemd unit.
+After editing ``/etc/paivana/paivana.conf`` enable and start it:
+
+.. code-block:: shell-session
+
+ # systemctl enable --now paivana-httpd.socket
+ # systemctl status paivana-httpd
+
+The socket listens on ``/run/paivana/httpd/paivana-http.sock`` with
+group ``www-data``, which lets a co-located Nginx or Apache talk to
+the daemon without granting it broader filesystem access. Logs are
+sent to the journal:
+
+.. code-block:: shell-session
+
+ # journalctl -u paivana-httpd -f
+
+
+.. _Paivana-Templates:
+
+Configuring Paivana templates
+-----------------------------
+
+``paivana-httpd`` does not store any per-site pricing or URL-matching rules
+itself. Instead, all rules are expressed as :ref:`merchant templates
+<template>` of type ``paivana`` in the merchant backend. When
+``paivana-httpd`` starts up it asks the merchant backend for every template
+configured for the instance identified by ``MERCHANT_BACKEND_URL`` and uses
+the ``website_regex`` field of each template to decide which template (and
+therefore which payment options) applies to an incoming request URL.
+
+The corresponding REST API is documented in detail in the
+:ref:`Merchant Backend HTTP API <merchant-api>`; see in particular
+the
+`POST /private/templates
+<https://docs.taler.net/core/api-merchant.html#post--private-templates>`__
+endpoint and the
+:ts:type:`TemplateContractPaivana` definition.
+
+Prerequisites
+^^^^^^^^^^^^^
+
+Before creating a template you need:
+
+- a running ``taler-merchant-httpd`` (see the
+ :ref:`Launching-the-backend` section of the merchant manual);
+- a merchant :ref:`instance <Instance-setup>` with at least one
+ configured :ref:`bank account <instance-bank-account>`;
+- the access token of that instance (used as
+ ``MERCHANT_ACCESS_TOKEN`` in ``paivana.conf``).
+
+In the examples below we assume the merchant backend is reachable
+at ``http://localhost:9966/``, the default instance is ``default``,
+its access token is ``secret-token:sandbox`` and the currency is
+``KUDOS``. Adjust the URLs, tokens and amounts to match your
+deployment. The
+`src/backend/test.sh
+<https://git.taler.net/paivana.git/tree/src/backend/test.sh>`__
+script that ships with Paivana sets up exactly this minimal
+configuration and is a good starting point for experimentation.
+
+Creating a single global template
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The simplest Paivana setup uses one template that matches every
+URL on the site and charges a fixed price. This is the
+configuration created by ``src/backend/test.sh``:
+
+.. code-block:: bash
+
+ $ curl -X POST http://localhost:9966/private/templates \
+ -H 'Authorization: Bearer secret-token:sandbox' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "template_id": "paivana",
+ "template_description": "A Paivana template",
+ "template_contract": {
+ "template_type": "paivana",
+ "summary": "Access to example.com",
+ "website_regex": ".*",
+ "choices": [ { "amount": "KUDOS:1" } ]
+ }
+ }'
+
+The ``template_type`` must be ``"paivana"``: this allows
+``paivana-httpd`` to pick the template up at startup and
+also enables some required logic in the merchant backend. The
+``website_regex`` is a POSIX extended regular expression that is
+matched against the request URL; ``.*`` covers everything. Each
+entry in ``choices`` describes one way the client may pay and is an
+:ts:type:`OrderChoice` object (so the paywall can also support
+the use of subscription tokens, discount coupons, etc.).
+
+A successful create returns HTTP ``204 No Content``. After
+creating the template, (re)start ``paivana-httpd`` so that it
+re-reads the template list:
+
+.. code-block:: shell-session
+
+ # systemctl restart paivana-httpd
+
+Multiple templates with URL-specific pricing
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When a single site contains content with different prices, define one template
+per price bucket and use ``website_regex`` to scope each template to the
+matching URLs. When several templates match the same URL ``paivana-httpd``
+picks the first one if finds that matches. Be careful: if multiple templates
+match a URL, the result is non-deterministic!
+
+For example, a news site might charge 2 KUDOS for premium articles
+and 50 cents (``KUDOS:0.5``) for standard articles:
+
+.. code-block:: bash
+
+ $ curl -X POST http://localhost:9966/private/templates \
+ -H 'Authorization: Bearer secret-token:sandbox' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "template_id": "premium",
+ "template_description": "Premium long-form articles",
+ "template_contract": {
+ "template_type": "paivana",
+ "summary": "Premium article on example.com",
+ "website_regex": "^/premium/.*",
+ "choices": [ { "amount": "KUDOS:2" } ]
+ }
+ }'
+
+ $ curl -X POST http://localhost:9966/private/templates \
+ -H 'Authorization: Bearer secret-token:sandbox' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "template_id": "default",
+ "template_description": "Standard articles",
+ "template_contract": {
+ "template_type": "paivana",
+ "summary": "Standard article on example.com",
+ "website_regex": "^/standard/.*",
+ "choices": [ { "amount": "KUDOS:0.5" } ]
+ }
+ }'
+
+Offering multiple payment options
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``choices`` array lets a single template offer several mutually exclusive
+ways to pay. A common pattern is to accept either a cash payment or to sell a
+subscription; the wallet shows both options and the customer picks one. The
+third option, where the customer already has a subscription, will be used
+automatically by the wallet for subscribers and the customer will not even
+have to click to bypass the paywall as a subscriber. See the merchant manual
+for the details of :ref:`OrderChoice <template-choice>` objects.
+
+.. code-block:: bash
+
+ $ curl -X POST http://localhost:9966/private/templates \
+ -H 'Authorization: Bearer secret-token:sandbox' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "template_id": "article",
+ "template_description": "Single article, paid or via subscription",
+ "template_contract": {
+ "template_type": "paivana",
+ "summary": "Article on example.com",
+ "website_regex": ".*",
+ "choices": [
+ { "amount": "KUDOS:1",
+ "description": "Pay per article" },
+ { "amount": "KUDOS:100",
+ "description": "Buy subscription",
+ "outputs": [ { "token": "monthly-subscription" } ] },
+ { "amount": "KUDOS:0",
+ "description": "Use my subscription",
+ "inputs": [ { "token": "monthly-subscription" } ],
+ "outputs": [ { "token": "monthly-subscription" } ] }
+ ]
+ }
+ }'
+
+Managing templates
+^^^^^^^^^^^^^^^^^^
+
+Templates can be listed, updated and deleted through the merchant
+backend's REST API or through the merchant backend SPA at
+``$MERCHANT_BACKEND_URL/``. See the merchant manual section on
+:ref:`templates <template>` for details, and the API reference for
+the relevant endpoints:
+
+- `GET /private/templates
+ <https://docs.taler.net/core/api-merchant.html#get--private-templates>`__ —
+ list all templates of the instance;
+- `PATCH /private/templates/$TEMPLATE_ID
+ <https://docs.taler.net/core/api-merchant.html#patch--private-templates-$TEMPLATE_ID>`__ —
+ update a template;
+- `DELETE /private/templates/$TEMPLATE_ID
+ <https://docs.taler.net/core/api-merchant.html#delete--private-templates-$TEMPLATE_ID>`__ —
+ remove a template.
+
+After any change, restart ``paivana-httpd`` so the new template
+list takes effect.
+
+
+.. _Paivana-ReverseProxy:
+
+Reverse proxy configuration
+---------------------------
+
+``paivana-httpd`` itself speaks plain HTTP on a UNIX socket (or a
+local TCP port). In production it is often run behind an Internet-facing
+reverse proxy that terminates TLS and forwards requests to the
+Paivana socket. This section gives minimal working examples for
+both Nginx and Apache. The same approach is used for the merchant
+backend; see the merchant manual's
+:ref:`reverse-proxy-configuration` section for additional
+discussion.
+
+The examples assume the public domain is ``example.com``,
+that ``paivana-httpd`` is socket-activated by the shipped
+``paivana-httpd.socket`` unit (so its listening socket lives at
+``/run/paivana/httpd/paivana-http.sock``) and that TLS termination
+happens at the reverse proxy.
+
+.. tab-set::
+
+ .. tab-item:: Nginx
+
+ Place the snippet below in
+ ``/etc/nginx/sites-available/example.com`` (the
+ Debian package installs a starter template under
+ ``/etc/nginx/sites-available/paivana``), then enable it via
+ ``ln -s ../sites-available/example.com
+ /etc/nginx/sites-enabled/`` and reload Nginx
+ (``systemctl reload nginx``).
+
+ .. code-block:: nginx
+
+ server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+ server_name example.com;
+
+ ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
+
+ location / {
+ proxy_pass http://unix:/run/paivana/httpd/paivana-http.sock;
+ proxy_redirect off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header X-Forwarded-Host $host;
+ proxy_set_header X-Forwarded-Proto https;
+ }
+ }
+
+ server {
+ listen 80;
+ listen [::]:80;
+ server_name example.com;
+ return 301 https://$host$request_uri;
+ }
+
+ Make sure ``paivana-httpd`` is started with
+ ``--respect-forwarded-headers`` (see
+ :manpage:`paivana-httpd(1)`) so the ``X-Forwarded-For``
+ header set above is honoured.
+
+ .. tab-item:: Apache
+
+ Enable the required modules once:
+
+ .. code-block:: shell-session
+
+ # a2enmod proxy proxy_http headers ssl
+ # systemctl reload apache2
+
+ Then drop the following into
+ ``/etc/apache2/sites-available/example.com.conf``
+ (the Debian package installs a starter template at
+ ``/etc/apache2/sites-available/paivana.conf``), enable it
+ with ``a2ensite example.com`` and reload Apache.
+
+ .. code-block:: apacheconf
+
+ <VirtualHost *:80>
+ ServerName example.com
+ Redirect permanent / https://example.com/
+ </VirtualHost>
+
+ <VirtualHost *:443>
+ ServerName example.com
+
+ SSLEngine on
+ SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
+ SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
+
+ <Location "/">
+ ProxyPass "unix:/run/paivana/httpd/paivana-http.sock|http://example.com/"
+ ProxyPassReverse "unix:/run/paivana/httpd/paivana-http.sock|http://example.com/"
+ RequestHeader set X-Forwarded-Proto "https"
+ RequestHeader set X-Forwarded-Host "example.com"
+ </Location>
+ </VirtualHost>
+
+ As with Nginx, run ``paivana-httpd`` with
+ ``--respect-forwarded-headers`` so that the client IP is
+ taken from ``X-Forwarded-For``.
+
+If you operate both Paivana and the merchant backend on the same
+host, you typically expose them under two different hostnames (e.g.
+``example.com`` and ``backend.example.com``); the merchant
+backend must *never* be proxied through ``paivana-httpd``, only
+the upstream content service should be.
+
+
+Verifying the setup
+-------------------
+
+After completing the steps above, a quick smoke test is to request
+a paywalled URL with ``curl``:
+
+.. code-block:: shell-session
+
+ $ curl -i https://example.com/some-article
+
+An unpaid request should return ``HTTP/1.1 402 Payment Required`` together
+with a Taler-formatted paywall body containing the ``taler://pay/...`` URI of
+the freshly created order. Paying that order with any GNU Taler wallet (see
+the `Wallet documentation <https://docs.taler.net/wallet/>`__) and
+re-requesting the URL from the same client should then yield the upstream
+content unchanged. If the page is run in a browser, the client-side
+JavaScript should automatically trigger the required reload of the page after
+the wallet made the payment.
+
+For interactive debugging, ``paivana-httpd -n`` disables the
+paywall and turns the daemon into a transparent reverse proxy;
+this is useful to confirm that the network plumbing to the
+upstream service works before involving the merchant backend.
+See :manpage:`paivana-httpd(1)` for the other runtime flags.
diff --git a/taler-paivana-manual.rst b/taler-paivana-manual.rst
@@ -14,7 +14,8 @@
You should have received a copy of the GNU Affero General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- @author Martin Schanzenbach
+ @author Christian Grothoff
+
Paivana Operator Manual
#######################
@@ -78,578 +79,8 @@ and configured to process orders. When setting up the respective
Paivana service, you must have the base URL, username and password
of the selected merchant backend at hand.
+.. include:: paivana-httpd-manual.rst
-.. _Paivana-httpd:
-
-Paivana-httpd
-=============
-
-This chapter documents the installation and operation of the Paivana
-reverse proxy ``paivana-httpd``. The reverse proxy sits between the
-public Internet and an upstream Web service, intercepting requests
-that have not yet been paid for and presenting the client with a
-GNU Taler paywall. Once a payment has been confirmed by the
-configured GNU Taler merchant backend, ``paivana-httpd`` forwards
-subsequent requests of that client to the upstream service.
-
-The full list of command-line options is documented in
-:manpage:`paivana-httpd(1)`; the configuration file is
-documented in :manpage:`paivana.conf(5)`.
-
-
-Architecture overview
----------------------
-
-``paivana-httpd`` does not implement any payment logic of its own.
-Instead, every Paivana deployment combines three components:
-
-1. **The upstream web service.** This is the existing HTTP service
- whose content should be sold (a static website, a cgit service,
- a REST API, …). It does not need to be modified to
- work with Paivana.
-2. **A GNU Taler merchant backend** (``taler-merchant-httpd``). The
- merchant backend manages templates, creates orders, talks to one
- or more Taler exchanges, and ultimately reports back whether a
- given order has been paid. See the
- :ref:`Taler Merchant Backend Operator Manual
- <taler-merchant-backend-operator-manual>` for full details.
-3. **``paivana-httpd`` itself.** This is the reverse proxy that
- gates the upstream service. It reads a single
- :ref:`paivana.conf <Paivana-Configuration>` configuration file
- that points at both the merchant backend and the upstream
- service.
-
-Typically a TLS-terminating reverse proxy (Nginx or Apache) is
-deployed in front of ``paivana-httpd`` to handle HTTPS and to route
-multiple virtual hosts; see :ref:`Paivana-ReverseProxy` below.
-
-In normal operation the request flow is:
-
-::
-
- client ──▶ Nginx/Apache (TLS) ──▶ paivana-httpd ──▶ upstream
- │
- ▼
- taler-merchant-httpd
- │
- ▼
- Taler exchange
-
-
-Installation
-------------
-
-Installing from source
-^^^^^^^^^^^^^^^^^^^^^^
-
-The package sources can be found in our
-`download directory <http://ftpmirror.gnu.org/taler/>`__.
-
-GNU Taler components follow the ``MAJOR.MINOR.MICRO`` version
-scheme. The general rule for compatibility is that ``MAJOR`` and
-``MINOR`` must match across components; exceptions are noted in the
-release notes. For example, ``paivana-httpd`` 1.6.x is expected to
-work with ``taler-merchant-httpd`` 1.6.x. A ``MAJOR`` version of 0
-indicates experimental development; in that case you should always
-run the *latest* releases of every component together.
-
-The following packages must be installed before compiling
-``paivana-httpd``:
-
-- GNUnet (``libgnunetutil``) matching the Taler release
-- GNU Taler exchange libraries (``libtalerexchange``,
- ``libtalerutil``)
-- GNU Taler merchant client library (``libtalermerchant``)
-- GNU Taler HTTP daemon helpers (``libtalermhd``,
- ``libtalertemplating``)
-- libmicrohttpd, libcurl, libjansson, libgcrypt, zlib
-
-Build and install with:
-
-.. code-block:: shell-session
-
- $ ./bootstrap
- $ ./configure --prefix=$PREFIX
- $ make
- $ sudo make install
-
-
-Installing the binary packages on Debian
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. include:: frags/installing-debian.rst
-
-To install ``paivana-httpd`` you can now simply run:
-
-.. code-block:: shell-session
-
- # apt install paivana-httpd
-
-The package does not perform any deployment-specific configuration
-work; it only sets up the ``paivana-httpd`` system user, the systemd
-service and socket units, and installs example configuration
-snippets for Nginx and Apache under ``/etc/nginx/sites-available/``
-and ``/etc/apache2/sites-available/``. You still must configure the
-HTTP request routing and the Paivana templates as described below.
-
-
-Installing the binary packages on Ubuntu
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. include:: frags/installing-ubuntu.rst
-
-To install ``paivana-httpd``, run:
-
-.. code-block:: shell-session
-
- # apt install paivana-httpd
-
-As on Debian, the package does not perform any deployment-specific
-configuration work.
-
-
-.. _Paivana-Configuration:
-
-Configuring paivana-httpd
--------------------------
-
-The main configuration file is ``/etc/paivana/paivana.conf``. Its
-syntax follows the standard GNUnet configuration file format and is
-documented in full in :manpage:`paivana.conf(5)`. Default values
-shipped with the package live under
-``/usr/share/paivana/config.d/``; values in ``paivana.conf``
-override those defaults.
-
-All Paivana-specific keys live in the ``[paivana]`` section. At a
-minimum, the file must specify three things:
-
-- where ``paivana-httpd`` should listen for incoming requests
- (``SERVE``, ``UNIXPATH`` / ``PORT``);
-- where it should forward paid requests to
- (``DESTINATION_BASE_URL``);
-- how it should reach the merchant backend
- (``MERCHANT_BACKEND_URL`` and ``MERCHANT_ACCESS_TOKEN``).
-
-A typical configuration that listens on a UNIX domain socket
-managed by systemd and forwards to a local upstream server looks
-like this:
-
-.. code-block:: ini
-
- [paivana]
- # Listen on the socket provided by paivana-httpd.socket.
- SERVE = unix
- UNIXPATH = /run/paivana/httpd/paivana-http.sock
- UNIXPATH_MODE = 660
-
- # Public base URL of this paywall as seen by clients.
- # Used when the Host/X-Forwarded-Host headers are unavailable.
- BASE_URL = https://paywall.example.com/
-
- # Upstream service that gets proxied after payment.
- DESTINATION_BASE_URL = http://127.0.0.1:8080/
-
- # Merchant backend used to create and verify orders.
- MERCHANT_BACKEND_URL = http://localhost:9966/
- MERCHANT_ACCESS_TOKEN = secret-token:CHANGE-ME
-
- # Stable secret used to MAC the access cookie.
- # If unset, a random value is generated at every startup,
- # invalidating all previously issued cookies.
- SECRET = please-change-this-to-a-long-random-value
-
- # Resources that should never trigger the paywall, e.g.
- # logos, stylesheets or favicons.
- WHITELIST = ^/(favicon\.ico|assets/.*|robots\.txt)$
-
-The exhaustive list of supported keys (``SERVE``, ``PORT``,
-``BIND_TO``, ``UNIXPATH``, ``UNIXPATH_MODE``, ``BASE_URL``,
-``DESTINATION_BASE_URL``, ``MERCHANT_BACKEND_URL``,
-``MERCHANT_BACKEND_UNIX_PATH``, ``MERCHANT_ACCESS_TOKEN``,
-``SECRET``, ``WHITELIST``) is documented in
-:manpage:`paivana.conf(5)`.
-
-If you reach the merchant backend over a UNIX domain socket on the
-same host (recommended for a single-machine deployment), replace
-the ``MERCHANT_BACKEND_URL`` block with:
-
-.. code-block:: ini
-
- MERCHANT_BACKEND_URL = http://localhost/
- MERCHANT_BACKEND_UNIX_PATH = /run/taler-merchant/merchant.sock
-
-.. note::
-
- ``MERCHANT_ACCESS_TOKEN`` and ``SECRET`` are sensitive values.
- Make sure ``paivana.conf`` is only readable by the
- ``paivana-httpd`` user. The Debian package installs the file
- accordingly.
-
-When ``paivana-httpd`` runs behind a trusted reverse proxy
-(Nginx/Apache), pass ``-f`` / ``--respect-forwarded-headers`` in the
-systemd unit's ``ExecStart=`` so the real client address is taken
-from ``X-Forwarded-For``. See :manpage:`paivana-httpd(1)` for the
-remaining command-line flags (in particular ``-g`` to require only
-a single payment per site and ``-n`` to disable the paywall for
-debugging).
-
-
-Starting and stopping the service
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The Debian/Ubuntu package ships a socket-activated systemd unit.
-After editing ``/etc/paivana/paivana.conf`` enable and start it:
-
-.. code-block:: shell-session
-
- # systemctl enable --now paivana-httpd.socket
- # systemctl status paivana-httpd
-
-The socket listens on ``/run/paivana/httpd/paivana-http.sock`` with
-group ``www-data``, which lets a co-located Nginx or Apache talk to
-the daemon without granting it broader filesystem access. Logs are
-sent to the journal:
-
-.. code-block:: shell-session
-
- # journalctl -u paivana-httpd -f
-
-
-.. _Paivana-Templates:
-
-Configuring Paivana templates
------------------------------
-
-``paivana-httpd`` does not store any per-site pricing or URL-matching rules
-itself. Instead, all rules are expressed as :ref:`merchant templates
-<template>` of type ``paivana`` in the merchant backend. When
-``paivana-httpd`` starts up it asks the merchant backend for every template
-configured for the instance identified by ``MERCHANT_BACKEND_URL`` and uses
-the ``website_regex`` field of each template to decide which template (and
-therefore which payment options) applies to an incoming request URL.
-
-The corresponding REST API is documented in detail in the
-:ref:`Merchant Backend HTTP API <merchant-api>`; see in particular
-the
-`POST /private/templates
-<https://docs.taler.net/core/api-merchant.html#post--private-templates>`__
-endpoint and the
-:ts:type:`TemplateContractPaivana` definition.
-
-Prerequisites
-^^^^^^^^^^^^^
-
-Before creating a template you need:
-
-- a running ``taler-merchant-httpd`` (see the
- :ref:`Launching-the-backend` section of the merchant manual);
-- a merchant :ref:`instance <Instance-setup>` with at least one
- configured :ref:`bank account <instance-bank-account>`;
-- the access token of that instance (used as
- ``MERCHANT_ACCESS_TOKEN`` in ``paivana.conf``).
-
-In the examples below we assume the merchant backend is reachable
-at ``http://localhost:9966/``, the default instance is ``default``,
-its access token is ``secret-token:sandbox`` and the currency is
-``KUDOS``. Adjust the URLs, tokens and amounts to match your
-deployment. The
-`src/backend/test.sh
-<https://git.taler.net/paivana.git/tree/src/backend/test.sh>`__
-script that ships with Paivana sets up exactly this minimal
-configuration and is a good starting point for experimentation.
-
-Creating a single global template
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The simplest Paivana setup uses one template that matches every
-URL on the site and charges a fixed price. This is the
-configuration created by ``src/backend/test.sh``:
-
-.. code-block:: bash
-
- $ curl -X POST http://localhost:9966/private/templates \
- -H 'Authorization: Bearer secret-token:sandbox' \
- -H 'Content-Type: application/json' \
- -d '{
- "template_id": "paivana",
- "template_description": "A Paivana template",
- "template_contract": {
- "template_type": "paivana",
- "summary": "Access to example.com",
- "website_regex": ".*",
- "choices": [ { "amount": "KUDOS:1" } ]
- }
- }'
-
-The ``template_type`` must be ``"paivana"``: this allows
-``paivana-httpd`` to pick the template up at startup and
-also enables some required logic in the merchant backend. The
-``website_regex`` is a POSIX extended regular expression that is
-matched against the request URL; ``.*`` covers everything. Each
-entry in ``choices`` describes one way the client may pay and is an
-:ts:type:`OrderChoice` object (so the paywall can also support
-the use of subscription tokens, discount coupons, etc.).
-
-A successful create returns HTTP ``204 No Content``. After
-creating the template, (re)start ``paivana-httpd`` so that it
-re-reads the template list:
-
-.. code-block:: shell-session
-
- # systemctl restart paivana-httpd
-
-Multiple templates with URL-specific pricing
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-When a single site contains content with different prices, define one template
-per price bucket and use ``website_regex`` to scope each template to the
-matching URLs. When several templates match the same URL ``paivana-httpd``
-picks the first one if finds that matches. Be careful: if multiple templates
-match a URL, the result is non-deterministic!
-
-For example, a news site might charge 2 KUDOS for premium articles
-and 50 cents (``KUDOS:0.5``) for standard articles:
-
-.. code-block:: bash
-
- $ curl -X POST http://localhost:9966/private/templates \
- -H 'Authorization: Bearer secret-token:sandbox' \
- -H 'Content-Type: application/json' \
- -d '{
- "template_id": "premium",
- "template_description": "Premium long-form articles",
- "template_contract": {
- "template_type": "paivana",
- "summary": "Premium article on example.com",
- "website_regex": "^/premium/.*",
- "choices": [ { "amount": "KUDOS:2" } ]
- }
- }'
-
- $ curl -X POST http://localhost:9966/private/templates \
- -H 'Authorization: Bearer secret-token:sandbox' \
- -H 'Content-Type: application/json' \
- -d '{
- "template_id": "default",
- "template_description": "Standard articles",
- "template_contract": {
- "template_type": "paivana",
- "summary": "Standard article on example.com",
- "website_regex": "^/standard/.*",
- "choices": [ { "amount": "KUDOS:0.5" } ]
- }
- }'
-
-Offering multiple payment options
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``choices`` array lets a single template offer several mutually exclusive
-ways to pay. A common pattern is to accept either a cash payment or to sell a
-subscription; the wallet shows both options and the customer picks one. The
-third option, where the customer already has a subscription, will be used
-automatically by the wallet for subscribers and the customer will not even
-have to click to bypass the paywall as a subscriber. See the merchant manual
-for the details of :ref:`OrderChoice <template-choice>` objects.
-
-.. code-block:: bash
-
- $ curl -X POST http://localhost:9966/private/templates \
- -H 'Authorization: Bearer secret-token:sandbox' \
- -H 'Content-Type: application/json' \
- -d '{
- "template_id": "article",
- "template_description": "Single article, paid or via subscription",
- "template_contract": {
- "template_type": "paivana",
- "summary": "Article on example.com",
- "website_regex": ".*",
- "choices": [
- { "amount": "KUDOS:1",
- "description": "Pay per article" },
- { "amount": "KUDOS:100",
- "description": "Buy subscription",
- "outputs": [ { "token": "monthly-subscription" } ] },
- { "amount": "KUDOS:0",
- "description": "Use my subscription",
- "inputs": [ { "token": "monthly-subscription" } ],
- "outputs": [ { "token": "monthly-subscription" } ] }
- ]
- }
- }'
-
-Managing templates
-^^^^^^^^^^^^^^^^^^
-
-Templates can be listed, updated and deleted through the merchant
-backend's REST API or through the merchant backend SPA at
-``$MERCHANT_BACKEND_URL/``. See the merchant manual section on
-:ref:`templates <template>` for details, and the API reference for
-the relevant endpoints:
-
-- `GET /private/templates
- <https://docs.taler.net/core/api-merchant.html#get--private-templates>`__ —
- list all templates of the instance;
-- `PATCH /private/templates/$TEMPLATE_ID
- <https://docs.taler.net/core/api-merchant.html#patch--private-templates-$TEMPLATE_ID>`__ —
- update a template;
-- `DELETE /private/templates/$TEMPLATE_ID
- <https://docs.taler.net/core/api-merchant.html#delete--private-templates-$TEMPLATE_ID>`__ —
- remove a template.
-
-After any change, restart ``paivana-httpd`` so the new template
-list takes effect.
-
-
-.. _Paivana-ReverseProxy:
-
-Reverse proxy configuration
----------------------------
-
-``paivana-httpd`` itself speaks plain HTTP on a UNIX socket (or a
-local TCP port). In production it is often run behind an Internet-facing
-reverse proxy that terminates TLS and forwards requests to the
-Paivana socket. This section gives minimal working examples for
-both Nginx and Apache. The same approach is used for the merchant
-backend; see the merchant manual's
-:ref:`reverse-proxy-configuration` section for additional
-discussion.
-
-The examples assume the public domain is ``example.com``,
-that ``paivana-httpd`` is socket-activated by the shipped
-``paivana-httpd.socket`` unit (so its listening socket lives at
-``/run/paivana/httpd/paivana-http.sock``) and that TLS termination
-happens at the reverse proxy.
-
-.. tab-set::
-
- .. tab-item:: Nginx
-
- Place the snippet below in
- ``/etc/nginx/sites-available/example.com`` (the
- Debian package installs a starter template under
- ``/etc/nginx/sites-available/paivana``), then enable it via
- ``ln -s ../sites-available/example.com
- /etc/nginx/sites-enabled/`` and reload Nginx
- (``systemctl reload nginx``).
-
- .. code-block:: nginx
-
- server {
- listen 443 ssl http2;
- listen [::]:443 ssl http2;
- server_name example.com;
-
- ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
-
- location / {
- proxy_pass http://unix:/run/paivana/httpd/paivana-http.sock;
- proxy_redirect off;
- proxy_set_header Host $host;
- proxy_set_header X-Forwarded-For $remote_addr;
- proxy_set_header X-Forwarded-Host $host;
- proxy_set_header X-Forwarded-Proto https;
- }
- }
-
- server {
- listen 80;
- listen [::]:80;
- server_name example.com;
- return 301 https://$host$request_uri;
- }
-
- Make sure ``paivana-httpd`` is started with
- ``--respect-forwarded-headers`` (see
- :manpage:`paivana-httpd(1)`) so the ``X-Forwarded-For``
- header set above is honoured.
-
- .. tab-item:: Apache
-
- Enable the required modules once:
-
- .. code-block:: shell-session
-
- # a2enmod proxy proxy_http headers ssl
- # systemctl reload apache2
-
- Then drop the following into
- ``/etc/apache2/sites-available/example.com.conf``
- (the Debian package installs a starter template at
- ``/etc/apache2/sites-available/paivana.conf``), enable it
- with ``a2ensite example.com`` and reload Apache.
-
- .. code-block:: apacheconf
-
- <VirtualHost *:80>
- ServerName example.com
- Redirect permanent / https://example.com/
- </VirtualHost>
-
- <VirtualHost *:443>
- ServerName example.com
-
- SSLEngine on
- SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
- SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
-
- <Location "/">
- ProxyPass "unix:/run/paivana/httpd/paivana-http.sock|http://example.com/"
- ProxyPassReverse "unix:/run/paivana/httpd/paivana-http.sock|http://example.com/"
- RequestHeader set X-Forwarded-Proto "https"
- RequestHeader set X-Forwarded-Host "example.com"
- </Location>
- </VirtualHost>
-
- As with Nginx, run ``paivana-httpd`` with
- ``--respect-forwarded-headers`` so that the client IP is
- taken from ``X-Forwarded-For``.
-
-If you operate both Paivana and the merchant backend on the same
-host, you typically expose them under two different hostnames (e.g.
-``example.com`` and ``backend.example.com``); the merchant
-backend must *never* be proxied through ``paivana-httpd``, only
-the upstream content service should be.
-
-
-Verifying the setup
--------------------
-
-After completing the steps above, a quick smoke test is to request
-a paywalled URL with ``curl``:
-
-.. code-block:: shell-session
-
- $ curl -i https://example.com/some-article
-
-An unpaid request should return ``HTTP/1.1 402 Payment Required`` together
-with a Taler-formatted paywall body containing the ``taler://pay/...`` URI of
-the freshly created order. Paying that order with any GNU Taler wallet (see
-the `Wallet documentation <https://docs.taler.net/wallet/>`__) and
-re-requesting the URL from the same client should then yield the upstream
-content unchanged. If the page is run in a browser, the client-side
-JavaScript should automatically trigger the required reload of the page after
-the wallet made the payment.
-
-For interactive debugging, ``paivana-httpd -n`` disables the
-paywall and turns the daemon into a transparent reverse proxy;
-this is useful to confirm that the network plumbing to the
-upstream service works before involving the merchant backend.
-See :manpage:`paivana-httpd(1)` for the other runtime flags.
-
-
-Drupal integration
-==================
-
-This chapter documents the installation and operation of the
-Drupal Paivana module.
-
-FIXME!
-
-Wordpress integration
-=====================
-
-This chapter documents the installation and operation of the
-Wordpress Paivana module.
+.. include:: drupal-paivana-manual.rst
-FIXME!
+.. include:: wordpress-paivana-manual.rst
diff --git a/wordpress-paivana-manual.rst b/wordpress-paivana-manual.rst
@@ -0,0 +1,28 @@
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2026 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 2.1, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+
+.. _wordpress-paivana:
+
+
+Wordpress integration
+=====================
+
+This chapter documents the installation and operation of the
+Wordpress Paivana module.
+
+FIXME!