runv-server

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

commit d3b6022f7a9654e916bd138ed5c2f0f06f76012f
parent f6197a83bc740609229ad95f8a1c0341033ca1f2
Author: Pablo Murad <pablo@pablomurad.com>
Date:   Sat, 21 Mar 2026 15:41:14 -0300

chat, gemini and gopher

Diffstat:
Mscripts/admin/setup_alt_protocols.py | 49+++++++++++++++++++++++++++++++++++++++++++++----
Mscripts/docs/alt_protocols.md | 12++++++++++++
2 files changed, 57 insertions(+), 4 deletions(-)

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.03 — runv.club +Versão 0.04 — runv.club """ from __future__ import annotations @@ -30,7 +30,7 @@ from typing import Any, Final # Constantes # --------------------------------------------------------------------------- -VERSION: Final[str] = "0.03" +VERSION: Final[str] = "0.04" DEFAULT_USERS_JSON: Final[Path] = Path("/var/lib/runv/users.json") DEFAULT_HOMES_ROOT: Final[Path] = Path("/home") @@ -328,6 +328,7 @@ def wait_for_unit_active( attempts, unit, ) + log_systemd_unit_failed_hint(unit, log) return False @@ -456,6 +457,33 @@ def apt_install( return True +def log_ufw_suggested_commands(log: logging.Logger) -> None: + """Comandos para copiar quando o script não aplicou regras UFW automaticamente.""" + log.info( + "Se usar UFW, depois de «sudo ufw enable» (se ainda não estiver activo), execute:\n" + " sudo ufw allow 70/tcp comment 'gopher'\n" + " sudo ufw allow 1965/tcp comment 'gemini'\n" + " sudo ufw reload" + ) + + +def log_systemd_unit_failed_hint(unit: str, log: logging.Logger) -> None: + """Se o unit estiver em estado failed, regista ERROR com ponteiro para journalctl.""" + r = subprocess.run( + ["systemctl", "is-failed", unit], + capture_output=True, + text=True, + timeout=30, + ) + if r.returncode != 0: + return + log.error( + "%s está em estado «failed» — diagnóstico: sudo journalctl -u %s -b --no-pager -n 80", + unit, + unit, + ) + + def dpkg_installed(package: str) -> bool: r = subprocess.run( ["dpkg", "-s", package], @@ -475,6 +503,7 @@ def ufw_maybe_allow( ) -> None: if skip_firewall: log.info("firewall ignorado (--skip-firewall)") + log_ufw_suggested_commands(log) return r = subprocess.run( ["ufw", "status"], @@ -488,6 +517,7 @@ def ufw_maybe_allow( "UFW não está ativo (ou comando falhou). Não abro portas automaticamente. " "Abra 70/tcp (Gopher) e 1965/tcp (Gemini) se usar firewall." ) + log_ufw_suggested_commands(log) return for port, label in ports: cmd = ["ufw", "allow", f"{port}/tcp"] @@ -512,13 +542,24 @@ def validate_final( ) log.info("gophernicus.socket: %s", (r.stdout or "").strip() or r.returncode) + molly_unit = f"molly-brown@{MOLLY_INSTANCE}.service" r2 = subprocess.run( - ["systemctl", "is-active", f"molly-brown@{MOLLY_INSTANCE}.service"], + ["systemctl", "is-active", molly_unit], capture_output=True, text=True, timeout=30, ) - log.info("molly-brown@%s: %s", MOLLY_INSTANCE, (r2.stdout or "").strip() or r2.returncode) + molly_state = (r2.stdout or "").strip() or str(r2.returncode) + log.info("molly-brown@%s: %s", MOLLY_INSTANCE, molly_state) + if molly_state != "active": + log.warning( + "molly-brown não está «active» (estado reportado: %s). " + "«activating» durante o script não significa sucesso — confirme com " + "«systemctl is-active %s» e «sudo ss -tlnp | grep 1965».", + molly_state, + molly_unit, + ) + log_systemd_unit_failed_hint(molly_unit, log) if usernames: sample = usernames[0] diff --git a/scripts/docs/alt_protocols.md b/scripts/docs/alt_protocols.md @@ -31,6 +31,18 @@ O **molly-brown** trata `AccessLog` e `ErrorLog` como **caminhos de ficheiro**. `sudo python3 scripts/admin/setup_alt_protocols.py --verbose --force` - **Correcção manual rápida:** `sudo mkdir -p /var/log/molly-brown`; criar os dois `.log`; `sudo chown` para o utilizador do serviço (`systemctl show -p User --value molly-brown@runv.club.service`); editar o `.conf` e substituir `AccessLog` / `ErrorLog` pelos caminhos absolutos; depois `sudo systemctl reset-failed molly-brown@runv.club.service` e `sudo systemctl start molly-brown@runv.club.service`. +## Checklist rápido (conf antiga, UFW, «activating») + +1. **Ainda vê `open /-` no journal?** O `/etc/molly-brown/runv.club.conf` no servidor pode continuar com `ErrorLog = "-"` até correr o script com **`--force`** (ou editar à mão). Confirme: `grep -E 'AccessLog|ErrorLog' /etc/molly-brown/runv.club.conf`. +2. **UFW:** o script só executa `ufw allow` automaticamente quando **`ufw status`** mostra o firewall **activo** na altura da execução. Se activou o UFW **depois**, ou usa outro firewall, abra **70/tcp** (Gopher) e **1965/tcp** (Gemini) manualmente: + ```bash + sudo ufw allow 70/tcp comment 'gopher' + sudo ufw allow 1965/tcp comment 'gemini' + sudo ufw reload + ``` + Com `--skip-firewall` ou UFW inactivo, o script regista no log os mesmos comandos sugeridos para copiar. +3. **`molly-brown@runv.club: activating` no fim do script:** **não** indica sucesso — só que o unit ainda não estava `active` nesse instante (p.ex. crash loop). Use `systemctl is-active molly-brown@runv.club.service`, `systemctl is-failed …` e `sudo ss -tlnp | grep 1965`. Se `is-failed` for positivo, veja `journalctl` como abaixo. + ## Molly não sobe ou fica em «activating» - **`journalctl` sem mensagens:** os logs do serviço do sistema exigem **root** — use `sudo journalctl -u molly-brown@runv.club.service -b --no-pager -n 80`.