#!/usr/bin/env bash # Setter opp Announcer på klienten som er koblet til høyttaleranlegget. # Debian/Ubuntu/Mint. Appen kjører i Docker; dette skriptet ordner Docker, # .env, datamapper, brannmur og autostart. # # git clone https://git.1x1.no/kent/announcer.git # cd announcer && ./install.sh # # Kjør som vanlig bruker (ikke sudo); skriptet spør om passord der det trengs. # Valgfritt: # ANNOUNCER_PIN=1234 ./install.sh sida krever PIN # ANNOUNCER_PORT=8090 ./install.sh annen port # ANNOUNCER_TITLE="Utrop" ./install.sh annen tittel # BIND_IP=127.0.0.1 ./install.sh bare maskina selv # ANNOUNCER_MESH_SECRET=… ./install.sh sone i et mesh (samme nøkkel som sentralen) # # Kan kjøres på nytt; da bygges bildet om og containeren startes om. En .env # som finnes blir ikke overskrevet. set -euo pipefail if [[ $EUID -eq 0 ]]; then echo "Kjør som vanlig bruker, ikke root/sudo." >&2 exit 1 fi REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$REPO_DIR" step() { printf '\n\033[1m==> %s\033[0m\n' "$*"; } warn() { printf '\033[33m! %s\033[0m\n' "$*"; } # -------------------------------------------------------------------------- step "Rydder bort eventuell nativ installasjon" # Tidligere versjoner kjørte appen direkte som en systemd-brukerenhet. To # instanser ville slåss om porten, så den gamle skal bort. for old in sg-announcer announcer; do unit="$HOME/.config/systemd/user/$old.service" if [[ -f "$unit" ]]; then systemctl --user disable --now "$old" >/dev/null 2>&1 || true rm -f "$unit" echo "fjernet $old.service (nativ)" fi done systemctl --user daemon-reload 2>/dev/null || true # -------------------------------------------------------------------------- step "Docker" if ! command -v docker >/dev/null 2>&1; then echo "installerer Docker …" curl -fsSL https://get.docker.com | sudo sh fi if ! id -nG "$USER" | tr ' ' '\n' | grep -qx docker; then sudo usermod -aG docker "$USER" warn "La $USER i docker-gruppa. Du må logge ut og inn igjen," warn "og så kjøre ./install.sh på nytt. Stopper her." exit 0 fi if ! docker info >/dev/null 2>&1; then warn "Docker svarer ikke. Er tjenesten startet? sudo systemctl enable --now docker" exit 1 fi docker --version docker compose version | head -1 # -------------------------------------------------------------------------- step "Oppsett (.env)" # BIND_IP er det som avgjør hvem som når sida. ufw gjør det ikke: Dockers # publiserte porter settes opp i nat-tabellen og går forbi ufws regler. NB_IP="$(ip -4 addr show wt0 2>/dev/null | awk '/inet /{sub(/\/.*/,"",$2);print $2;exit}')" if [[ -n "${BIND_IP:-}" ]]; then : elif [[ -n "$NB_IP" ]]; then BIND_IP="$NB_IP" echo "NetBird funnet – binder til $BIND_IP, så bare VPN-et når sida." else BIND_IP="0.0.0.0" fi if [[ -f .env ]]; then echo ".env finnes allerede, lar den stå. Slett den for å lage en ny." else cat > .env </dev/null || cat /etc/timezone 2>/dev/null || echo Europe/Oslo) ANNOUNCER_PORT=${ANNOUNCER_PORT:-8090} ANNOUNCER_SINK=${ANNOUNCER_SINK:-} ANNOUNCER_TITLE=${ANNOUNCER_TITLE:-} ANNOUNCER_PUBLIC_URL=${ANNOUNCER_PUBLIC_URL:-} ANNOUNCER_PIN=${ANNOUNCER_PIN:-} ANNOUNCER_JWT_SECRET=${ANNOUNCER_JWT_SECRET:-} ANNOUNCER_OIDC_CLIENT_SECRET=${ANNOUNCER_OIDC_CLIENT_SECRET:-} ANNOUNCER_SECRET_KEY= ANNOUNCER_MESH_SECRET=${ANNOUNCER_MESH_SECRET:-} ENV chmod 600 .env # PIN og nøkler står i klartekst echo "skrev .env (PUID=$(id -u), BIND_IP=$BIND_IP)" fi step "Lyd uten innlogging" # Lydsocketen ligger i /run/user/, som bare finnes når brukerens # systemd-instans kjører – normalt fra grafisk innlogging. En sone i et skap # (Raspberry Pi uten skjerm) har ingen som logger inn. Linger starter # brukerens tjenester (PipeWire inkludert) ved boot uansett. Harmløst på en # laptop, nødvendig på en Pi. if command -v loginctl >/dev/null 2>&1; then sudo loginctl enable-linger "$USER" && echo "linger på for $USER" fi step "Datamapper" mkdir -p data/{voices,cache,chimes,logs,instance} [[ -f data/chimes/README.txt ]] || cp -n chimes/README.txt data/chimes/ 2>/dev/null || true echo "data/ – stemmer, buffer, egne jingler, logg og sesjonsnøkkel" if [[ ! -f data/config.toml ]]; then echo "ingen data/config.toml: sida er åpen for alle som når den." echo " vil du ha innlogging: cp config.example.toml data/config.toml" fi # -------------------------------------------------------------------------- step "Bygger og starter" docker compose up -d --build step "Venter på at tjenesten svarer" # Første oppstart laster ned Piper-stemmene (~670 MB) før den svarer. PORT="$(grep -E '^ANNOUNCER_PORT=' .env | cut -d= -f2)" PROBE_IP="$BIND_IP"; [[ "$PROBE_IP" == "0.0.0.0" ]] && PROBE_IP=127.0.0.1 for i in $(seq 1 60); do if curl -fsS -o /dev/null "http://$PROBE_IP:$PORT/api/config" 2>/dev/null; then echo "svarer etter ~$((i*5)) s" break fi [[ $i -eq 1 ]] && echo "laster ned stemmer, dette tar noen minutter første gang …" [[ $i -eq 60 ]] && warn "svarte ikke innen 5 min. Se: docker compose logs -f" sleep 5 done # -------------------------------------------------------------------------- step "Brannmur" # Merk at ufw *ikke* styrer tilgangen til announcer – det gjør BIND_IP i # .env. ufw settes her bare for maskinens øvrige porter. if [[ -n "$NB_IP" ]]; then sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow in on wt0 to any port 22 proto tcp comment "ssh via netbird" sudo ufw allow in on wt0 to any port 22022 proto tcp comment "netbird ssh-server" sudo ufw --force enable echo "ufw aktiv: ssh kun på wt0." echo "announcer er bundet til $BIND_IP:$PORT – det er NetBird-adressen," echo "så sida nås bare over VPN-et. ufw er ikke involvert i det." elif command -v ufw >/dev/null 2>&1 && sudo ufw status 2>/dev/null | grep -q "Status: active"; then warn "ufw er aktiv, men styrer ikke Docker-porter." warn "Vil du begrense tilgangen: sett BIND_IP i .env og kjør docker compose up -d." else echo "ufw er ikke aktiv." [[ "$BIND_IP" == "0.0.0.0" ]] && warn "Sida er åpen på alle nett maskina er på." fi # -------------------------------------------------------------------------- IP="$(ip -4 addr show scope global 2>/dev/null | awk '/inet /{sub(/\/.*/,"",$2);print $2;exit}')" step "Ferdig" docker compose ps cat <}}:$PORT Lyden spilles i din innloggede økt, så maskinen må være logget inn grafisk. Containeren starter ved boot, altså før innlogging – da feiler avspilling, men den retter seg selv ved første utrop etter at du er logget inn. Tips for en laptop på arrangementet: - Slå på automatisk innlogging (Innstillinger -> Påloggingsvindu). - Hindre at den sover med lokket igjen: sudo sed -i 's/^#\?HandleLidSwitch=.*/HandleLidSwitch=ignore/' /etc/systemd/logind.conf sudo systemctl restart systemd-logind Mesh (flere anlegg): sett [zones] i data/config.toml på sentralen og samme ANNOUNCER_MESH_SECRET i .env på sentralen og hver sone. Se docs/mesh.md. På en Pi med både HDMI og jack: velg lydutgang med sudo raspi-config (System Options -> Audio), ellers går lyden til skjermen som ikke er der. Drift: docker compose logs -f følg loggen docker compose restart etter endringer i data/config.toml docker compose up -d --build etter endringer i koden cat data/logs/announcements.jsonl hvem som sendte hva MSG