5 Commits

Author SHA1 Message Date
librelad
65167463f9 fix(chat apps): tag every service so its IP actually substitutes
Installing rocketchat failed with

    invalid IPv4 address: ParseAddr("IP_DATA_2"): unable to parse IP

ipUpdateComposeTags allocates one IP per SERVICE_TAG_N annotation and fills
IP_TAG_i only where SERVICE_TAG_i exists. The four new apps tagged only their
primary service, so every sidecar — matrix's postgres, mattermost's postgres,
rocketchat's mongo, and fifteen of stoat's sixteen — kept a literal IP_DATA_n
in the deployed compose and docker refused to create the container.

Tag every service that carries an ipv4_address, index-aligned with its IP_TAG.
For stoat that also meant moving caddy from SERVICE_TAG_1 to _6 so the indices
line up with the IPs rather than the reading order.

mastodon had the same latent break (IP_TAG_2 and _3 untagged) and is fixed the
same way — it would have failed on first install for the same reason.

SERVICE_TAG carries the compose *key*, not container_name: 'libreportal app
restart <app> <service>' passes it to 'docker compose restart', which only
understands keys.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 19:48:09 +01:00
librelad
ab811440e4 fix(pihole): use the official image, ported to Pi-hole v6
The app shipped cbcrowe/pihole-unbound — a third-party bundle last
rebuilt 841 days ago. Pi-hole itself is fine: the official
pihole/pihole was rebuilt 42 days ago. We packaged an abandoned fork,
not a dead project.

Not a tag swap. The official image is v6, which replaced nearly every
v5 environment variable with an FTLCONF_ equivalent — and the container
ACCEPTS the old names and ignores them, so a v5-style block looks
correct while configuring nothing, including the admin password:

  WEBPASSWORD         -> FTLCONF_webserver_api_password
  WEBTHEME            -> FTLCONF_webserver_interface_theme
  PIHOLE_DNS_         -> FTLCONF_dns_upstreams   (";" separates values)
  DNSSEC              -> FTLCONF_dns_dnssec
  DNSMASQ_LISTENING   -> FTLCONF_dns_listeningMode
  REV_SERVER{,_TARGET,_DOMAIN,_CIDR} -> FTLCONF_dns_revServers, one
                         combined "<enabled>,<cidr>,<target>,<domain>"
  FTLCONF_LOCAL_IPV4  -> gone in v6

listeningMode is ALL rather than the old "single": on a bridge network
queries arrive via the docker gateway, and "single" drops them.

The bundled unbound is gone, so PIHOLE_DNS_=127.0.0.1#5335 pointed at
nothing. New CFG_PIHOLE_UPSTREAM_DNS defaults to Quad9, with the config
documenting how to point it at the unbound app for full recursion. The
freed port slot becomes the (disabled) DHCP port, which v6 supports.

Volumes: v6 keeps config, databases and gravity under /etc/pihole, and
ignores /etc/dnsmasq.d unless explicitly re-enabled — so the old
two-mount layout is replaced by a single ./etc-pihole.

Variable names taken from the official v5->v6 upgrade doc, not memory.
Substitution verified end to end: every placeholder resolves and
revServers renders in the documented format.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 02:30:13 +01:00
librelad
56102ac5c0 feat(updater): P1b — CFG_<APP>_VERSION drives the anchor image tag
Add a `#LIBREPORTAL|<APP>_VERSION_TAG|<current-tag>` sentinel to each app's
anchor (`<slug>-service`) image line, so a `CFG_<APP>_VERSION` config drives
that tag through the existing tagging system — the config becomes the source,
the compose tag is derived (like ports/IPs/domains already are). This is the
"install/pin a specific version" knob.

- Placeholder is the literal current tag (e.g. `31-fpm-alpine`), NOT a `*_DATA`
  token: an unset var leaves the line untouched (inert comment, keeps the real
  tag) and never trips the up_app stale-tag scanner.
- Only the anchor line is tagged (sidecars mariadb/redis/nginx stay
  tracked-by-digest, not user-version-picked). ollama correctly targets
  `ollama/ollama`, not the companion open-webui.
- Untagged anchors normalized to `:latest` (semantic no-op) so they're
  templatable too. The manager (libreportal) is skipped — it updates via its
  release channel, not a docker tag.

32 apps wired. Verified: CFG_NEXTCLOUD_VERSION=32 → `nextcloud:32` (prefix
preserved, idempotent, sidecars untouched); all compose files still valid YAML.
Inert until a version config is set, so no behaviour change on existing installs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-07-17 23:13:57 +01:00
librelad
dec3055b63 feat(routing): dynamic per-port subdomains + router-block toggle
Replace the static one-host-per-app model with per-port routers: each
Traefik-managed port carries a subdomain (12-col PORT format) and gets a
DOMAINSUBNAME_TAG_<n> host, so one container can serve unlimited hosts.
tagsProcessorPortSubdomains stamps per-port hosts (subdomain @/empty = apex,
multi-level allowed); tagsProcessorPortRouterBlocks comments out
# TRAEFIK_PORT_<n>_BEGIN/END blocks for non-Traefik ports so unfilled
placeholders never ship (mirrors GLUETUN_OFF). Convert all 27 router apps
(subdomains seeded from HOST_NAME; headscale admin. prefix -> subdomain).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-22 00:45:01 +01:00
librelad
875a60f90f LibrePortal v0.1.0 — initial release
A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys,
Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun
VPN routing, and a web dashboard to manage it all.

Free & open forever to self-host; optional paid hosted services fund it.
See PROMISE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-21 20:37:54 +01:00