ops: paivana and caddy config refresh

This commit is contained in:
Hernâni Marques 2026-09-09 00:52:54 +02:00
parent d8dbc6242b
commit 56f814a6de
No known key found for this signature in database
74 changed files with 4517 additions and 79 deletions

View file

@ -2,27 +2,32 @@
GNU Taler **paivana-httpd** reverse-proxy paywall (DD 95 / DD 76 style), GOA payments.
One process = one `BASE_URL` + one `DESTINATION_BASE_URL` + one `MERCHANT_BACKEND_URL`.
Shared **image / secrets / entrypoint / conf template**; per-service env sets
`PAIVANA_BASE_URL` + `PAIVANA_DESTINATION_BASE_URL`. Portal on **9025**; app
paywalls on **90289031** (Caddy unchanged). App backends listen loopback only
(`19128` SilverBullet, `19129` Galene HTTP, `19130` CryptPad edge, `19131` Meet).
| Item | Value |
|------|--------|
| Live | `/home/hernani/koopa-paivana/` |
| Containers | `koopa-paivana`, `koopa-paivana-upstream` |
| Containers | `koopa-paivana`, `koopa-paivana-{silverbullet,galene,cryptpad,meet}`, `koopa-paivana-upstream` |
| Image | `localhost/koopa-paivana:latest` (built from `Containerfile`); process **uid 1000** `paivana-httpd` |
| Upstream | `nginxinc/nginx-unprivileged` on **:8080** (not root nginx:80) |
| Host port | **9025** → Caddy `paivana.hacktivism.ch` |
| Currency | **GOA** |
| Upstream | portal: `nginxinc/nginx-unprivileged` on **:8080**; apps via host `172.17.0.1:1912819131` |
| Host ports | **9025** portal; **9028/9029/9030/9031** app paywalls → Caddy |
| Currency | **GOA** (goa-shop); other units need other merchant backends / later instances |
| Merchant | `https://taler.hacktivism.ch/instances/goa-shop/` |
| Template | `paivana` (`template_type: paivana`, amount **`GOA:4200`**, `website_regex: .*`) |
| Access | **`-g`** site-wide: pay once → example upstream free to browse |
| Upstream | example site in `upstream/` (compose service) |
| Template | `paivana` (`template_type: paivana`, amount **`GOA:42`**, `website_regex: .*`) |
| Access | **`-g`** site-wide: pay once → that hostname free to browse |
## Layout
| Path | Role |
|------|------|
| `Containerfile` | Multi-stage: build paivana-httpd from `git.taler.net/paivana` + Taler libs |
| `compose.yml` | `koopa-paivana` + nginx upstream |
| `conf/paivana.conf.template` | Config; secrets substituted at start |
| `entrypoint.sh` | Inject secrets → run `paivana-httpd -g -f` |
| `compose.yml` | portal + 4 app paywalls + nginx upstream (YAML anchor `x-paivana-common`) |
| `conf/paivana.conf.template` | Shared conf; `@BASE_URL@` / `@DESTINATION_BASE_URL@` / secrets at start |
| `entrypoint.sh` | Env + secrets → run `paivana-httpd -g -f` |
| `secrets/` | **not in git** — live only |
| `upstream/` | Protected demo content |
| `container-koopa-paivana.service` | systemd --user oneshot compose up |
@ -90,9 +95,10 @@ extra_hosts:
| Check | Expect |
|-------|--------|
| `curl -si http://127.0.0.1:9025/` | **302**`/.well-known/paivana/templates/paivana#…` |
| `https://paivana.hacktivism.ch/` | **402** paywall HTML + `paivana: taler://pay-template/…` |
| `curl -si http://127.0.0.1:902{8,9,0}/` | **302** same template path (per-host BASE_URL) |
| `https://{paivana,silverbullet,galene,cryptpad,meet}.hacktivism.ch/` | unpaid → **302** `…/templates/paivana#…` (or paywall HTML) |
| monitoring `urls` | `www.paivana` OK |
| e2e (GOA, lokal) | `e2e.paivana` Template-Pay **GOA:4200** (wenn `E2E_PAIVANA=1`) |
| e2e (GOA, lokal) | `e2e.paivana` Template-Pay **GOA:42** (wenn `E2E_PAIVANA=1`) |
---
@ -137,22 +143,27 @@ Flags `-g` (site-wide payment) and `-f` (X-Forwarded-For).
## Merchant template
Create (or replace via PATCH / DELETE+POST — see live merchant API):
```bash
curl -X POST 'https://taler.hacktivism.ch/instances/goa-shop/private/templates' \
-H "Authorization: Bearer secret-token:…" \
-H 'Content-Type: application/json' \
-d '{
"template_id": "paivana",
"template_description": "Paivana paywall (GOA)",
"template_description": "Paivana paywall portal (GOA)",
"template_contract": {
"template_type": "paivana",
"summary": "Access to paivana.hacktivism.ch",
"summary": "Access to paivana.hacktivism.ch portal",
"website_regex": ".*",
"choices": [{ "amount": "GOA:4200", "description": "Unlock example site (then free to browse)" }]
"choices": [{ "amount": "GOA:42", "description": "Unlock portal (cryptpad / galene / silverbullet links)" }]
}
}'
```
goa-shop is GOA-only. TESTPAYSAN / FLOODS / talersticker CHF / stage-CHF need
other `MERCHANT_BACKEND_URL` values (separate Paivana process or later phase).
## Docs
- https://docs.taler.net/taler-paivana-manual.html

View file

@ -1,29 +1,45 @@
# koopa-paivana — host :9025 → Caddy paivana.hacktivism.ch
# koopa-paivana — shared image/secrets/entrypoint for portal + app paywalls
# Live: /home/hernani/koopa-paivana/
#
# Public Caddy targets (unchanged):
# 9025 → portal (paivana.hacktivism.ch)
# 9028 → paywall silverbullet
# 9029 → paywall galene
# 9030 → paywall cryptpad
# 9031 → paywall meet (Jitsi web)
# App backends (loopback only; see app compose):
# 127.0.0.1:19128 / 19129 / 19130 / 19131
x-paivana-common: &paivana-common
image: localhost/koopa-paivana:latest
restart: unless-stopped
user: "1000:1000"
userns_mode: keep-id
extra_hosts:
- "taler.hacktivism.ch:172.17.0.1"
- "bank.hacktivism.ch:172.17.0.1"
- "exchange.hacktivism.ch:172.17.0.1"
volumes:
- ./conf/paivana.conf.template:/etc/paivana/paivana.conf.template:ro
- ./entrypoint.sh:/usr/local/bin/paivana-entrypoint:ro
- ./secrets/merchant-access-token:/run/secrets/merchant-access-token:ro
- ./secrets/paivana-secret:/run/secrets/paivana-secret:ro
labels:
org.hacktivism.managed_by: koopa-admin
org.hacktivism.currency: GOA
services:
paivana:
<<: *paivana-common
build:
context: .
dockerfile: Containerfile
image: localhost/koopa-paivana:latest
container_name: koopa-paivana
restart: unless-stopped
# Image already USER paivana-httpd; pin numeric + keep-id for host secrets/volumes.
user: "1000:1000"
userns_mode: keep-id
ports:
- "9025:9967"
extra_hosts:
# pasta publishes merchant on host :9010. Prefer fixed IPv4 — host-gateway
# alone still loses to public AAAA and times out from the container.
- "taler.hacktivism.ch:172.17.0.1"
- "bank.hacktivism.ch:172.17.0.1"
- "exchange.hacktivism.ch:172.17.0.1"
volumes:
- ./conf/paivana.conf.template:/etc/paivana/paivana.conf.template:ro
- ./entrypoint.sh:/usr/local/bin/paivana-entrypoint:ro
- ./secrets/merchant-access-token:/run/secrets/merchant-access-token:ro
- ./secrets/paivana-secret:/run/secrets/paivana-secret:ro
environment:
PAIVANA_BASE_URL: https://paivana.hacktivism.ch/
PAIVANA_DESTINATION_BASE_URL: http://upstream:8080/
depends_on:
- upstream
labels:
@ -33,8 +49,68 @@ services:
org.hacktivism.managed_by: koopa-admin
org.hacktivism.currency: GOA
# App paywalls: same image/secrets; BASE/DEST via env. Caddy still hits 90289031.
paivana-silverbullet:
<<: *paivana-common
container_name: koopa-paivana-silverbullet
ports:
- "9028:9967"
environment:
PAIVANA_BASE_URL: https://silverbullet.hacktivism.ch/
PAIVANA_DESTINATION_BASE_URL: http://172.17.0.1:19128/
labels:
org.hacktivism.service: paivana-silverbullet
org.hacktivism.host_port: "9028"
org.hacktivism.site: silverbullet.hacktivism.ch
org.hacktivism.managed_by: koopa-admin
org.hacktivism.currency: GOA
paivana-galene:
<<: *paivana-common
container_name: koopa-paivana-galene
ports:
- "9029:9967"
environment:
PAIVANA_BASE_URL: https://galene.hacktivism.ch/
PAIVANA_DESTINATION_BASE_URL: http://172.17.0.1:19129/
labels:
org.hacktivism.service: paivana-galene
org.hacktivism.host_port: "9029"
org.hacktivism.site: galene.hacktivism.ch
org.hacktivism.managed_by: koopa-admin
org.hacktivism.currency: GOA
paivana-cryptpad:
<<: *paivana-common
container_name: koopa-paivana-cryptpad
ports:
- "9030:9967"
environment:
PAIVANA_BASE_URL: https://cryptpad.hacktivism.ch/
PAIVANA_DESTINATION_BASE_URL: http://172.17.0.1:19130/
labels:
org.hacktivism.service: paivana-cryptpad
org.hacktivism.host_port: "9030"
org.hacktivism.site: cryptpad.hacktivism.ch
org.hacktivism.managed_by: koopa-admin
org.hacktivism.currency: GOA
paivana-meet:
<<: *paivana-common
container_name: koopa-paivana-meet
ports:
- "9031:9967"
environment:
PAIVANA_BASE_URL: https://meet.hacktivism.ch/
PAIVANA_DESTINATION_BASE_URL: http://172.17.0.1:19131/
labels:
org.hacktivism.service: paivana-meet
org.hacktivism.host_port: "9031"
org.hacktivism.site: meet.hacktivism.ch
org.hacktivism.managed_by: koopa-admin
org.hacktivism.currency: GOA
upstream:
# Non-root nginx (listens on 8080). See DESTINATION_BASE_URL in conf template.
image: docker.io/nginxinc/nginx-unprivileged:1.27-alpine
container_name: koopa-paivana-upstream
restart: unless-stopped

View file

@ -1,14 +1,14 @@
# paivana.hacktivism.ch — paywall reverse proxy
# Secrets injected by entrypoint from /run/secrets/
# Shared paivana-httpd conf — BASE/DEST injected by entrypoint (env).
# Secrets injected from /run/secrets/
[paivana]
SERVE = tcp
PORT = 9967
BIND_TO = 0.0.0.0
BASE_URL = https://paivana.hacktivism.ch/
BASE_URL = @BASE_URL@
DESTINATION_BASE_URL = http://upstream:8080/
DESTINATION_BASE_URL = @DESTINATION_BASE_URL@
MERCHANT_BACKEND_URL = https://taler.hacktivism.ch/instances/goa-shop/
MERCHANT_ACCESS_TOKEN = @MERCHANT_ACCESS_TOKEN@

View file

@ -5,6 +5,10 @@ SECRET_FILE="${PAIVANA_SECRET_FILE:-/run/secrets/paivana-secret}"
TEMPLATE="${PAIVANA_CONF_TEMPLATE:-/etc/paivana/paivana.conf.template}"
OUT="${PAIVANA_CONF:-/tmp/paivana.conf}"
# Per-instance (portal + app paywalls share this entrypoint/image).
BASE_URL="${PAIVANA_BASE_URL:-https://paivana.hacktivism.ch/}"
DEST_URL="${PAIVANA_DESTINATION_BASE_URL:-http://upstream:8080/}"
if [ ! -r "$TOKEN_FILE" ]; then
echo "missing merchant token: $TOKEN_FILE" >&2
exit 1
@ -17,10 +21,12 @@ fi
TOKEN=$(tr -d '\n\r' < "$TOKEN_FILE")
SECRET=$(tr -d '\n\r' < "$SECRET_FILE")
awk -v t="$TOKEN" -v s="$SECRET" '
awk -v t="$TOKEN" -v s="$SECRET" -v b="$BASE_URL" -v d="$DEST_URL" '
{
gsub(/@MERCHANT_ACCESS_TOKEN@/, t)
gsub(/@PAIVANA_SECRET@/, s)
gsub(/@BASE_URL@/, b)
gsub(/@DESTINATION_BASE_URL@/, d)
print
}
' "$TEMPLATE" > "$OUT"

View file

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Example site — free after GOA:4200</title>
<title>hacktivism tools — unlocked</title>
<style>
:root { color-scheme: light dark; }
body {
@ -26,29 +26,41 @@
.price { font-variant-numeric: tabular-nums; }
code { background: color-mix(in srgb, CanvasText 12%, transparent); padding: 0.1em 0.35em; border-radius: 3px; }
.card {
margin-top: 1.5rem;
margin-top: 1.25rem;
padding: 1rem 1.1rem;
border: 1px solid color-mix(in srgb, CanvasText 18%, transparent);
border-radius: 10px;
}
ul { padding-left: 1.2rem; }
a { color: inherit; }
.sites a {
display: block;
margin: 0.45rem 0;
font-weight: 600;
}
</style>
</head>
<body>
<span class="badge">unlocked</span>
<h1>Example site</h1>
<h1>hacktivism tools</h1>
<p>
You paid <strong class="price">GOA:4200</strong> once via GNU Taler / Paivana.
This whole example site is now free for you to browse (site-wide access cookie).
You paid once via GNU Taler / Paivana
(<strong class="price">GOA:42</strong> on this merchant).
Site-wide access cookie is set for <code>paivana.hacktivism.ch</code>.
</p>
<div class="card sites">
<p><strong>Sites</strong></p>
<a href="https://cryptpad.hacktivism.ch/">cryptpad.hacktivism.ch</a>
<a href="https://galene.hacktivism.ch/">galene.hacktivism.ch</a>
<a href="https://silverbullet.hacktivism.ch/">silverbullet.hacktivism.ch</a>
</div>
<div class="card">
<p><strong>What this demonstrates</strong></p>
<p><strong>Notes</strong></p>
<ul>
<li>Paywall: <code>paivana-httpd</code> in front of a normal upstream HTTP site</li>
<li>Currency: exploration money <code>GOA</code> on exchange.hacktivism.ch</li>
<li>After payment: no further charge for pages behind this proxy</li>
<li>One Paivana process = one <code>DESTINATION_BASE_URL</code> → this portal is the gated upstream.</li>
<li>Merchant: <code>goa-shop</code> · template <code>paivana</code>.</li>
<li>Host: <code>https://paivana.hacktivism.ch/</code></li>
</ul>
<p style="margin-bottom:0">Host: <code>https://paivana.hacktivism.ch/</code></p>
</div>
</body>
</html>