paivana

HTTP paywall reverse proxy
Log | Files | Refs | Submodules | README | LICENSE

README (6464B)


      1 Paivana
      2 =======
      3 
      4 Paivana is an HTTP reverse proxy that gates access to a target website
      5 behind a GNU Taler payment.  Unpaid visitors receive a paywall page
      6 where they can pay using a GNU Taler wallet; once payment is confirmed
      7 the request is forwarded transparently to the configured upstream
      8 server.
      9 
     10 The sole binary is `paivana-httpd`.
     11 
     12 
     13 How it works
     14 ------------
     15 
     16 0. `paivana-httpd` learns prices from the Paivana templates configured
     17    in the taler-merchant-backend.  Paivana templates include a regular
     18    expression which determines the set of pages the template applies to.
     19 1. An HTTP client accesses a page at `paivana-httpd`.
     20 2. If the paywall is enabled for the respective URL and no valid access
     21    cookie is present, `paivana-httpd` redirects the browser to
     22    a static paywall HTML page (customizable Mustache template)
     23    referencing the payment template.
     24    The page includes a "Paivana" HTTP header to also facilitate agentic
     25    payments.
     26 3. The browser computes a unique payment identifier and
     27    renders a dynamic payment request (taler:// QR code
     28    or link) and long-polls the taler-merchant-backend awaiting
     29    completion of the payment.
     30 4. The user instructs their Taler wallet to complete the payment.
     31 5. The browser notices that the payment is complete and calls back to
     32    `POST /.well-known/paivana` (provided by `paivana-httpd`)
     33    with a reference to the unique payment identifier.
     34 6. `paivana-httpd` verifies the payment with the merchant, sets
     35    an HMAC access cookie, and redirects the browser to the original URL.
     36 7. Requests with a valid cookie are forwarded to the upstream server
     37    via libcurl and the response is streamed back.
     38 
     39 The cookie is an HMAC over `(expiration time, website, client address)` keyed by a
     40 `paivana_secret` derived from the configured `SECRET`.  If `SECRET` is absent,
     41 a random nonce is used and cookies do not survive a restart of `paivana-httpd`
     42 
     43 
     44 Dependencies
     45 ------------
     46 
     47 - GNUnet (libgnunetutil, libgnunetcurl)
     48 - libmicrohttpd
     49 - libcurl >= 7.34.0
     50 - libjansson
     51 - libgcrypt >= 1.6.1
     52 - zlib
     53 - GNU Taler: libtalerutil, libtalermerchant, libtalerexchange,
     54              libtalermhd, libtalertemplating
     55 
     56 
     57 Build
     58 -----
     59 
     60 The project uses Meson but supports a GNU build process.
     61 
     62     ./bootstrap
     63     ./configure --prefix=$TARGET
     64     make
     65     sudo make install
     66 
     67 
     68 Configuration
     69 -------------
     70 
     71 Paivana reads an INI-style `.conf` file.  The only section used is
     72 `[paivana]`.  A minimal working configuration:
     73 
     74     [paivana]
     75     DESTINATION_BASE_URL = https://example.com/
     76     MERCHANT_BACKEND_URL  = https://backend.demo.taler.net/instances/sandbox/
     77     MERCHANT_ACCESS_TOKEN = secret-token:sandbox
     78     SERVE = tcp
     79     PORT  = 9967
     80 
     81 ### Required keys
     82 
     83   Key                     Description
     84   ----------------------  -----------------------------------------------------
     85   DESTINATION_BASE_URL    Upstream server to proxy to once payment is confirmed.
     86   MERCHANT_BACKEND_URL    Base URL of the Taler merchant backend.
     87   MERCHANT_ACCESS_TOKEN   Bearer token for all calls to the merchant backend.
     88 
     89 ### Optional keys
     90 
     91   Key       Description
     92   --------  ---------------------------------------------------------------
     93   BASE_URL  Public base URL of Paivana.  Derived from request headers
     94             (X-Forwarded-Host / Host / X-Forwarded-Port) if absent.
     95   SECRET    Stable secret for cookie MAC and Paivana ID derivation.
     96             A random nonce is generated on every startup if absent.
     97   SERVE     `tcp` (default) or `unix` (Unix-domain socket) or `systemd`
     98             (systemd socket activation).
     99   PORT      TCP port, used when SERVE = tcp.
    100   BIND_TO   IP address to bind to; dual-stack wildcard if absent.
    101   UNIXPATH  UNIX path do bind to, used when SERVE = unix.
    102 
    103 
    104 Running
    105 -------
    106 
    107 $ paivana-httpd -c /etc/paivana/paivana.conf
    108 
    109 Pass `-n` / `--no-payment` to bypass the paywall entirely (pure reverse
    110 proxy, useful for testing upstream plumbing).
    111 
    112 The daemon does not serve requests until it has fetched paywall templates
    113 from the merchant backend.  If template loading fails, startup is aborted.
    114 
    115 
    116 Deployment behind a reverse proxy
    117 ----------------------------------
    118 
    119 The recommended production setup runs Paivana over a Unix socket and
    120 places nginx or Apache in front for TLS termination.
    121 
    122 nginx (`/etc/nginx/sites-available/paivana`):
    123 
    124     server {
    125         listen 443 ssl;
    126         server_name example.com;
    127 
    128         location / {
    129             proxy_pass http://unix:/run/paivana/httpd/paivana-http.sock;
    130             proxy_set_header Host $host;
    131         }
    132     }
    133 
    134 Apache (requires mod_proxy and mod_proxy_http):
    135 
    136     <Location "/">
    137         ProxyPass "unix:/var/lib/paivana/httpd/paivana.sock|http://example.com/"
    138     </Location>
    139 
    140 Set `BASE_URL` in the configuration file to the public HTTPS URL so
    141 that redirects and cookie domains are correct.
    142 
    143 
    144 Source layout
    145 -------------
    146 
    147     src/backend/          Main binary and all subsystems
    148       paivana-httpd.c     Entry point, scheduler, global state, shutdown
    149       paivana-httpd_reverse.c   Request-proxying state machine (core)
    150       paivana-httpd_pay.c       POST /.well-known/paivana handler
    151       paivana-httpd_cookie.c    HMAC access-cookie logic
    152       paivana-httpd_templates.c Paywall template loading and rendering
    153       paivana-httpd_helper.c    Client IP / base URL helpers
    154       paivana-httpd_daemon.c    MHD daemon startup
    155       paivana_pd.c              GNUnet project-data descriptor
    156     src/include/platform.h  GNUnet-style platform header (include first)
    157     src/tests/              Automated reverse-proxy tests
    158     contrib/paywall.en.must Default Mustache paywall template
    159     doc/prebuilt/           Git submodule: taler-docs (man pages)
    160 
    161 
    162 Architecture notes
    163 ------------------
    164 
    165 Single-threaded event loop: GNUnet scheduler drives both inbound HTTP
    166 (libmicrohttpd) and outbound requests (libgnunetcurl / libcurl multi).
    167 Running multiple `paivana-httpd` processes on the same port is
    168 supported as the main way to scale-up the system.
    169 
    170 Requests and responses are currently not streamed in the reverse
    171 proxy; as a result, uploads and downloads are currently hard-capped by
    172 the implementation at 40 MiB.  Lower limits for the upload may be
    173 configured.
    174 
    175 The MHD daemon is not started until paywall templates have been fetched
    176 from the merchant backend asynchronously.
    177 
    178 
    179 License
    180 -------
    181 
    182 GNU Affero General Public License version 3 or later.
    183 See COPYING for the full text.
    184 
    185 
    186 Bug reports
    187 -----------
    188 
    189 Please report bugs at https://bugs.taler.net/.