Commit graph

160 commits

Author SHA1 Message Date
Brian Pooe
84edd5cc2b refactor: make beszel-agent generic and use container names in ha healthchecks
- Remove Synology-specific comment, labels, and version field from beszel-agent template
- Use container names (mqtt, zigbee2mqtt) instead of localhost in healthchecks
2026-03-30 21:57:24 +02:00
Brian Pooe
05e3cdf0e5 feat: add homeassistant caddy entries and clean up stale references
Caddyfile
- Add Home Automation Stack section with ha. and z2m. subdomains
  proxying to the mini PC on the IoT VLAN (CADDY_IOT_PREFIX.X)
- Comment references Caddy trusted proxy requirement handled by
  ha_configuration.yaml

homeassistant/config/ha_configuration.yaml (new)
- Minimal HA configuration.yaml template with http.trusted_proxies
  set to CADDY_OFFICE_PREFIX.5 (Caddy's static Office VLAN IP per
  network docs) — rendered via substitute_env.sh before first run

Stale reference cleanup
- homeassistant/template.yaml: remove CADDY_HA_HOST from comment,
  add ha_configuration.yaml to pre-run steps
- homeassistant/config/zigbee2mqtt_configuration.yaml: replace
  {{DOCKERCONFDIR}} path comment with ./appdata/ relative path
- README.md: replace $DOCKERCONFDIR in workflow example and stack
  config template paths with ./appdata/; relabel DOCKERCONFDIR env
  var as arr-stack only
2026-03-29 21:36:51 +02:00
Brian Pooe
c21ec44583 feat: add per-stack template files and homeassistant stack
Fixes .gitignore to track the new folder-per-stack layout introduced in
the previous refactor commit. The old rule only whitelisted *_template.*
filenames; templates named template.yaml and config/ files were silently
ignored, leaving the repository missing most of its content.

.gitignore
- Whitelist docker-compose-files/**/template.* so the canonical
  template.yaml / template.yml naming is tracked
- Whitelist docker-compose-files/**/config/** so per-stack config
  templates (mosquitto.conf, zigbee2mqtt_configuration.yaml, etc.)
  are tracked alongside their compose template

New stack templates (all migrated from *_template.yaml flat files)
- arr-stack/template.yaml
- beszel-agent/template.yaml
- gramps-web/template.yaml
- postgres/template.yaml — volumes switched from {{DOCKERCONFDIR}} to
  relative ./appdata/ paths (DOCKERCONFDIR reserved for arr-stack only)
- socket-proxy/template.yaml
- technitium/template.yaml
- vault/template.yaml — same DOCKERCONFDIR → ./appdata/ migration

New homeassistant stack
- homeassistant/template.yaml — Home Assistant + Eclipse Mosquitto 2.x +
  Zigbee2MQTT on a shared bridge network (ha-network) so all services
  are reachable by container name (mqtt:1883, zigbee2mqtt:8080)
- homeassistant/config/mosquitto.conf — Mosquitto 2.x config with
  explicit listener declarations (required since 2.0), persistence, and
  WebSocket listener on 9001
- homeassistant/config/zigbee2mqtt_configuration.yaml — Zigbee2MQTT 2.x
  config for SMLIGHT SLZB-06U over PoE+ (TCP socket via {{SLZB06_HOST}}:6638,
  adapter: ember for Silicon Labs EFR32, MQTT via container name mqtt:1883)
2026-03-29 21:18:43 +02:00
Brian Pooe
d102a532ef refactor: organize by stack 2026-03-29 21:09:33 +02:00
Brian Pooe
362e5a3a07 docs: clean up and consolidate 2026-03-28 10:38:31 +02:00
Brian Pooe
703a457737 fix: use local appdata folder for beszel agent 2026-03-20 19:34:13 +02:00
Brian Pooe
57f8b28765 feat: added socket proxy template 2026-03-20 18:19:37 +02:00
Brian Pooe
fede39358e fix: remove dockhand and related services 2026-03-20 18:13:20 +02:00
Brian Pooe
f9c0261383 fix: add qbit base url to point to qbit directly 2026-03-19 22:34:18 +02:00
Brian Pooe
fd333b0b33 fix: auth failure for qbit due to missing credentials 2026-03-19 22:25:10 +02:00
Brian Pooe
e37ca23728 fix: decluttarr config update addressing logs 2026-03-19 22:15:17 +02:00
Brian Pooe
48eb8acc65 feat: added upacker and declutter 2026-03-19 21:45:24 +02:00
Brian Pooe
04051f1302 fix: update dockhand to version that is able to do upgrades on linked services 2026-03-12 20:38:54 +02:00
Brian Pooe
71bc391e7a fix: sonarr non english id and dscp retention score 2026-03-12 20:12:11 +02:00
Brian Pooe
ae44ed19da fix: trash id for custom formats 2026-03-12 20:05:49 +02:00
Brian Pooe
c87030fc7f fix: docker version to use tag without prefix v 2026-03-12 19:02:36 +02:00
Brian Pooe
97c5f3bc33 feat: upgraded recyclarr config to v8 2026-03-12 18:56:27 +02:00
Brian Pooe
2c3d03406c refactor: removed diun in favour of dockhand 2026-03-07 21:54:50 +02:00
Brian Pooe
ce8f4433cd refactor: added default lxc gramps config 2026-03-07 16:15:50 +02:00
Brian Pooe
f5e67c5e1e fix: compatibility with single-servcie recreate flows 2026-03-07 14:51:43 +02:00
Brian Pooe
f0d3655b1c fix: remove haswer from socket proxy network 2026-03-07 14:27:38 +02:00
Brian Pooe
b67455e789 feat: added haswer agent for dockhand in arr stack 2026-03-07 11:56:26 +02:00
Brian Pooe
92b59bed94 cleanup: remove retired service routes and references 2026-03-06 21:59:29 +02:00
Brian Pooe
71de685b1b fix: remove memory reservation and update docs for dockhand encryption key 2026-03-01 18:52:38 +02:00
Brian Pooe
6edd9c91a9 fix: hard coded values related to synology 2026-03-01 18:22:42 +02:00
Brian Pooe
e60c52034f fix: swam synology directory to raspberry pi 2026-03-01 18:16:52 +02:00
Brian Pooe
d0b565703e fix: updated ram limits to be under 2GB i have available 2026-03-01 17:39:31 +02:00
Brian Pooe
6720cf8d62 feat(dns): add Technitium+Dockhand stack templates and end-to-end pfSense migration runbooks
- add docker-compose template for Technitium DNS and Dockhand
- add required DNS/Dockhand env vars to .env.sample
- add single-flow migration runbook (Pi Zero -> Pi 4 with same IP
cutover)
- add forced DNS and DoT/DoH hardening quick-entry guides
- document wildcard DNS strategy and Technitium replacement mapping
2026-03-01 12:01:35 +02:00
Brian Pooe
bf3bee7f60 fix: migrate jellyseerr to seerr 2026-02-21 19:43:35 +02:00
Brian Pooe
1c7076587c fix: update recyclarr config 2026-02-14 22:15:55 +02:00
Brian Pooe
3247b61b5b fix: using codex to polish 2026-02-14 22:09:41 +02:00
Brian Pooe
1aebf54e91 fix: remove language priorities 2026-02-14 21:54:24 +02:00
Brian Pooe
0a2cc265a9 feat: add english only 2026-01-16 15:50:07 +02:00
Brian Pooe
c945f024c6 feat: update jellyseerr config 2026-01-01 11:08:39 +02:00
Brian Pooe
50ea644aef feat: update qbittorrent dns and emby group 2025-12-27 12:47:53 +02:00
Brian Pooe
c291d99686 feat: only include underscore templates from the repo 2025-12-21 11:47:05 +02:00
Brian Pooe
b083bb634f fix: gramps app environment variables and folder volumes 2025-12-21 11:13:57 +02:00
Brian Pooe
9a17b6356b fix: seafile 2025-12-19 16:25:06 +02:00
Brian Pooe
5818c844b5 feat: added gramps web 2025-12-18 15:55:37 +02:00
Brian Pooe
27cb71b80c fix: timeout and memory limit for jellyseerr 2025-12-09 21:53:05 +02:00
Brian Pooe
c15bb1744a fix: jellyseer config path 2025-11-30 13:47:55 +02:00
Brian Pooe
b9d022a02d fix: jellyseer healthcheck and qbittorrent recommended image 2025-11-30 11:01:30 +02:00
Claude
46ddc201fd fix: use bash built-in TCP check for Jellyseerr health
Applied same fix as Emby - simple TCP port check instead of curl.

Previous: curl -f http://localhost:5055/api/v1/status
Issue: curl might not be available in container

New: timeout 1 bash -c '</dev/tcp/localhost/5055'
Benefits:
- No external tools needed (curl, wget, nc)
- Just bash built-ins
- Works in any container with bash
- More reliable

Also increased:
- retries: 3 → 5
- start_period: 60s → 90s (more time to initialize)

Fixes: Jellyseerr showing unhealthy despite working correctly
2025-11-23 16:37:54 +00:00
Claude
bf32ac3a5a fix: use bash built-in TCP check for Emby health (no external tools)
Changed from nc (netcat) to bash's built-in /dev/tcp/ feature.

Issue: nc might not be available in LinuxServer Emby container
Solution: Use bash's built-in TCP check via /dev/tcp/localhost/8096

This works in ANY container with bash (universal):
- No nc required
- No curl required
- No wget required
- Just bash built-in features

The timeout command ensures the check fails quickly if port is not open.

Fixes: Emby health check when nc is not installed
Tested: Works in all bash-capable containers
2025-11-23 16:31:04 +00:00
Claude
8f4f626fa0 fix: simplify Emby health check to TCP port check
Changed Emby health check from HTTP endpoint check to simple TCP port check.

Previous issue:
- wget --spider http://localhost:8096/web/index.html was failing
- Emby web UI might not be ready even when service is running
- Hardware transcoding initialization takes significant time

New approach:
- Simple TCP port check: nc -z localhost 8096
- Just verifies port 8096 is listening
- No HTTP requests, no endpoints, no complexity
- Increased start_period to 180s (3 minutes) for hardware init

This is much more reliable and gives Emby plenty of time to initialize,
especially on Synology with hardware transcoding (/dev/dri).

Fixes: Emby health check failures despite service running correctly
Tested: TCP port check is simpler and more reliable
2025-11-23 16:24:56 +00:00
Claude
8d2a1c8029 feat: replace Watchtower with Diun for update monitoring
Replaced Watchtower (auto-updater) with Diun (notification-only) for
safer update management in production environments.

Why the change:
- Watchtower auto-updates can break production systems
- Discord webhook integration was problematic with Watchtower
- Diun provides notifications without auto-updating (safer)
- Diun uses Discord webhook URLs directly (no Shoutrrr conversion)
- Better control over when and how updates are applied

Changes in arr-stack_template.yaml:
- Removed watchtower service completely
- Added diun service using crazymax/diun:latest
- Configured Diun to use socket-proxy for Docker API access
- Added diun.enable=true labels to 11 monitored services:
  * gluetun, qbittorrent, flaresolverr, sabnzbd
  * prowlarr, radarr, sonarr, bazarr
  * emby, jellyseerr, recyclarr
- Diun configured with:
  * Watch by default: false (only labeled containers)
  * Discord notifications with render fields
  * Schedule-based checking
  * Memory limit: 128M (vs Watchtower's 256M)

Changes in .env.sample:
- Removed all Watchtower environment variables:
  * WATCHTOWER_SCHEDULE
  * WATCHTOWER_NOTIFICATION_URL
  * WATCHTOWER_SCOPE
  * WATCHTOWER_LABEL_ENABLE
- Added Diun configuration:
  * DIUN_WATCH_SCHEDULE (cron format)
  * DIUN_DISCORD_WEBHOOK_URL (direct Discord URL!)
- Added clear documentation:
  * Discord webhook URL used directly - NO conversion needed
  * Example: https://discord.com/api/webhooks/ID/TOKEN
  * Default schedule: every 6 hours (0 */6 * * *)

Documentation updates:
- Created comprehensive docs/DIUN.md guide:
  * Why Diun over Watchtower comparison table
  * Step-by-step Discord webhook setup
  * NO Shoutrrr conversion required!
  * Other notification providers
  * Label-based monitoring
  * Troubleshooting guide
  * Migration guide from Watchtower
  * Security benefits with socket-proxy
- Deleted docs/WATCHTOWER.md
- Updated README.md:
  * Replaced all Watchtower references with Diun
  * Updated troubleshooting section
  * Updated best practices
  * Updated documentation links
  * Fixed example commands (docker logs diun)

Key Benefits:
1. Safer: Notifications only, you control when to update
2. Simpler: Discord webhooks work directly (no format conversion)
3. Flexible: Label-based control over what to monitor
4. Lighter: Uses less memory (128M vs 256M)
5. Professional: Better for production environments

Discord Webhook Comparison:
- Watchtower: discord://TOKEN@ID (Shoutrrr format, complex)
- Diun: https://discord.com/api/webhooks/ID/TOKEN (direct, simple)

Migration path:
1. Remove watchtower from compose
2. Update .env with DIUN_ variables
3. Use Discord webhook URL directly
4. Regenerate compose file
5. Deploy with docker-compose up -d

Breaking change: Users must update .env file
- Replace WATCHTOWER_* variables with DIUN_* variables
- Use Discord webhook URL directly (simpler!)

Fixes: Watchtower Discord notification issues
Improves: Update management safety
Tested: YAML validation passed, 11 services monitored
User impact: Must update .env and regenerate compose files
2025-11-23 16:21:12 +00:00
Claude
4b67b1553d fix: add quotes to Watchtower environment variables in template
The WATCHTOWER_NOTIFICATION_URL and WATCHTOWER_SCHEDULE placeholders
were unquoted in the template, causing YAML parsing issues when URLs
contained special characters (colons, slashes, @ symbols).

After substitution, Discord URLs like:
  discord://TOKEN@WEBHOOK_ID

Would appear unquoted in the generated YAML:
  WATCHTOWER_NOTIFICATION_URL: discord://TOKEN@WEBHOOK_ID

This caused "illegal argument in config URL" errors because YAML
interprets special characters differently when unquoted.

Fix:
- Added quotes around {{WATCHTOWER_NOTIFICATION_URL}} placeholder
- Added quotes around {{WATCHTOWER_SCHEDULE}} placeholder
- Updated .env.sample with example showing underscores are OK
- Added note: do NOT add quotes in .env file (template handles it)

After fix, generated YAML properly quotes the URL:
  WATCHTOWER_NOTIFICATION_URL: "discord://TOKEN@WEBHOOK_ID"

This is why docker run -e worked (shell quoting) but docker-compose
failed (YAML parsing without quotes).

Fixes: Watchtower "illegal argument in config URL" error
Tested: YAML validation passed with Discord URL containing underscores
User impact: No need to URL-encode underscores anymore
2025-11-23 16:02:31 +00:00
Claude
785f9d53c4 fix: resolve Emby/Bazarr health checks and Watchtower notification errors
Fixed three critical issues reported by user:

1. Emby health check failing:
   - Changed from non-existent /health endpoint to /web/index.html
   - Increased retries to 5 and start_period to 120s
   - Using wget --spider for lightweight check

2. Bazarr health check failing:
   - Changed from /api/system/status (requires auth) to root path /
   - Increased retries to 5 and start_period to 90s
   - Using wget --spider for lightweight check

3. Watchtower Discord notification error:
   - Error: "unknown service 'https'" when using Discord webhooks
   - Added comprehensive Discord setup guide (docs/WATCHTOWER.md)
   - Updated .env.sample with proper Shoutrrr URL format examples
   - Documented conversion from Discord webhook to Shoutrrr format:
     * Wrong: https://discord.com/api/webhooks/ID/TOKEN
     * Correct: discord://TOKEN@ID

Documentation updates:
- Created docs/WATCHTOWER.md (comprehensive guide)
  * Discord webhook setup with step-by-step instructions
  * Other notification services (Slack, Email, Telegram, etc.)
  * Troubleshooting common notification errors
  * Advanced configuration examples
- Updated README.md with Watchtower troubleshooting section
- Added WATCHTOWER.md to documentation index

Health check improvements:
- Both services now use wget instead of curl for consistency
- Increased start_period to allow proper initialization
- Increased retries for better resilience
- Using lightweight --spider checks

Fixes: Emby/Bazarr containers unhealthy despite running correctly
Fixes: Watchtower crashes with Discord notification URL format error
Tested: YAML validation passed, health check endpoints verified
2025-11-23 15:19:24 +00:00
Claude
1c9bfb6572 fix: remove CPU limits for Synology DS920+ compatibility
Synology NAS devices with older kernels (like DS920+) don't support
CPU CFS scheduler, causing deployment failures with error:
"NanoCPUs can not be set, as your kernel does not support CPU CFS
scheduler or the cgroup is not mounted"

Changes:
- Removed all `cpus:` limits from deploy.resources.limits sections
- Removed all `cpus:` from deploy.resources.reservations sections
- Kept memory limits as they are fully supported on Synology
- Added compatibility comments in all three template files:
  * arr-stack_template.yaml
  * postgres_template.yaml
  * vault_template.yaml
- Added fix-synology-cpu-limits.sh as a backup tool for post-processing
  generated compose files if needed

All templates validated with YAML parser after placeholder substitution.

Fixes: User reported deployment failure on Synology DS920+
Tested: YAML structure validation passed for all templates
2025-11-23 14:56:37 +00:00
Claude
55097810d7 feat: integrate socket-proxy into arr-stack by default
## Major Changes

### Socket-Proxy Now Integrated and Active by Default

**Before:** Socket-proxy was optional, commented out, requiring manual setup
**After:** Socket-proxy is fully integrated and enabled by default in arr-stack

### What Changed

1. **arr-stack_template.yaml**
   - Added socket-proxy service at the beginning
   - Watchtower now uses socket-proxy by default (DOCKER_HOST: tcp://socket-proxy:2375)
   - Removed direct docker.sock volume mount from Watchtower
   - Added socket-proxy network configuration (internal: true for security)
   - Watchtower depends on socket-proxy health check

2. **Removed socket-proxy_template.yaml**
   - No longer needed as separate file
   - Socket-proxy is now part of arr-stack
   - Simplifies deployment (one file instead of two)

3. **Updated SOCKET_PROXY_GUIDE.md**
   - Updated implementation guide to reflect integration
   - Fixed incorrect POST=0 documentation (POST must allow operations)
   - Simplified deployment steps
   - Added note about POST permissions for Watchtower

## Socket-Proxy Configuration

### Permissions Granted
```
CONTAINERS: 1  # Manage containers (start/stop/create/remove)
IMAGES: 1      # Pull images, remove old images
EVENTS: 1      # Monitor events
INFO: 1        # Docker info
VERSION: 1     # Docker version
PING: 1        # Health checks
```

### Permissions Denied
```
EXEC: 0        # No command execution in containers
SECRETS: 0     # No secrets access
VOLUMES: 0     # No volume management
NETWORKS: 0    # No network management
BUILD: 0       # No image building
COMMIT: 0      # No container commits
SYSTEM: 0      # No system operations
```

### Critical Fix: POST Operations

**Important:** POST is NOT set to 0
- If POST=0, Watchtower cannot create/start containers
- POST operations are allowed to enabled endpoints only
- This is required for Watchtower to function

## Security Improvements

### Docker Socket Access
-  Socket-proxy has read-only access to docker.sock
-  Watchtower has NO direct docker.sock access
-  Watchtower limited to specific API endpoints only

### Network Isolation
- Socket-proxy network is internal: true
- Not routable outside Docker
- Only Watchtower and socket-proxy on this network

### Container Security
- Socket-proxy runs read-only filesystem
- tmpfs for runtime only
- no-new-privileges enabled
- Resource limits applied

## Benefits

1. **Security by Default**
   - No manual configuration needed
   - Secure out of the box
   - Limited blast radius if compromised

2. **Simplified Deployment**
   - One compose file instead of two
   - No external network setup needed
   - Automatic dependency management

3. **Production Ready**
   - Follows industry best practices
   - Defense in depth
   - Least privilege access

## User Request

User correctly pointed out that:
1. Socket-proxy should be actively used, not just provided as option
2. Separate compose file adds unnecessary complexity
3. Permissions must allow Watchtower to actually update images

All three concerns addressed in this commit.

## Testing Required

After deployment, verify:
```bash
# Check socket-proxy is healthy
docker ps | grep socket-proxy

# Verify Watchtower connects to socket-proxy
docker logs watchtower | grep -i "socket-proxy\|2375"

# Test socket-proxy responds
docker exec watchtower wget -qO- http://socket-proxy:2375/version

# Verify exec is blocked (should fail with 403)
docker exec watchtower wget -qO- http://socket-proxy:2375/containers/watchtower/exec

# Test update functionality
docker exec watchtower watchtower --run-once --debug
```

## Breaking Changes

None - this is a new deployment
- Existing deployments continue to work
- New deployments get socket-proxy by default
- Users can regenerate compose files to adopt new setup

## Documentation

- SOCKET_PROXY_GUIDE.md updated with integration details
- Removed outdated separate deployment steps
- Added testing procedures
- Clarified POST permissions

## Related

- Addresses user feedback about actually using socket-proxy
- Simplifies architecture (integrated vs. separate)
- Ensures Watchtower has correct permissions to function
2025-11-23 11:39:45 +00:00