Compare commits

..

6 commits

4 changed files with 330 additions and 4 deletions

View file

@ -0,0 +1,7 @@
How to change passwords in case of a major heck up
```zsh
sudo podman exec -it -u www-data partdb sh
# inside container:
cd /var/www/html
php bin/console partdb:users:set-password USERNAME
```

View file

@ -0,0 +1,94 @@
{
config,
pkgs,
lib,
...
}: {
options.local = {
hostname = lib.mkOption {
type = lib.types.str;
default = "nixos-default";
description = "System hostname";
};
username = lib.mkOption {
type = lib.types.str;
default = "user";
description = "Primary user username";
};
userDescription = lib.mkOption {
type = lib.types.str;
default = "NixOS User";
description = "Primary user description";
};
address = lib.mkOption {
type = lib.types.str;
default = "10.1.1.100";
description = "Static IP address";
};
};
imports = [
./modules/desktop-manager/sway_greetd_homemanager.nix
./modules/local/hostname_username.nix
./modules/local/networking_local.nix
./modules/bootloader/seabios-assigned-iso-at-birth.nix
./modules/lix-default.nix
# Optionally: ./modules/toolsets/remote_building.nix
#
#
## Compose modules for Portainer service
./modules/songsheet/wavelog/docker-compose.nix
./modules/secrets-config/sops-composesongsheet.nix
];
config = {
local.hostname = "christine-teamspeak";
local.username = "teamspeak_christine";
local.userDescription = "NixOS Teamspeak Service";
local.address = "10.1.1.248";
services.teamspeak3 = {
enable = true;
openFirewall = true;
};
## Add Conduit for Matrix
# See https://search.nixos.org/options?channel=unstable&query=services.matrix-conduit.
# and https://docs.conduit.rs/configuration.html
services.matrix-conduit = {
enable = true;
settings.global = {
allow_registration = true;
# You will need this token when creating your first account.
#registration_token = "testtoken1234";
# server_name = yourDomainName;
port = 12244;
# Bind to all interfaces so Traefik on the network can reach Conduit.
address = "0.0.0.0";
database_backend = "rocksdb";
server_name = "lgbtq.prg-radio.org";
# See https://docs.conduit.rs/turn.html, and https://github.com/element-hq/synapse/blob/develop/docs/turn-howto.md for more details
# turn_uris = [
# "turn:your.turn.url?transport=udp"
# "turn:your.turn.url?transport=tcp"
# ];
# turn_secret = "your secret";
};
};
networking.firewall.allowedTCPPorts = [
80
443
12244
];
networking.firewall.allowedUDPPorts = [
80
443
12244
];
system.stateVersion = "25.11";
};
}

View file

@ -67,6 +67,20 @@
];
};
};
# Federation entrypoint: external TLS on 8448
federation = {
address = ":8448";
};
# TeamSpeak entry points
teamspeak-voice = {
address = ":9987/udp";
};
teamspeak-squery = {
address = ":10022/tcp";
};
teamspeak-data = {
address = ":30033/tcp";
};
};
log = {
level = "INFO";
@ -90,7 +104,13 @@
entryPoints = ["websecure"];
tls = {};
};
# Matrix HTTP router for client requests (Element etc.)
matrix = {
rule = "Host(`lgbtq.prg-radio.org`)";
service = "matrix";
entryPoints = ["websecure"];
tls = {};
};
wavelog = {
rule = "Host(`wavelog.prg-radio.org`)";
service = "wavelog";
@ -111,7 +131,11 @@
{url = "http://10.1.1.4:3000";}
];
};
matrix.loadBalancer = {
servers = [
{url = "http://10.1.1.248:12244";}
];
};
wavelog.loadBalancer = {
servers = [
{url = "http://10.1.1.249:8086";}
@ -124,6 +148,60 @@
];
};
};
# TCP routing for TeamSpeak
tcp.routers = {
teamspeak-squery = {
rule = "HostSNI(`*`)";
service = "teamspeak-squery";
entryPoints = ["teamspeak-squery"];
};
teamspeak-data = {
rule = "HostSNI(`*`)";
service = "teamspeak-data";
entryPoints = ["teamspeak-data"];
};
# Federation TCP router: incoming on :8448 -> Conduit backend
matrix-federation = {
rule = "HostSNI(`*`)";
service = "matrix-federation";
entryPoints = ["federation"];
};
};
tcp.services = {
teamspeak-squery.loadBalancer = {
servers = [
{address = "10.1.1.248:10022";}
];
};
teamspeak-data.loadBalancer = {
servers = [
{address = "10.1.1.248:30033";}
];
};
matrix-federation.loadBalancer = {
servers = [
{address = "10.1.1.248:12244";}
];
};
};
# UDP routing for TeamSpeak voice
udp.routers = {
teamspeak-voice = {
entryPoints = ["teamspeak-voice"];
service = "teamspeak-voice";
};
};
udp.services = {
teamspeak-voice.loadBalancer = {
servers = [
{address = "10.1.1.248:9987";}
];
};
};
};
};
@ -147,8 +225,8 @@
wants = ["acme-finished-prg-radio.org.target"];
};
networking.firewall.allowedTCPPorts = [80 443];
networking.firewall.allowedUDPPorts = [80 443];
networking.firewall.allowedTCPPorts = [80 443 10022 30033 8448];
networking.firewall.allowedUDPPorts = [80 443 9987];
system.stateVersion = "25.11";
};

View file

@ -0,0 +1,147 @@
#!/usr/bin/env zsh
set -euo pipefail
PATH_TO_BACKUPGPG_KEY=${PATH_TO_BACKUPGPG_KEY:-}
PATH_TO_BACKUP_FILE=${PATH_TO_BACKUP_FILE:-}
PATH_TO_OUTPUT_DIR=${PATH_TO_OUTPUT_DIR:-}
KEEP=false
# TIL You can do these kind of scripts.
usage() {
cat <<EOF
Usage: $0 [-f <backup-file>] [-k <private-key-file>] [-o <output-dir>] [--keep]
Decrypt and unpack a .gz.gpg backup file for inspection. The script will
create a temporary GNUPGHOME (if a key is provided), decrypt the file, and
if needed gunzip it to produce a .sql file. The resulting SQL file path will
be printed and a short preview will be shown.
Options:
-f <file> Path to the .sql.gz.gpg backup file (or set PATH_TO_BACKUP_FILE)
-k <key> Path to a private key file to import (optional; or set PATH_TO_BACKUPGPG_KEY)
-o <dir> Output directory for the final .sql file (defaults to current working directory)
--keep Keep temporary files (do not delete temp GNUPGHOME/dir)
-h, --help Show this message
EOF
exit 1
}
# Simple arg parsing to allow flags
while [[ $# -gt 0 ]]; do
case "$1" in
-f)
PATH_TO_BACKUP_FILE="$2"; shift 2;;
-k)
PATH_TO_BACKUPGPG_KEY="$2"; shift 2;;
-o)
PATH_TO_OUTPUT_DIR="$2"; shift 2;;
--keep)
KEEP=true; shift;;
-h|--help)
usage;;
*)
echo "Unknown argument: $1" >&2; usage;;
esac
done
if [[ -z "$PATH_TO_BACKUP_FILE" ]]; then
echo "Error: no backup file provided." >&2
usage
fi
if [[ ! -f "$PATH_TO_BACKUP_FILE" ]]; then
echo "Error: backup file does not exist: $PATH_TO_BACKUP_FILE" >&2
exit 2
fi
command -v gpg >/dev/null 2>&1 || { echo "gpg not found in PATH" >&2; exit 3; }
command -v gunzip >/dev/null 2>&1 || { echo "gunzip not found in PATH" >&2; exit 3; }
command -v file >/dev/null 2>&1 || { echo "file command not found in PATH" >&2; exit 3; }
TMPDIR=$(mktemp -d)
trap '[[ "$KEEP" = false ]] && rm -rf "$TMPDIR"' EXIT
# If a key is provided, use an isolated GNUPGHOME so we don't touch the user's keyring.
if [[ -n "$PATH_TO_BACKUPGPG_KEY" ]]; then
if [[ ! -f "$PATH_TO_BACKUPGPG_KEY" ]]; then
echo "Private key file not found: $PATH_TO_BACKUPGPG_KEY" >&2
exit 4
fi
export GNUPGHOME="$TMPDIR/gnupg"
# Create GNUPGHOME and explicitly set secure permissions
mkdir -p "$GNUPGHOME"
chmod 0700 "$GNUPGHOME"
echo "Importing provided private key into temporary GNUPGHOME..."
gpg --batch --import "$PATH_TO_BACKUPGPG_KEY" >/dev/null 2>&1
fi
# Determine output directory: prefer PATH_TO_OUTPUT_DIR, otherwise current directory
if [[ -n "$PATH_TO_OUTPUT_DIR" ]]; then
OUTDIR="$PATH_TO_OUTPUT_DIR"
else
OUTDIR="$(pwd)"
fi
mkdir -p "$OUTDIR"
# Keep decrypted intermediate in TMPDIR, final .sql in OUTDIR (PWD by default)
DECRYPTED="$TMPDIR/backup.decrypted"
# Derive a reasonable final filename from the backup file name
orig_base=$(basename -- "$PATH_TO_BACKUP_FILE")
name_no_gpg=${orig_base%.gpg}
name_no_gz=${name_no_gpg%.gz}
if [[ "$name_no_gz" == *.sql ]]; then
final_name="$name_no_gz"
else
final_name="${name_no_gz}.sql"
fi
FINAL_SQL="$OUTDIR/$final_name"
# If file exists, append timestamp to avoid accidental overwrite
if [[ -e "$FINAL_SQL" ]]; then
ts=$(date +%Y%m%d%H%M%S)
FINAL_SQL="$OUTDIR/${name_no_gz}.${ts}.sql"
echo "Notice: output file already existed; writing to $FINAL_SQL"
fi
echo "Decrypting: $PATH_TO_BACKUP_FILE"
# Decrypt to a temporary file. gpg will prompt for passphrase if needed (user must be present)
if ! gpg --batch --yes --decrypt --output "$DECRYPTED" "$PATH_TO_BACKUP_FILE"; then
echo "gpg decryption failed" >&2
exit 5
fi
# Detect if the decrypted file is gzip compressed
if file --brief --mime-type "$DECRYPTED" | grep -q gzip; then
echo "Detected gzip compressed payload; decompressing to: $FINAL_SQL"
if ! gunzip -c "$DECRYPTED" > "$FINAL_SQL"; then
echo "gunzip failed" >&2
exit 6
fi
else
# Not gzip: assume plain SQL or other plain text
echo "Writing decrypted payload to: $FINAL_SQL"
cp "$DECRYPTED" "$FINAL_SQL"
fi
echo "Unpacked SQL available at: $FINAL_SQL"
# Show a short preview
echo
echo "--- File preview (first 80 lines) ---"
head -n 80 "$FINAL_SQL" || true
echo "--- end preview ---"
echo
if [[ "$KEEP" = true ]]; then
echo "Temporary files (including GNUPGHOME) retained under: $TMPDIR"
echo "Final SQL file retained at: $FINAL_SQL"
else
echo "Temporary files (excluding final SQL) were stored under: $TMPDIR (removed on exit)"
echo "Final SQL file is at: $FINAL_SQL"
fi
# Print final path so callers can copy it if they used --keep or scripting
echo "$FINAL_SQL"