From d137383936f40cf6490ae4d6b95192b051eea9fb Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:23:15 +0000 Subject: [PATCH 01/15] refactor(seedbox): rewrite install.sh for Docker + Tailscale architecture - Remove Transmission deployment (now via Gitea Actions) - Add git clone for repo structure - Simplify to server preparation only - Keep NFS mount configuration - Update MOTD for new architecture --- seedbox/install.sh | 278 +++++++++++++++++++++------------------------ 1 file changed, 129 insertions(+), 149 deletions(-) diff --git a/seedbox/install.sh b/seedbox/install.sh index 17af045..559f426 100644 --- a/seedbox/install.sh +++ b/seedbox/install.sh @@ -1,6 +1,9 @@ #!/bin/bash -# install.sh - Automated deployment of Seedbox Server with Transmission -# Usage: NFS_SERVER= curl -fsSL https://gitea.arnodo.fr/Damien/infra-scripts/raw/branch/main/seedbox/install.sh | bash +# install.sh - Seedbox Server Initial Setup +# Usage: curl -fsSL https://gitea.arnodo.fr/Damien/infra-scripts/raw/branch/main/seedbox/install.sh | bash +# +# This script prepares the server for Docker-based seedbox deployment. +# Services are deployed separately via Gitea Actions. set -euo pipefail @@ -14,6 +17,16 @@ log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } +# Configuration (can be overridden via environment) +HOSTNAME="${SEEDBOX_HOSTNAME:-seedbox}" +NFS_SERVER="${NFS_SERVER:-}" +NFS_SHARE_MEDIA="${NFS_SHARE_MEDIA:-/volume2/Multimédia}" +NFS_MOUNT_MEDIA="${NFS_MOUNT_MEDIA:-/mnt/media}" +NFS_OPTS="defaults,_netdev,nofail,x-systemd.automount,x-systemd.mount-timeout=30s" +SEEDBOX_DIR="/srv/seedbox" +DOWNLOADS_DIR="${SEEDBOX_DIR}/downloads" +REPO_URL="${REPO_URL:-https://gitea.arnodo.fr/Damien/infra-scripts.git}" + # Pre-flight checks check_root() { if [[ $EUID -eq 0 ]]; then @@ -32,83 +45,57 @@ check_debian() { fi } -check_required_vars() { - if [[ -z "${NFS_SERVER:-}" ]]; then - log_error "NFS_SERVER environment variable is required." - log_error "Usage: NFS_SERVER= curl -fsSL ... | bash" - exit 1 - fi -} - -# Generate random password if not provided -# Note: uses head -c with || true to avoid SIGPIPE with pipefail -generate_password() { - head -c 100 /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 16 || true -} - -# Get Tailscale FQDN hostname from Self.DNSName -# Extracts DNSName from the Self object in tailscale status --json -get_tailscale_hostname() { - local dns_name - # Use awk to extract Self.DNSName specifically (not from peers) - # Looks for DNSName within the Self block - dns_name=$(tailscale status --json 2>/dev/null | awk -F'"' ' - /"Self"/ { in_self=1 } - in_self && /"DNSName"/ { gsub(/\.$/, "", $4); print $4; exit } - ' || true) - - if [[ -z "$dns_name" ]]; then - # Fallback: use hostname + default tailnet domain hint - dns_name="${HOSTNAME}.ts.net" - log_warn "Could not determine Tailscale FQDN, using fallback: $dns_name" - fi - echo "$dns_name" -} - -# Configuration variables (can be overridden via environment) -HOSTNAME="${SEEDBOX_HOSTNAME:-seedbox}" -# NFS shares configuration -NFS_SHARE_DOWNLOAD="${NFS_SHARE_DOWNLOAD:-/volume2/Downloads}" -NFS_SHARE_MEDIA="${NFS_SHARE_MEDIA:-/volume2/Multimédia}" -NFS_MOUNT_DOWNLOAD="${NFS_MOUNT_DOWNLOAD:-/mnt/download}" -NFS_MOUNT_MEDIA="${NFS_MOUNT_MEDIA:-/mnt/media}" -# NFS mount options (same as Proxmox) -NFS_OPTS="defaults,_netdev,nofail,x-systemd.automount,x-systemd.mount-timeout=30s" -PEER_PORT="${PEER_PORT:-51413}" -TIMEZONE="${TZ:-Europe/Paris}" -TRANSMISSION_USER="${TRANSMISSION_USER:-admin}" -TRANSMISSION_PASS="${TRANSMISSION_PASS:-$(generate_password)}" -TRANSMISSION_DIR="$HOME/transmission" - main() { - log_info "=== Seedbox Server Deployment ===" + log_info "=== Seedbox Server Setup ===" check_root check_debian - check_required_vars + # Step 1: System update + log_info "Updating system..." + sudo apt-get update -qq + sudo apt-get upgrade -y -qq + + # Step 2: Set hostname log_info "Setting hostname to: $HOSTNAME" echo "$HOSTNAME" | sudo tee /etc/hostname > /dev/null sudo hostnamectl set-hostname "$HOSTNAME" + # Step 3: Install base packages log_info "Installing base packages..." - sudo apt-get update -qq - sudo apt-get install -y -qq vim ca-certificates curl gnupg lsb-release fail2ban unattended-upgrades nfs-common ufw at > /dev/null + sudo apt-get install -y -qq \ + vim \ + ca-certificates \ + curl \ + gnupg \ + lsb-release \ + fail2ban \ + unattended-upgrades \ + nfs-common \ + ufw \ + at \ + git \ + > /dev/null + # Step 4: Install Tailscale log_info "Installing Tailscale..." curl -fsSL https://tailscale.com/install.sh | sh - log_info "Connecting to Tailscale..." + log_info "Connecting to Tailscale (SSH only)..." sudo tailscale up --ssh + + # Get Tailscale hostname for display + TS_FQDN=$(tailscale status --json 2>/dev/null | awk -F'"' ' + /"Self"/ { in_self=1 } + in_self && /"DNSName"/ { gsub(/\.$/, "", $4); print $4; exit } + ' || echo "${HOSTNAME}.ts.net") + # Step 5: Install Docker log_info "Installing Docker..." - # Use official Docker installation method (DEB822 format) - # See: https://docs.docker.com/engine/install/debian/ sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc - # Add Docker repository using DEB822 format (.sources) # shellcheck disable=SC1091 sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null < /dev/null + sudo apt-get install -y -qq \ + docker-ce \ + docker-ce-cli \ + containerd.io \ + docker-buildx-plugin \ + docker-compose-plugin \ + > /dev/null + # Step 6: Configure Docker for user log_info "Adding current user to docker group..." sudo usermod -aG docker "$USER" - log_info "Configuring NFS mounts..." - sudo mkdir -p "$NFS_MOUNT_DOWNLOAD" "$NFS_MOUNT_MEDIA" - - # Add download share to fstab if not already present - if ! grep -q "${NFS_SERVER}:${NFS_SHARE_DOWNLOAD}" /etc/fstab; then - log_info "Adding NFS mount: ${NFS_SERVER}:${NFS_SHARE_DOWNLOAD} -> ${NFS_MOUNT_DOWNLOAD}" - echo "${NFS_SERVER}:${NFS_SHARE_DOWNLOAD} ${NFS_MOUNT_DOWNLOAD} nfs ${NFS_OPTS} 0 0" | sudo tee -a /etc/fstab > /dev/null - fi - - # Add media share to fstab if not already present - if ! grep -q "${NFS_SERVER}:${NFS_SHARE_MEDIA}" /etc/fstab; then - log_info "Adding NFS mount: ${NFS_SERVER}:${NFS_SHARE_MEDIA} -> ${NFS_MOUNT_MEDIA}" - echo "${NFS_SERVER}:${NFS_SHARE_MEDIA} ${NFS_MOUNT_MEDIA} nfs ${NFS_OPTS} 0 0" | sudo tee -a /etc/fstab > /dev/null - fi - - # Mount NFS shares - sudo mount -a || log_warn "NFS mount failed - ensure NAS is accessible via Tailscale" - - log_info "Creating Transmission stack..." - mkdir -p "$TRANSMISSION_DIR" - - cat > "$TRANSMISSION_DIR/docker-compose.yml" << EOF -services: - transmission: - image: linuxserver/transmission:latest - container_name: transmission - restart: unless-stopped - ports: - # Peer port - public for seeding - - "${PEER_PORT}:${PEER_PORT}" - - "${PEER_PORT}:${PEER_PORT}/udp" - # WebUI - bound to localhost only (exposed via tailscale serve) - - "127.0.0.1:9091:9091" - volumes: - - ./config:/config - # Downloads: incomplete and complete torrents - - ${NFS_MOUNT_DOWNLOAD}:/downloads - # Media: final destination for completed ISOs and images - - ${NFS_MOUNT_MEDIA}:/media - environment: - - PUID=1000 - - PGID=1000 - - TZ=${TIMEZONE} - - USER=${TRANSMISSION_USER} - - PASS=${TRANSMISSION_PASS} - - PEERPORT=${PEER_PORT} -EOF - - log_info "Starting Transmission..." - cd "$TRANSMISSION_DIR" - # Use sg to run docker compose with the new docker group membership - sg docker -c "docker compose up -d" - - log_info "Exposing Transmission WebUI via Tailscale..." - sudo tailscale serve --bg http://localhost:9091 - - # Get Tailscale hostname for final message - TS_HOSTNAME=$(get_tailscale_hostname) - + # Step 7: Configure UFW firewall log_info "Configuring UFW firewall..." sudo ufw --force reset > /dev/null sudo ufw default deny incoming > /dev/null sudo ufw default allow outgoing > /dev/null - # Allow BitTorrent peer port from public internet - sudo ufw allow ${PEER_PORT}/tcp > /dev/null - sudo ufw allow ${PEER_PORT}/udp > /dev/null + # BitTorrent peer port (public) + sudo ufw allow 51413/tcp > /dev/null + sudo ufw allow 51413/udp > /dev/null # Allow all traffic on Tailscale interface sudo ufw allow in on tailscale0 > /dev/null - # Temporarily allow SSH during setup (safety net) + # Temporary SSH access (safety net) sudo ufw allow 22/tcp > /dev/null sudo ufw --force enable > /dev/null # Schedule SSH rule removal in 5 minutes log_warn "SSH port 22 temporarily open for 5 minutes (safety net)." - log_warn "Verify Tailscale SSH access works, then wait or run: sudo ufw delete allow 22/tcp" - echo "sudo ufw delete allow 22/tcp && logger 'UFW: SSH port 22 closed by scheduled task'" | sudo at now + 5 minutes 2>/dev/null || { - log_warn "Could not schedule automatic SSH cleanup. Run manually after verification:" + echo "sudo ufw delete allow 22/tcp && logger 'UFW: SSH port 22 closed'" | sudo at now + 5 minutes 2>/dev/null || { + log_warn "Could not schedule automatic SSH cleanup. Run manually:" log_warn " sudo ufw delete allow 22/tcp" } + # Step 8: Create directory structure + log_info "Creating directory structure..." + sudo mkdir -p "$SEEDBOX_DIR" + sudo mkdir -p "$DOWNLOADS_DIR" + sudo chown -R "$USER:$USER" "$SEEDBOX_DIR" + + # Step 9: Configure NFS mount (if NFS_SERVER provided) + if [[ -n "$NFS_SERVER" ]]; then + log_info "Configuring NFS mount..." + sudo mkdir -p "$NFS_MOUNT_MEDIA" + + if ! grep -q "${NFS_SERVER}:${NFS_SHARE_MEDIA}" /etc/fstab; then + log_info "Adding NFS mount: ${NFS_SERVER}:${NFS_SHARE_MEDIA} -> ${NFS_MOUNT_MEDIA}" + echo "${NFS_SERVER}:${NFS_SHARE_MEDIA} ${NFS_MOUNT_MEDIA} nfs ${NFS_OPTS} 0 0" | sudo tee -a /etc/fstab > /dev/null + fi + + sudo mount -a || log_warn "NFS mount failed - ensure NAS is accessible via Tailscale" + else + log_warn "NFS_SERVER not set. NFS mount skipped. Set it later if needed." + fi + + # Step 10: Clone repository + log_info "Cloning infra-scripts repository..." + if [[ -d "${SEEDBOX_DIR}/.git" ]]; then + cd "$SEEDBOX_DIR" + git pull origin main || log_warn "Git pull failed" + else + git clone "$REPO_URL" "${SEEDBOX_DIR}/repo-tmp" + mv "${SEEDBOX_DIR}/repo-tmp/seedbox/"* "$SEEDBOX_DIR/" 2>/dev/null || true + mv "${SEEDBOX_DIR}/repo-tmp/seedbox/".* "$SEEDBOX_DIR/" 2>/dev/null || true + rm -rf "${SEEDBOX_DIR}/repo-tmp" + cd "$SEEDBOX_DIR" + git init + git remote add origin "$REPO_URL" + git fetch origin + git checkout -b main --track origin/main -- seedbox/ 2>/dev/null || true + fi + + # Step 11: Configure MOTD log_info "Configuring MOTD..." sudo chmod -x /etc/update-motd.d/* 2>/dev/null || true cat << 'MOTD' | sudo tee /etc/update-motd.d/00-seedbox > /dev/null #!/bin/bash -# Get Tailscale FQDN from Self.DNSName TS_FQDN=$(tailscale status --json 2>/dev/null | awk -F'"' ' /"Self"/ { in_self=1 } in_self && /"DNSName"/ { gsub(/\.$/, "", $4); print $4; exit } @@ -223,49 +196,56 @@ echo "\___ \| _| | _| | | | | _ \| | | \ /" echo " ___) | |___| |___| |_| | |_) | |_| / \\" echo "|____/|_____|_____|____/|____/ \___/_/\_\\" echo "" -echo "ISO Seedbox Server - Transmission" +echo "Docker Seedbox Server" echo "─────────────────────────────────────────" echo "Access:" -echo " • WebUI : https://${TS_FQDN}" -echo " • SSH : Tailscale only" -echo " • Seeding : Public port 51413" +echo " • SSH : ${TS_FQDN}" +echo " • Seeding : Public port 51413" +echo "" +echo "Services: (via Tailscale)" +docker ps --format ' • {{.Names}} : {{.Status}}' 2>/dev/null || echo " Docker not running" echo "" echo "Storage:" -echo " • Downloads : /mnt/download" -echo " • Media : /mnt/media" +echo " • Downloads : /srv/seedbox/downloads" +echo " • Media : /mnt/media (NFS)" echo "" echo "Useful commands:" -echo " cd ~/transmission && docker compose logs -f" -echo " df -h /mnt/download /mnt/media" +echo " cd /srv/seedbox && docker compose ls" +echo " docker logs -f " echo "─────────────────────────────────────────" echo "" MOTD sudo chmod +x /etc/update-motd.d/00-seedbox + # Final summary echo "" log_info "==========================================" - log_info "Deployment complete!" + log_info "Server setup complete!" log_info "==========================================" echo "" - echo "Transmission WebUI:" - echo " URL : https://${TS_HOSTNAME}" - echo " Username : ${TRANSMISSION_USER}" - echo " Password : ${TRANSMISSION_PASS}" + echo "Server accessible at:" + echo " SSH: ${TS_FQDN}" echo "" - echo "Storage (NFS mounts):" - echo " Downloads : ${NFS_SERVER}:${NFS_SHARE_DOWNLOAD} -> ${NFS_MOUNT_DOWNLOAD}" - echo " Media : ${NFS_SERVER}:${NFS_SHARE_MEDIA} -> ${NFS_MOUNT_MEDIA}" + echo "Directory structure:" + echo " ${SEEDBOX_DIR}/" + echo " ├── stacks/ # Docker Compose stacks" + echo " ├── downloads/ # Local downloads (SSD)" + echo " └── .env # Secrets (created by Gitea Actions)" echo "" - echo "Transmission paths:" - echo " /downloads -> ${NFS_MOUNT_DOWNLOAD} (incomplete + complete torrents)" - echo " /media -> ${NFS_MOUNT_MEDIA} (final destination for ISOs)" + echo "NFS mount:" + if [[ -n "$NFS_SERVER" ]]; then + echo " ${NFS_SERVER}:${NFS_SHARE_MEDIA} -> ${NFS_MOUNT_MEDIA}" + else + echo " Not configured. Run with NFS_SERVER= to configure." + fi echo "" - echo "Peer port : ${PEER_PORT} (public)" + echo "Next steps:" + echo " 1. Configure Gitea secrets (see README.md)" + echo " 2. Push to main branch to trigger deployment" + echo " 3. Services will be available at .taila5ad8.ts.net" echo "" log_warn "SSH port 22 will be closed in 5 minutes." - log_warn "To cancel: sudo atq (list jobs) then sudo atrm " - echo "" - echo "Save these credentials! The password was auto-generated." + log_warn "Use Tailscale SSH: ssh ${TS_FQDN}" echo "" } -- 2.52.0 From c601e3593078e9c75806d359013b7fc556767ee5 Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:23:25 +0000 Subject: [PATCH 02/15] docs(seedbox): add .env.example with secrets documentation --- seedbox/.env.example | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 seedbox/.env.example diff --git a/seedbox/.env.example b/seedbox/.env.example new file mode 100644 index 0000000..1e4f734 --- /dev/null +++ b/seedbox/.env.example @@ -0,0 +1,20 @@ +# Gitea secrets required for seedbox deployment +# +# Configure these in: Gitea > Repository > Settings > Secrets and Variables > Actions +# +# TS_AUTHKEY - Tailscale OAuth client secret (recommended) or auth key +# Create at: https://login.tailscale.com/admin/settings/oauth +# Required scopes: devices:write +# Format: tskey-client-xxxxx-yyyyyyyy +# +# SEEDBOX_SSH_KEY - SSH private key for deployment +# Generate with: ssh-keygen -t ed25519 -f seedbox-deploy -N "" +# Add public key to seedbox: ~/.ssh/authorized_keys +# +# TRANSMISSION_USER - Transmission WebUI username (default: admin) +# TRANSMISSION_PASS - Transmission WebUI password + +# Example .env file (DO NOT COMMIT WITH REAL VALUES) +TS_AUTHKEY=tskey-client-xxxxx-yyyyyyyy +TRANSMISSION_USER=admin +TRANSMISSION_PASS=changeme -- 2.52.0 From 9afaf880a9396423937f840a8dc06007243a73a0 Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:23:44 +0000 Subject: [PATCH 03/15] ci(seedbox): add Gitea Actions deployment pipeline - Deploy on push to main and PR validation - SSH deployment to seedbox via Tailscale - Inject secrets from Gitea - Deploy all stacks in stacks/ directory --- seedbox/.gitea/workflows/deploy.yml | 91 +++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 seedbox/.gitea/workflows/deploy.yml diff --git a/seedbox/.gitea/workflows/deploy.yml b/seedbox/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..b74bd6b --- /dev/null +++ b/seedbox/.gitea/workflows/deploy.yml @@ -0,0 +1,91 @@ +name: Deploy Seedbox + +on: + push: + branches: [main] + paths: + - 'seedbox/**' + pull_request: + branches: [main] + paths: + - 'seedbox/**' + +jobs: + deploy: + name: Deploy Seedbox Stacks + runs-on: self-hosted + container: + image: alpine:latest + + steps: + - name: Install dependencies + run: apk add --no-cache openssh-client git + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup SSH key + run: | + mkdir -p ~/.ssh + echo "${{ secrets.SEEDBOX_SSH_KEY }}" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + # Trust the seedbox host + ssh-keyscan -H seedbox.taila5ad8.ts.net >> ~/.ssh/known_hosts 2>/dev/null || true + + - name: Validate compose files (PR only) + if: github.event_name == 'pull_request' + run: | + echo "Validating docker-compose files..." + for stack in seedbox/stacks/*/; do + if [ -f "${stack}docker-compose.yml" ]; then + echo "✓ ${stack}docker-compose.yml exists" + fi + done + echo "Validation complete." + + - name: Deploy to seedbox + if: github.event_name == 'push' + run: | + ssh -o StrictHostKeyChecking=accept-new debian@seedbox.taila5ad8.ts.net << 'ENDSSH' + set -e + cd /srv/seedbox + + echo "=== Pulling latest changes ===" + git fetch origin main + git reset --hard origin/main + + echo "=== Creating .env file ===" + cat > .env << 'ENVEOF' + TS_AUTHKEY=${{ secrets.TS_AUTHKEY }} + TRANSMISSION_USER=${{ secrets.TRANSMISSION_USER }} + TRANSMISSION_PASS=${{ secrets.TRANSMISSION_PASS }} + ENVEOF + chmod 600 .env + + echo "=== Deploying stacks ===" + for stack in stacks/*/; do + if [ -f "${stack}docker-compose.yml" ]; then + stack_name=$(basename "$stack") + echo "Deploying ${stack_name}..." + docker compose -f "${stack}docker-compose.yml" --env-file .env pull + docker compose -f "${stack}docker-compose.yml" --env-file .env up -d --remove-orphans + fi + done + + echo "=== Cleanup unused images ===" + docker image prune -f + + echo "=== Current status ===" + docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' + ENDSSH + + - name: Deployment summary + if: github.event_name == 'push' + run: | + echo "✅ Deployment complete!" + echo "" + echo "Services should be available at:" + echo " • transmission.taila5ad8.ts.net" + echo " • portainer.taila5ad8.ts.net" + echo " • prowlarr.taila5ad8.ts.net" + echo " • sonarr.taila5ad8.ts.net" -- 2.52.0 From 86441327b9bdae01b5decd1427eb3ffd028efd3a Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:23:54 +0000 Subject: [PATCH 04/15] feat(seedbox): add Transmission stack with Tailscale sidecar - WebUI accessible via transmission.taila5ad8.ts.net (HTTPS) - Peer port 51413 exposed publicly for seeding - Local downloads + NFS media mount --- .../stacks/transmission/docker-compose.yml | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 seedbox/stacks/transmission/docker-compose.yml diff --git a/seedbox/stacks/transmission/docker-compose.yml b/seedbox/stacks/transmission/docker-compose.yml new file mode 100644 index 0000000..03b5d5a --- /dev/null +++ b/seedbox/stacks/transmission/docker-compose.yml @@ -0,0 +1,45 @@ +services: + ts-transmission: + image: tailscale/tailscale:latest + hostname: transmission + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_EXTRA_ARGS=--advertise-tags=tag:container + - TS_STATE_DIR=/var/lib/tailscale + - TS_SERVE_CONFIG=/config/serve.json + - TS_USERSPACE=false + volumes: + - ts-state:/var/lib/tailscale + - ./serve.json:/config/serve.json:ro + devices: + - /dev/net/tun:/dev/net/tun + cap_add: + - net_admin + ports: + # BitTorrent peer port - exposed publicly for seeding + - "51413:51413" + - "51413:51413/udp" + restart: unless-stopped + + transmission: + image: linuxserver/transmission:latest + container_name: transmission + network_mode: service:ts-transmission + depends_on: + - ts-transmission + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Paris + - USER=${TRANSMISSION_USER:-admin} + - PASS=${TRANSMISSION_PASS} + - PEERPORT=51413 + volumes: + - config:/config + - /srv/seedbox/downloads:/downloads + - /mnt/media:/media + restart: unless-stopped + +volumes: + ts-state: + config: -- 2.52.0 From 333aa103c26a3ad2b9310dfd961a87aa5ad48aef Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:24:00 +0000 Subject: [PATCH 05/15] feat(seedbox): add Tailscale Serve config for Transmission --- seedbox/stacks/transmission/serve.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 seedbox/stacks/transmission/serve.json diff --git a/seedbox/stacks/transmission/serve.json b/seedbox/stacks/transmission/serve.json new file mode 100644 index 0000000..2be2bfb --- /dev/null +++ b/seedbox/stacks/transmission/serve.json @@ -0,0 +1,16 @@ +{ + "TCP": { + "443": { + "HTTPS": true + } + }, + "Web": { + "transmission.taila5ad8.ts.net:443": { + "Handlers": { + "/": { + "Proxy": "http://127.0.0.1:9091" + } + } + } + } +} -- 2.52.0 From 4473779d558154eb979496b9d5d0c1226b3ade3d Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:24:07 +0000 Subject: [PATCH 06/15] feat(seedbox): add Portainer stack with Tailscale sidecar - Accessible via portainer.taila5ad8.ts.net (HTTPS only) - Docker socket mounted for container management --- seedbox/stacks/portainer/docker-compose.yml | 33 +++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 seedbox/stacks/portainer/docker-compose.yml diff --git a/seedbox/stacks/portainer/docker-compose.yml b/seedbox/stacks/portainer/docker-compose.yml new file mode 100644 index 0000000..12f381f --- /dev/null +++ b/seedbox/stacks/portainer/docker-compose.yml @@ -0,0 +1,33 @@ +services: + ts-portainer: + image: tailscale/tailscale:latest + hostname: portainer + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_EXTRA_ARGS=--advertise-tags=tag:container + - TS_STATE_DIR=/var/lib/tailscale + - TS_SERVE_CONFIG=/config/serve.json + - TS_USERSPACE=false + volumes: + - ts-state:/var/lib/tailscale + - ./serve.json:/config/serve.json:ro + devices: + - /dev/net/tun:/dev/net/tun + cap_add: + - net_admin + restart: unless-stopped + + portainer: + image: portainer/portainer-ce:latest + container_name: portainer + network_mode: service:ts-portainer + depends_on: + - ts-portainer + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - data:/data + restart: unless-stopped + +volumes: + ts-state: + data: -- 2.52.0 From 4fe08a130ba85c8a212b189a13410c7f20e421ee Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:24:18 +0000 Subject: [PATCH 07/15] feat(seedbox): add Tailscale Serve config for Portainer --- seedbox/stacks/portainer/serve.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 seedbox/stacks/portainer/serve.json diff --git a/seedbox/stacks/portainer/serve.json b/seedbox/stacks/portainer/serve.json new file mode 100644 index 0000000..f9a8af8 --- /dev/null +++ b/seedbox/stacks/portainer/serve.json @@ -0,0 +1,16 @@ +{ + "TCP": { + "443": { + "HTTPS": true + } + }, + "Web": { + "portainer.taila5ad8.ts.net:443": { + "Handlers": { + "/": { + "Proxy": "http://127.0.0.1:9000" + } + } + } + } +} -- 2.52.0 From 5928b5e990d6a0b4e23064252ec57605295223ba Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:24:24 +0000 Subject: [PATCH 08/15] feat(seedbox): add Prowlarr stack with Tailscale sidecar - Indexer manager for *arr apps - Accessible via prowlarr.taila5ad8.ts.net (HTTPS only) --- seedbox/stacks/prowlarr/docker-compose.yml | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 seedbox/stacks/prowlarr/docker-compose.yml diff --git a/seedbox/stacks/prowlarr/docker-compose.yml b/seedbox/stacks/prowlarr/docker-compose.yml new file mode 100644 index 0000000..4157c75 --- /dev/null +++ b/seedbox/stacks/prowlarr/docker-compose.yml @@ -0,0 +1,36 @@ +services: + ts-prowlarr: + image: tailscale/tailscale:latest + hostname: prowlarr + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_EXTRA_ARGS=--advertise-tags=tag:container + - TS_STATE_DIR=/var/lib/tailscale + - TS_SERVE_CONFIG=/config/serve.json + - TS_USERSPACE=false + volumes: + - ts-state:/var/lib/tailscale + - ./serve.json:/config/serve.json:ro + devices: + - /dev/net/tun:/dev/net/tun + cap_add: + - net_admin + restart: unless-stopped + + prowlarr: + image: linuxserver/prowlarr:latest + container_name: prowlarr + network_mode: service:ts-prowlarr + depends_on: + - ts-prowlarr + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Paris + volumes: + - config:/config + restart: unless-stopped + +volumes: + ts-state: + config: -- 2.52.0 From 6e13516d715be4a462e2611a344c8deb90156da9 Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:24:37 +0000 Subject: [PATCH 09/15] feat(seedbox): add Tailscale Serve config for Prowlarr --- seedbox/stacks/prowlarr/serve.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 seedbox/stacks/prowlarr/serve.json diff --git a/seedbox/stacks/prowlarr/serve.json b/seedbox/stacks/prowlarr/serve.json new file mode 100644 index 0000000..decfb5b --- /dev/null +++ b/seedbox/stacks/prowlarr/serve.json @@ -0,0 +1,16 @@ +{ + "TCP": { + "443": { + "HTTPS": true + } + }, + "Web": { + "prowlarr.taila5ad8.ts.net:443": { + "Handlers": { + "/": { + "Proxy": "http://127.0.0.1:9696" + } + } + } + } +} -- 2.52.0 From 1935d7fc9905220d58ae5e90f645129eb0a84337 Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:24:43 +0000 Subject: [PATCH 10/15] feat(seedbox): add Sonarr stack with Tailscale sidecar - TV series management - Accessible via sonarr.taila5ad8.ts.net (HTTPS only) - Mounts downloads and media volumes --- seedbox/stacks/sonarr/docker-compose.yml | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 seedbox/stacks/sonarr/docker-compose.yml diff --git a/seedbox/stacks/sonarr/docker-compose.yml b/seedbox/stacks/sonarr/docker-compose.yml new file mode 100644 index 0000000..0ec5b6e --- /dev/null +++ b/seedbox/stacks/sonarr/docker-compose.yml @@ -0,0 +1,38 @@ +services: + ts-sonarr: + image: tailscale/tailscale:latest + hostname: sonarr + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_EXTRA_ARGS=--advertise-tags=tag:container + - TS_STATE_DIR=/var/lib/tailscale + - TS_SERVE_CONFIG=/config/serve.json + - TS_USERSPACE=false + volumes: + - ts-state:/var/lib/tailscale + - ./serve.json:/config/serve.json:ro + devices: + - /dev/net/tun:/dev/net/tun + cap_add: + - net_admin + restart: unless-stopped + + sonarr: + image: linuxserver/sonarr:latest + container_name: sonarr + network_mode: service:ts-sonarr + depends_on: + - ts-sonarr + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Paris + volumes: + - config:/config + - /srv/seedbox/downloads:/downloads + - /mnt/media:/media + restart: unless-stopped + +volumes: + ts-state: + config: -- 2.52.0 From 979040a4c739e033ef659f31dedd4a8d479e3426 Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:29:49 +0000 Subject: [PATCH 11/15] docs(seedbox): complete README rewrite for new architecture - Document Docker + Tailscale sidecar architecture - Add Gitea secrets configuration guide - Add service management (add/remove/update) - Add troubleshooting section - Add Tailscale ACL configuration --- seedbox/README.md | 464 ++++++++++++++++++++++++++++++---------------- 1 file changed, 302 insertions(+), 162 deletions(-) diff --git a/seedbox/README.md b/seedbox/README.md index 22fabde..d5f7f4d 100644 --- a/seedbox/README.md +++ b/seedbox/README.md @@ -1,214 +1,354 @@ # Seedbox Server -Deploys a seedbox with Transmission for maintaining Linux ISO mirrors and OS images. +Docker-based seedbox with Tailscale integration. Each service runs in its own container with a Tailscale sidecar for secure HTTPS access via your tailnet. + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ SEEDBOX │ +│ │ +│ Tailscale Host (SSH only) │ +│ └─► seedbox.taila5ad8.ts.net │ +│ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ Docker Stacks │ │ +│ │ │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ +│ │ │ Transmission│ │ Prowlarr │ │ Sonarr │ │ │ +│ │ │ + ts-sidecar│ │ + ts-sidecar│ │ + ts-sidecar│ │ │ +│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ +│ │ │ │ │ │ │ +│ │ ▼ ▼ ▼ │ │ +│ │ transmission. prowlarr. sonarr. │ │ +│ │ taila5ad8.ts.net taila5ad8.ts.net taila5ad8.ts.net │ │ +│ │ │ │ +│ │ ┌─────────────┐ │ │ +│ │ │ Portainer │ (optional, for monitoring) │ │ +│ │ │ + ts-sidecar│ │ │ +│ │ └─────────────┘ │ │ +│ │ │ │ │ +│ │ ▼ │ │ +│ │ portainer.taila5ad8.ts.net │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +│ Storage: │ +│ ├─ /srv/seedbox/downloads (local SSD) │ +│ └─ /mnt/media (NFS from NAS) │ +└─────────────────────────────────────────────────────────────────┘ +``` ## Quick Start +### 1. Server Installation + ```bash -NFS_SERVER=nas TRANSMISSION_PASS=MySecureP@ss123 \ +# With NFS mount +NFS_SERVER=nas curl -fsSL https://gitea.arnodo.fr/Damien/infra-scripts/raw/branch/main/seedbox/install.sh | bash + +# Without NFS (configure later) curl -fsSL https://gitea.arnodo.fr/Damien/infra-scripts/raw/branch/main/seedbox/install.sh | bash ``` -> **⚠️ Important:** Always set `TRANSMISSION_PASS` explicitly. If omitted, a random password is generated and displayed only once at the end of the installation. It cannot be recovered afterward without resetting the config. +### 2. Configure Gitea Secrets -## Components +Go to **Gitea > Repository > Settings > Secrets and Variables > Actions** and add: -- **Transmission**: BitTorrent client with WebUI -- **NFS**: Dual mount to NAS for downloads and media storage -- **Tailscale**: Private access to WebUI via `tailscale serve` -- **Docker**: Container runtime -- **UFW**: Firewall (only peer port exposed publicly) -- **fail2ban** + **unattended-upgrades**: Basic hardening +| Secret | Description | Example | +|--------|-------------|---------| +| `TS_AUTHKEY` | Tailscale OAuth client secret | `tskey-client-xxxxx-yyyyyyyy` | +| `SEEDBOX_SSH_KEY` | SSH private key (ed25519) | `-----BEGIN OPENSSH PRIVATE KEY-----...` | +| `TRANSMISSION_USER` | Transmission WebUI username | `admin` | +| `TRANSMISSION_PASS` | Transmission WebUI password | `your-secure-password` | -## Environment Variables +#### Creating Tailscale OAuth Client -| Variable | Default | Description | -|----------|---------|-------------| -| `NFS_SERVER` | *required* | NAS hostname/IP (Tailscale) | -| `NFS_SHARE_DOWNLOAD` | `/volume2/Downloads` | NFS export for downloads | -| `NFS_SHARE_MEDIA` | `/volume2/Multimédia` | NFS export for media/ISOs | -| `NFS_MOUNT_DOWNLOAD` | `/mnt/download` | Local mount for downloads | -| `NFS_MOUNT_MEDIA` | `/mnt/media` | Local mount for media | -| `SEEDBOX_HOSTNAME` | `seedbox` | Server hostname | -| `PEER_PORT` | `51413` | BitTorrent peer port | -| `TRANSMISSION_USER` | `admin` | WebUI username | -| `TRANSMISSION_PASS` | *auto-generated* | WebUI password (⚠️ set explicitly!) | -| `TZ` | `Europe/Paris` | Timezone | +1. Go to https://login.tailscale.com/admin/settings/oauth +2. Click "Generate OAuth Client" +3. Scopes: `devices:write` +4. Copy the **Client Secret** (starts with `tskey-client-`) -Example with custom settings: +#### Creating SSH Deploy Key ```bash -NFS_SERVER=nas \ -NFS_SHARE_DOWNLOAD=/volume1/torrents \ -NFS_SHARE_MEDIA=/volume1/iso \ -TRANSMISSION_USER=damien \ -TRANSMISSION_PASS=MySecurePassword \ -curl -fsSL https://gitea.arnodo.fr/Damien/infra-scripts/raw/branch/main/seedbox/install.sh | bash +# Generate key pair +ssh-keygen -t ed25519 -f seedbox-deploy -N "" -C "gitea-deploy" + +# Add public key to seedbox +ssh debian@seedbox.taila5ad8.ts.net "cat >> ~/.ssh/authorized_keys" < seedbox-deploy.pub + +# Copy private key content to Gitea secret SEEDBOX_SSH_KEY +cat seedbox-deploy ``` -### Password Recovery +#### Tailscale ACL Configuration -If you forgot to set `TRANSMISSION_PASS` and lost the auto-generated password: +Add this tag to your Tailscale ACL policy (https://login.tailscale.com/admin/acls): + +```json +{ + "tagOwners": { + "tag:container": ["autogroup:admin"] + }, + "acls": [ + { + "action": "accept", + "src": ["autogroup:member"], + "dst": ["tag:container:*"] + } + ] +} +``` + +### 3. Deploy Services + +Push to the `main` branch to trigger deployment: ```bash -# Option 1: Check the docker-compose.yml (password in clear text) -grep PASS ~/transmission/docker-compose.yml +git push origin main +``` -# Option 2: Reset by editing docker-compose.yml -cd ~/transmission -sed -i 's/PASS=.*/PASS=NewPassword/' docker-compose.yml -docker compose down && docker compose up -d +Or create a PR for validation first. + +## Services + +| Service | URL | Port | Description | +|---------|-----|------|-------------| +| Transmission | `transmission.taila5ad8.ts.net` | 9091 | BitTorrent client | +| Prowlarr | `prowlarr.taila5ad8.ts.net` | 9696 | Indexer manager | +| Sonarr | `sonarr.taila5ad8.ts.net` | 8989 | TV series manager | +| Portainer | `portainer.taila5ad8.ts.net` | 9000 | Docker management UI | + +## Directory Structure + +``` +/srv/seedbox/ +├── stacks/ +│ ├── transmission/ +│ │ ├── docker-compose.yml +│ │ └── serve.json +│ ├── prowlarr/ +│ │ ├── docker-compose.yml +│ │ └── serve.json +│ ├── sonarr/ +│ │ ├── docker-compose.yml +│ │ └── serve.json +│ └── portainer/ +│ ├── docker-compose.yml +│ └── serve.json +├── downloads/ # Local downloads (SSD) +├── .env # Secrets (created by pipeline) +└── .gitea/ + └── workflows/ + └── deploy.yml # Deployment pipeline +``` + +## Adding a New Service + +1. Create a new directory in `stacks/`: + +```bash +mkdir -p seedbox/stacks/myservice +``` + +2. Create `docker-compose.yml`: + +```yaml +services: + ts-myservice: + image: tailscale/tailscale:latest + hostname: myservice + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_EXTRA_ARGS=--advertise-tags=tag:container + - TS_STATE_DIR=/var/lib/tailscale + - TS_SERVE_CONFIG=/config/serve.json + - TS_USERSPACE=false + volumes: + - ts-state:/var/lib/tailscale + - ./serve.json:/config/serve.json:ro + devices: + - /dev/net/tun:/dev/net/tun + cap_add: + - net_admin + restart: unless-stopped + + myservice: + image: myservice/image:latest + container_name: myservice + network_mode: service:ts-myservice + depends_on: + - ts-myservice + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Paris + volumes: + - config:/config + restart: unless-stopped + +volumes: + ts-state: + config: +``` + +3. Create `serve.json`: + +```json +{ + "TCP": { + "443": { + "HTTPS": true + } + }, + "Web": { + "myservice.taila5ad8.ts.net:443": { + "Handlers": { + "/": { + "Proxy": "http://127.0.0.1:PORT" + } + } + } + } +} +``` + +4. Commit and push: + +```bash +git add seedbox/stacks/myservice/ +git commit -m "feat(seedbox): add myservice stack" +git push origin main +``` + +## Removing a Service + +### Option A: Via Git (recommended) + +1. Remove the stack directory: + +```bash +rm -rf seedbox/stacks/myservice/ +git add -A +git commit -m "feat(seedbox): remove myservice stack" +git push origin main +``` + +2. Manually stop containers on seedbox: + +```bash +ssh debian@seedbox.taila5ad8.ts.net +cd /srv/seedbox/stacks/myservice +docker compose down -v +``` + +3. Remove Tailscale device from admin console + +### Option B: Manual (emergency) + +```bash +ssh debian@seedbox.taila5ad8.ts.net +cd /srv/seedbox/stacks/myservice +docker compose down -v +rm -rf /srv/seedbox/stacks/myservice +# Remove device from https://login.tailscale.com/admin/machines +``` + +## Updating Services + +### Update Docker Images + +The pipeline automatically pulls latest images on each deployment. To force an update: + +```bash +# Trigger a new deployment by making any change +git commit --allow-empty -m "chore: trigger deployment" +git push origin main +``` + +### Manual Update + +```bash +ssh debian@seedbox.taila5ad8.ts.net +cd /srv/seedbox/stacks/transmission +docker compose pull +docker compose up -d ``` ## Network Access | Service | Public | Tailscale | |---------|--------|-----------| -| BitTorrent peers | ✅ Port 51413 | ✅ | -| Transmission WebUI | ❌ | ✅ HTTPS via `tailscale serve` | -| SSH | ❌ | ✅ Tailscale SSH | -| NFS (to NAS) | ❌ | ✅ | +| SSH | ❌ | ✅ `seedbox.taila5ad8.ts.net` | +| Transmission WebUI | ❌ | ✅ HTTPS via sidecar | +| Transmission Peer | ✅ Port 51413 | ✅ | +| Prowlarr | ❌ | ✅ HTTPS via sidecar | +| Sonarr | ❌ | ✅ HTTPS via sidecar | +| Portainer | ❌ | ✅ HTTPS via sidecar | -### WebUI Access +## Troubleshooting -The WebUI is exposed via Tailscale Serve with automatic HTTPS: - -``` -https://seedbox..ts.net -``` - -The WebUI binds to `localhost:9091` and is proxied through `tailscale serve`, ensuring it's never accessible from the public internet. - -## Storage Architecture - -``` -NAS (via Tailscale) Seedbox LXC (70GB) -┌─────────────────────┐ ┌─────────────────────┐ -│ /volume2/Downloads │◄──── NFS ────►│ /mnt/download │ -│ (incomplete + temp) │ │ └► /downloads │ -├─────────────────────┤ │ (in container) │ -│ /volume2/Multimédia │◄──── NFS ────►│ /mnt/media │ -│ (ISOs, VMDK, QCOW) │ │ └► /media │ -└─────────────────────┘ │ (in container) │ - └─────────────────────┘ -``` - -### Transmission Paths - -| Container Path | Host Path | NAS Path | Purpose | -|----------------|-----------|----------|---------| -| `/downloads` | `/mnt/download` | `/volume2/Downloads` | Incomplete + completed torrents | -| `/media` | `/mnt/media` | `/volume2/Multimédia` | Final ISOs, VMDK, QCOW images | - -### Recommended Workflow - -1. Torrents download to `/downloads` (on NAS via NFS) -2. Once complete, move ISOs to `/media/iso//` -3. Proxmox mounts the same NAS share for VM templates - -## What it does - -1. Sets hostname -2. Installs base packages (vim, fail2ban, unattended-upgrades, nfs-common, at) -3. Installs and connects Tailscale -4. Installs Docker -5. Configures dual NFS mounts to NAS (same as Proxmox) -6. Deploys Transmission container with both mounts -7. Exposes WebUI via `tailscale serve` (HTTPS on tailnet) -8. Configures UFW (peer port public, WebUI via Tailscale only) -9. Temporarily opens SSH port 22 for 5 minutes (safety net) - -## SSH Safety Net - -During installation, SSH port 22 is temporarily opened for 5 minutes to prevent lockout if you're connected via public IP. After 5 minutes, it will be automatically closed and only Tailscale SSH will work. +### Check container status ```bash -# List scheduled jobs -sudo atq - -# Cancel the scheduled SSH closure (replace N with job number) -sudo atrm N - -# Manually close SSH port 22 if needed -sudo ufw delete allow 22/tcp +docker ps -a +docker logs ts-transmission +docker logs transmission ``` -## Directory Structure - -Organize your media by type: +### Check Tailscale sidecar +```bash +docker exec ts-transmission tailscale status +docker exec ts-transmission tailscale serve status ``` -/mnt/media/ -├── iso/ -│ ├── debian/ -│ │ └── debian-12.7.0-amd64-netinst.iso -│ ├── ubuntu/ -│ │ └── ubuntu-24.04.1-live-server-amd64.iso -│ ├── rhel/ -│ │ └── rocky-9.4-x86_64-minimal.iso -│ └── proxmox/ -│ └── proxmox-ve_8.2-1.iso -├── vmdk/ -│ └── windows-server-2022.vmdk -└── qcow/ - └── cloud-init-debian-12.qcow2 + +### Restart a stack + +```bash +cd /srv/seedbox/stacks/transmission +docker compose restart +``` + +### View all Tailscale devices + +```bash +tailscale status +``` + +### Force re-authentication of sidecar + +```bash +cd /srv/seedbox/stacks/transmission +docker compose down +docker volume rm transmission_ts-state +docker compose up -d ``` ## NAS Configuration (Synology) -Ensure your NAS exports both shares via NFS: +Ensure your NAS exports the media share via NFS: -1. Control Panel → Shared Folder → Edit → NFS Permissions -2. For each share (`Downloads` and `Multimédia`), add rule: - - Hostname/IP: `*` or Tailscale IP of seedbox (e.g., `100.x.x.x`) +1. **Control Panel → Shared Folder → Edit → NFS Permissions** +2. Add rule: + - Hostname/IP: `100.64.0.0/10` (Tailscale subnet) or specific IP - Privilege: Read/Write - Squash: No mapping - Security: sys - Enable NFSv4.1: ✅ -## Post-install +## Post-install Verification ```bash -# Check NFS mounts -df -h /mnt/download /mnt/media +# Check NFS mount +df -h /mnt/media -# View Transmission logs -cd ~/transmission && docker compose logs -f +# Check Docker +docker ps -# Restart Transmission -cd ~/transmission && docker compose restart +# Check Tailscale devices +tailscale status -# Check tailscale serve status -tailscale serve status - -# Move completed ISO to final location -mv /mnt/download/debian-12.iso /mnt/media/iso/debian/ -``` - -## Troubleshooting - -### WebUI not accessible - -```bash -# Check tailscale serve is running -tailscale serve status - -# Restart if needed -sudo tailscale serve --bg http://localhost:9091 - -# Check container is running -docker ps | grep transmission - -# Check container logs -cd ~/transmission && docker compose logs -``` - -### Reset Transmission credentials - -```bash -cd ~/transmission -docker compose down -# Edit docker-compose.yml to change USER and PASS -vim docker-compose.yml -docker compose up -d +# Test service access +curl -k https://transmission.taila5ad8.ts.net ``` -- 2.52.0 From be0f6abaa2f61dc452d7d20d0009df72623c46f4 Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:30:00 +0000 Subject: [PATCH 12/15] docs(seedbox): add README for Transmission stack --- seedbox/stacks/transmission/README.md | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 seedbox/stacks/transmission/README.md diff --git a/seedbox/stacks/transmission/README.md b/seedbox/stacks/transmission/README.md new file mode 100644 index 0000000..3a742a7 --- /dev/null +++ b/seedbox/stacks/transmission/README.md @@ -0,0 +1,52 @@ +# Transmission Stack + +BitTorrent client with web interface, accessible via Tailscale. + +## Access + +- **URL**: https://transmission.taila5ad8.ts.net +- **Default credentials**: Set via `TRANSMISSION_USER` and `TRANSMISSION_PASS` secrets + +## Ports + +| Port | Protocol | Exposure | Description | +|------|----------|----------|-------------| +| 9091 | TCP | Tailscale only | WebUI | +| 51413 | TCP/UDP | Public | BitTorrent peer port | + +## Volumes + +| Path in container | Host path | Description | +|-------------------|-----------|-------------| +| `/config` | Docker volume | Transmission configuration | +| `/downloads` | `/srv/seedbox/downloads` | Download directory (local SSD) | +| `/media` | `/mnt/media` | Media library (NFS) | + +## Configuration + +### Download Paths + +In Transmission settings: +- **Download to**: `/downloads` +- **Move completed to**: `/media/downloads` (optional) + +### Peer Port + +The peer port 51413 is exposed publicly for optimal seeding performance. Ensure your firewall/router allows this port. + +## Troubleshooting + +```bash +# Check logs +docker logs transmission + +# Check Tailscale sidecar +docker exec ts-transmission tailscale status + +# Restart stack +cd /srv/seedbox/stacks/transmission +docker compose restart + +# Check WebUI is responding +docker exec ts-transmission curl -s http://127.0.0.1:9091 +``` -- 2.52.0 From 90dfc9ec8a6f5b3403d2492893dd3c93290a13a9 Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:30:08 +0000 Subject: [PATCH 13/15] docs(seedbox): add README for Portainer stack --- seedbox/stacks/portainer/README.md | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 seedbox/stacks/portainer/README.md diff --git a/seedbox/stacks/portainer/README.md b/seedbox/stacks/portainer/README.md new file mode 100644 index 0000000..fa3ae58 --- /dev/null +++ b/seedbox/stacks/portainer/README.md @@ -0,0 +1,52 @@ +# Portainer Stack + +Docker management UI, accessible via Tailscale. + +## Access + +- **URL**: https://portainer.taila5ad8.ts.net +- **Initial setup**: Create admin account on first access + +## Ports + +| Port | Protocol | Exposure | Description | +|------|----------|----------|-------------| +| 9000 | TCP | Tailscale only | WebUI | + +## Features + +- View and manage all Docker containers +- View logs in real-time +- Execute commands in containers +- Manage Docker networks and volumes +- Deploy stacks from templates + +## First Setup + +1. Access https://portainer.taila5ad8.ts.net +2. Create an admin account +3. Select "Docker" as environment type +4. Connect to local Docker socket + +## Troubleshooting + +```bash +# Check logs +docker logs portainer + +# Check Tailscale sidecar +docker exec ts-portainer tailscale status + +# Restart stack +cd /srv/seedbox/stacks/portainer +docker compose restart +``` + +## Note + +Portainer is optional and mainly useful for: +- Visual monitoring of containers +- Quick access to logs +- Emergency container management + +All deployments should still go through Gitea Actions for proper version control. -- 2.52.0 From 5f13ee47df88d0f4a2e12b84913dd5545f80b1d7 Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:30:18 +0000 Subject: [PATCH 14/15] docs(seedbox): add README for Prowlarr stack --- seedbox/stacks/prowlarr/README.md | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 seedbox/stacks/prowlarr/README.md diff --git a/seedbox/stacks/prowlarr/README.md b/seedbox/stacks/prowlarr/README.md new file mode 100644 index 0000000..e943deb --- /dev/null +++ b/seedbox/stacks/prowlarr/README.md @@ -0,0 +1,61 @@ +# Prowlarr Stack + +Indexer manager for Sonarr, Radarr, and other *arr applications. + +## Access + +- **URL**: https://prowlarr.taila5ad8.ts.net +- **Initial setup**: Configure on first access (no default credentials) + +## Ports + +| Port | Protocol | Exposure | Description | +|------|----------|----------|-------------| +| 9696 | TCP | Tailscale only | WebUI | + +## Features + +- Centralized indexer management +- Automatic sync with Sonarr/Radarr +- Support for Usenet and Torrent indexers +- Built-in indexer testing + +## Configuration + +### Connect to Sonarr + +1. In Prowlarr: **Settings → Apps → Add** +2. Select "Sonarr" +3. Prowlarr Server: `http://localhost:9696` (or use Tailscale hostname) +4. Sonarr Server: `http://sonarr.taila5ad8.ts.net` or internal Docker network +5. API Key: Get from Sonarr **Settings → General** + +### Add Indexers + +1. Go to **Indexers → Add** +2. Search for your preferred indexer +3. Configure credentials if required +4. Test and save + +## Troubleshooting + +```bash +# Check logs +docker logs prowlarr + +# Check Tailscale sidecar +docker exec ts-prowlarr tailscale status + +# Restart stack +cd /srv/seedbox/stacks/prowlarr +docker compose restart + +# Check WebUI is responding +docker exec ts-prowlarr curl -s http://127.0.0.1:9696 +``` + +## Integration Notes + +Prowlarr can communicate with other *arr apps via: +1. **Tailscale hostnames** (e.g., `sonarr.taila5ad8.ts.net`) - Recommended +2. **Docker network** - Requires additional network configuration -- 2.52.0 From 3a39b7c4f2ba41f93c4a5666f1db2378d93cd058 Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Sun, 4 Jan 2026 12:30:29 +0000 Subject: [PATCH 15/15] docs(seedbox): add README for Sonarr stack --- seedbox/stacks/sonarr/README.md | 82 +++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 seedbox/stacks/sonarr/README.md diff --git a/seedbox/stacks/sonarr/README.md b/seedbox/stacks/sonarr/README.md new file mode 100644 index 0000000..16d37cc --- /dev/null +++ b/seedbox/stacks/sonarr/README.md @@ -0,0 +1,82 @@ +# Sonarr Stack + +TV series management and automation. + +## Access + +- **URL**: https://sonarr.taila5ad8.ts.net +- **Initial setup**: Configure on first access (no default credentials) + +## Ports + +| Port | Protocol | Exposure | Description | +|------|----------|----------|-------------| +| 8989 | TCP | Tailscale only | WebUI | + +## Volumes + +| Path in container | Host path | Description | +|-------------------|-----------|-------------| +| `/config` | Docker volume | Sonarr configuration | +| `/downloads` | `/srv/seedbox/downloads` | Download directory | +| `/media` | `/mnt/media` | Media library (NFS) | + +## Configuration + +### Root Folders + +1. Go to **Settings → Media Management → Root Folders** +2. Add `/media/TV` or your preferred path + +### Download Client + +1. Go to **Settings → Download Clients → Add** +2. Select "Transmission" +3. Host: `transmission.taila5ad8.ts.net` +4. Port: `443` +5. Use SSL: ✅ +6. Username/Password: Your Transmission credentials + +### Connect to Prowlarr + +1. Go to **Settings → Indexers** +2. Prowlarr will auto-sync indexers if configured correctly + +### Quality Profiles + +Configure in **Settings → Profiles** based on your preferences. + +## Troubleshooting + +```bash +# Check logs +docker logs sonarr + +# Check Tailscale sidecar +docker exec ts-sonarr tailscale status + +# Restart stack +cd /srv/seedbox/stacks/sonarr +docker compose restart + +# Check WebUI is responding +docker exec ts-sonarr curl -s http://127.0.0.1:8989 +``` + +## Recommended Folder Structure + +``` +/mnt/media/ +├── TV/ +│ ├── Show Name (Year)/ +│ │ ├── Season 01/ +│ │ └── Season 02/ +│ └── Another Show/ +└── downloads/ + └── completed/ +``` + +## API Key + +Find your API key in **Settings → General → Security**. +This is needed for Prowlarr integration. -- 2.52.0