runv-server

server tooling for runv.club
Log | Files | Refs | README

commit 74505af9870bc3f30a9645e4c5ae41fd32cdefdb
parent f4fba944cb54b1a7072e6653cf300031af150f98
Author: Pablo Murad <pablo@pablomurad.com>
Date:   Sat, 21 Mar 2026 16:31:41 -0300

fix(alt-protocols): redirect /~/user to /~/user/ and document Gemini paths (v0.10)

Molly Brown only maps HomeDocBase for paths ~/username/ with trailing slash.
Add TempRedirect for /~/user -> /~/user/. Clarify that gemini://host/user is not
the user capsule; README and skel copy updated.

Made-with: Cursor

Diffstat:
MREADME.md | 9+++++++--
Mscripts/admin/create_runv_user.py | 4++--
Mscripts/admin/setup_alt_protocols.py | 9++++++---
Mscripts/docs/alt_protocols.md | 8++++++--
Mtools/skel/public_gemini/index.gmi | 2+-
5 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/README.md b/README.md @@ -1 +1,7 @@ -runv.club setup -\ No newline at end of file +# runv-server + +Repositório de automação e documentação para **runv.club** (pubnix Debian). + +## Gemini (Molly Brown) + +O capsule de cada utilizador **não** está em `gemini://runv.club/USERNAME` (isso seria o path `/USERNAME`, que no servidor não corresponde à home). O formato correcto é **`gemini://runv.club/~/USERNAME/`** (path **`/~/USERNAME/`**), ou **`gemini://runv.club/~USERNAME/`** (redirect para o anterior). Requer Molly a correr, symlink em `/var/gemini/users/USERNAME`, home e `public_gemini` atravessáveis pelo utilizador do serviço — ver [`scripts/docs/alt_protocols.md`](scripts/docs/alt_protocols.md). diff --git a/scripts/admin/create_runv_user.py b/scripts/admin/create_runv_user.py @@ -418,7 +418,7 @@ Tudo o que colocares em **`public_html`** pode ser lido pelo mundo via HTTP no e - **Gopher:** edita `~/public_gopher/gophermap` (e outros ficheiros nessa pasta). URL típica: `gopher://{DEFAULT_GEMINI_HOST_PUBLIC}/1/~{username}` (o caminho exacto depende do servidor). -- **Gemini:** edita `~/public_gemini/index.gmi`. URL canónica: `gemini://{DEFAULT_GEMINI_HOST_PUBLIC}/~/{username}/`; `gemini://{DEFAULT_GEMINI_HOST_PUBLIC}/~{username}/` também funciona (redirect no servidor). +- **Gemini:** edita `~/public_gemini/index.gmi`. URL canónica: `gemini://{DEFAULT_GEMINI_HOST_PUBLIC}/~/{username}/` (path `/~/{username}/`, **com barra final**); `gemini://{DEFAULT_GEMINI_HOST_PUBLIC}/~{username}/` também funciona (redirect). `gemini://{DEFAULT_GEMINI_HOST_PUBLIC}/{username}` **não** é o teu capsule. - Mantém **755** nas pastas públicas e **644** nos ficheiros, para o servidor conseguir ler. ## Comandos úteis na shell @@ -478,7 +478,7 @@ iDocumentação: man gophermap (no pacote gophernicus). fake NULL 0 def default_gemini_index_gmi(username: str) -> str: return f"""# ~{username} — runv.club (Gemini) -Bem-vindo ao teu capsule em `gemini://{DEFAULT_GEMINI_HOST_PUBLIC}/~/{username}/` (canónica). `gemini://{DEFAULT_GEMINI_HOST_PUBLIC}/~{username}/` também funciona. +Bem-vindo ao teu capsule em `gemini://{DEFAULT_GEMINI_HOST_PUBLIC}/~/{username}/` (canónica; barra final). `gemini://{DEFAULT_GEMINI_HOST_PUBLIC}/~{username}/` também funciona. `gemini://{DEFAULT_GEMINI_HOST_PUBLIC}/{username}` não aponta para aqui. Edita este ficheiro em `~/public_gemini/index.gmi`. Mantém pastas **755** e ficheiros **644**. diff --git a/scripts/admin/setup_alt_protocols.py b/scripts/admin/setup_alt_protocols.py @@ -7,7 +7,7 @@ Infraestrutura Gopher (gophernicus) e Gemini (molly-brown) para runv.club. Idempotente, dry-run, subprocess sem shell. Executar como root no Debian. -Versão 0.09 — runv.club +Versão 0.10 — runv.club """ from __future__ import annotations @@ -32,7 +32,7 @@ from typing import Any, Final # Constantes # --------------------------------------------------------------------------- -VERSION: Final[str] = "0.09" +VERSION: Final[str] = "0.10" LETSENCRYPT_LIVE: Final[Path] = Path("/etc/letsencrypt/live") LETSENCRYPT_ARCHIVE: Final[Path] = Path("/etc/letsencrypt/archive") @@ -73,7 +73,7 @@ iEdita este ficheiro em ~/public_gopher/gophermap. fake NULL 0 DEFAULT_USER_INDEX_GMI: Final[str] = """# ~{username} — runv.club (Gemini) -Bem-vindo ao teu capsule em `gemini://runv.club/~/{username}/` (URL canónica Molly). O endereço `gemini://runv.club/~{username}/` também funciona (redirect no servidor). +Bem-vindo ao teu capsule em `gemini://runv.club/~/{username}/` (URL canónica Molly: path `/~/{username}/` com **barra final**). O endereço `gemini://runv.club/~{username}/` também funciona (redirect). **Não** confundas com `gemini://runv.club/{username}` — esse path **não** é o capsule (no Molly só há homes em `/~/…`). Edita este ficheiro em `~/public_gemini/index.gmi`. Mantém pastas **755** e ficheiros **644** para o servidor ler o conteúdo. @@ -294,8 +294,11 @@ GeminiExt = "gmi" ReadMollyFiles = true # Molly Brown resolve espaços de utilizador em paths /~/user/… (HomeDocBase). +# A documentação oficial exige o prefixo ~/username/ *com* barra final; sem ela, +# /~/user não casa e devolve 51 — redireccionamos para /~/user/. # URLs estilo Apache /~user/… redireccionam sem tocar em ficheiros no disco. [TempRedirects] +"^/~/([^/]+)$" = "/~/$1/" "^/~([^/]+)(/.+)$" = "/~/$1$2" "^/~([^/]+)/?$" = "/~/$1/" """ diff --git a/scripts/docs/alt_protocols.md b/scripts/docs/alt_protocols.md @@ -17,12 +17,16 @@ Script em **`scripts/admin/setup_alt_protocols.py`**: instala e configura **goph - **Gopher (gophernicus):** selectors **`~username/…`** (tilde **colado** ao nome), alinhado com URLs como **`gopher://runv.club/1/~user`**. Não há o mesmo «split» de path que no Molly. - **Gemini (Molly Brown):** o servidor resolve caps em **`/~/username/…`**. URLs estilo Apache **`/~username/…`** são aceites graças a **`[TempRedirects]`** no `.conf` gerado pelo script (**v0.09+**). Pode usar indistintamente **`gemini://runv.club/~/user/`** (canónico) ou **`gemini://runv.club/~user/`** (compatível). +### URLs Gemini que *não* são capsules de utilizador + +O Molly **não** espelha o HTTP `mod_userdir` no mesmo path: **`gemini://runv.club/pmurad`** (path **`/pmurad`**) **não** aponta para a home — não existe ficheiro em `/var/gemini/pmurad`. O capsule está em **`gemini://runv.club/~/pmurad/`** (path **`/~/pmurad/`**, com **`~/`** e **barra final**). Sem a barra final, **`gemini://runv.club/~/pmurad`** era comum falhar com **51 Not found**; a partir do **v0.10** o `.conf` inclui redirect **`/~/user` → `/~/user/`**. + ## Travessia da home (`755` na política runv) Apache (`mod_userdir`), **gophernicus** e **molly-brown** precisam de **execução para «others»** (`o+x`, mínimo) em **cada** componente do caminho até a pasta pública (`~/public_html`, `~/public_gopher`, `~/public_gemini`). O utilizador de runtime **não é o mesmo** em todos: no Debian o Molly costuma correr como **`www-data`**; o **gophernicus** usa o **`User=`** do unit (tipicamente `gophernicus`) — veja `/lib/systemd/system/gophernicus@.service`. Uma home em **`700`** impede a travessia: **HTTP, Gopher e Gemini** deixam de servir conteúdo (p.ex. Gemini **«Not found»** com `index.gmi` presente). - **Novas contas:** [`create_runv_user.py`](../admin/create_runv_user.py) aplica **`755`** na home em `apply_runv_permissions`. -- **Backfill:** a partir do **v0.07**, [`setup_alt_protocols.py`](../admin/setup_alt_protocols.py) repõe a home do utilizador para **`755`** quando o modo actual é outro (com registo em log). O **v0.08** corrige a detecção de caminhos Let's Encrypt quando `live`/`archive` são **symlinks** (o bloco LE deixa de saltar incorrectamente). O **v0.09** adiciona redirects Molly `~user` → `~/user` e validação **`test -r`** do `gophermap` com o utilizador do serviço gophernicus. +- **Backfill:** a partir do **v0.07**, [`setup_alt_protocols.py`](../admin/setup_alt_protocols.py) repõe a home do utilizador para **`755`** quando o modo actual é outro (com registo em log). O **v0.08** corrige a detecção de caminhos Let's Encrypt quando `live`/`archive` são **symlinks** (o bloco LE deixa de saltar incorrectamente). O **v0.09** adiciona redirects Molly `~user` → `~/user` e validação **`test -r`** do `gophermap` com o utilizador do serviço gophernicus. O **v0.10** adiciona redirect **`/~/user` → `/~/user/`** (barra final exigida pelo Molly para `HomeDocBase`). - **Conflito:** [`patches/patch_permissions.py`](../../patches/patch_permissions.py) pode aplicar **`chmod 700`** em cada `/home/<user>` por política de privacidade — isso **quebra** a hospedagem em `public_*` até voltar a alinhar permissões (provisionamento ou `chmod` manual). ## Let's Encrypt e chave TLS (v0.07+; symlinks v0.08+) @@ -129,7 +133,7 @@ sudo python3 scripts/admin/setup_alt_protocols.py --verbose |------|--------| | `--dry-run` | Simula; não grava (validação de root ignorada em alguns passos só se documentado). | | `--verbose` | Log detalhado. | -| `--force` | Sobrescreve configs de sistema (com backup com timestamp) e ficheiros modelo no backfill (exceto **`~/public_gemini/index.gmi`** se já existir). Necessário para **regravar** `/etc/molly-brown/runv.club.conf` (incl. **`[TempRedirects]`** v0.09+) e remover o drop-in obsoleto **`50-runv-logs.conf`** (v0.05) ao migrar logs para `/var/lib/molly-brown/`. | +| `--force` | Sobrescreve configs de sistema (com backup com timestamp) e ficheiros modelo no backfill (exceto **`~/public_gemini/index.gmi`** se já existir). Necessário para **regravar** `/etc/molly-brown/runv.club.conf` (incl. **`[TempRedirects]`** v0.09+ e redirect **`/~/user/`** v0.10) e remover o drop-in obsoleto **`50-runv-logs.conf`** (v0.05) ao migrar logs para `/var/lib/molly-brown/`. | | `--skip-install` | Não corre `apt-get`. | | `--skip-gopher` / `--skip-gemini` | Ignora pacote, config e serviço desse protocolo. | | `--skip-firewall` | Não altera UFW. | diff --git a/tools/skel/public_gemini/index.gmi b/tools/skel/public_gemini/index.gmi @@ -1,6 +1,6 @@ # Capsule Gemini — runv.club -O endereço canónico é `gemini://runv.club/~/NOME_UTILIZADOR/` (substitui pelo teu username Unix). `gemini://runv.club/~NOME_UTILIZADOR/` também funciona (redirect no servidor). Gopher usa selector `~NOME` sem barra extra — ver documentação do projeto. +O endereço canónico é `gemini://runv.club/~/NOME_UTILIZADOR/` (substitui pelo teu username Unix; **barra final**). `gemini://runv.club/~NOME_UTILIZADOR/` também funciona (redirect). `gemini://runv.club/NOME_UTILIZADOR` (sem `~/`) **não** é este capsule. Gopher usa selector `~NOME` sem barra extra — ver documentação do projeto. Edita este ficheiro em `~/public_gemini/index.gmi`. Ficheiros `.gmi` são Texto Gemini; mantém pastas 755 e ficheiros 644 para o servidor conseguir ler.