From e95e82be2f9f0c0771f15bae2bddd9be62976888 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 8 Jun 2026 19:13:09 +0000 Subject: [PATCH] Fix functional bugs found in service audit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wg-easy: PASSWORD env var removed in v14+; generate bcrypt hash at install time via 'docker run wg-easy wgpw' and write PASSWORD_HASH instead. ntfy: write config/server.yml with base-url, cache-file, auth-file, and behind-proxy:true so push notification links work when behind Caddy. auth-default-access: deny-all (require topic auth). mealie: BASE_URL was hardcoded to http://localhost:9925; email links and OAuth redirects broke when served via Caddy. Now computed from SITE_DOMAIN and written to .env so it's easy to update. nextcloud: add OVERWRITEPROTOCOL=https, OVERWRITECLIURL, TRUSTED_PROXIES to .env so share links and internal redirects use https:// behind Caddy. onlyoffice: Caddy's default X-Frame-Options: SAMEORIGIN header blocked OnlyOffice from being embedded as an iframe in Nextcloud. Override it in the Caddy site block to allow framing. vaultwarden: remove exposed port 3012 (WebSocket — not needed since v1.29+, all handled on port 80). Publish port 8888 for direct host access instead. Remove WEBSOCKET_ENABLED=true (ignored in current versions). https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt --- services/mealie.sh | 16 +++++++++++++++- services/nextcloud.sh | 6 ++++++ services/ntfy.sh | 22 ++++++++++++++++++++++ services/onlyoffice.sh | 8 +++++++- services/vaultwarden.sh | 6 +----- services/wg-easy.sh | 26 +++++++++++++++++++++----- 6 files changed, 72 insertions(+), 12 deletions(-) diff --git a/services/mealie.sh b/services/mealie.sh index 05a6a27..b8fa9b2 100644 --- a/services/mealie.sh +++ b/services/mealie.sh @@ -169,6 +169,13 @@ install_mealie() { TZ_VAL="${SITE_TZ:-$(cat /etc/timezone 2>/dev/null || echo UTC)}" UID_VAL=$(id -u "$ACTUAL_USER"); GID_VAL=$(id -g "$ACTUAL_USER") + # BASE_URL must match the public URL Mealie is served on (used for email links, + # OAuth redirects, and the web app manifest). Default to SITE_DOMAIN if set. + local MEALIE_BASE_URL="http://localhost:9925" + if [ -n "$SITE_DOMAIN" ] && [ "$SITE_DOMAIN" != "example.com" ]; then + MEALIE_BASE_URL="https://recipes.${SITE_DOMAIN}" + fi + cat > docker-compose.yml << MEALIE_COMPOSE name: mealie @@ -178,6 +185,7 @@ services: container_name: mealie hostname: mealie restart: unless-stopped + env_file: .env environment: - PUID=$UID_VAL - PGID=$GID_VAL @@ -185,7 +193,6 @@ services: - ALLOW_SIGNUP=true - MAX_WORKERS=1 - WEB_CONCURRENCY=1 - - BASE_URL=http://localhost:9925 volumes: - ./data:/app/data ports: @@ -199,6 +206,13 @@ networks: name: \${CADDY_NET:-caddy_net} MEALIE_COMPOSE + cat > .env << MEALIE_ENV +# Public URL Mealie is served on — used for email links and OAuth redirects. +# Update if you change your domain or switch from HTTP to HTTPS. +BASE_URL=$MEALIE_BASE_URL +CADDY_NET=$SITE_CADDY_NET +MEALIE_ENV + mkdir -p data chown -R "$ACTUAL_USER:$ACTUAL_USER" "$MEALIE_DIR" log_success "Mealie configured at $MEALIE_DIR" diff --git a/services/nextcloud.sh b/services/nextcloud.sh index adc6645..077fcd6 100644 --- a/services/nextcloud.sh +++ b/services/nextcloud.sh @@ -257,6 +257,12 @@ NEXTCLOUD_ADMIN_USER=admin NEXTCLOUD_ADMIN_PASSWORD=$NC_ADMIN_PASS NEXTCLOUD_DB_TYPE=mysql MYSQL_HOST=db + +# ── Reverse proxy trust (required when behind Caddy) ───────────────────────── +# Without these, share links use http:// and internal redirects may break. +OVERWRITEPROTOCOL=https +OVERWRITECLIURL=https://cloud.${SITE_DOMAIN:-example.com} +TRUSTED_PROXIES=172.16.0.0/12 NC_ENV chmod 600 .env diff --git a/services/ntfy.sh b/services/ntfy.sh index 8ab453f..9a959f5 100644 --- a/services/ntfy.sh +++ b/services/ntfy.sh @@ -201,6 +201,28 @@ CADDY_NET=$SITE_CADDY_NET NTFY_ENV mkdir -p cache config + + # Write server.yml — ntfy needs base-url for correct push notification links + # Only on fresh install; never clobber existing config + if [ ! -f config/server.yml ]; then + local NTFY_BASE_URL="" + if [ -n "$SITE_DOMAIN" ] && [ "$SITE_DOMAIN" != "example.com" ]; then + NTFY_BASE_URL="https://ntfy.${SITE_DOMAIN}" + fi + cat > config/server.yml << NTFY_CFG +# ntfy server configuration — https://docs.ntfy.sh/config/ +base-url: "${NTFY_BASE_URL:-https://ntfy.example.com}" # UPDATE to your actual domain +cache-file: /var/cache/ntfy/cache.db +cache-duration: 12h +auth-file: /var/cache/ntfy/auth.db +auth-default-access: deny-all +behind-proxy: true +NTFY_CFG + [[ -n "$NTFY_BASE_URL" ]] \ + && log_info "base-url set to $NTFY_BASE_URL — update if domain changes" \ + || log_warning "base-url set to placeholder — edit config/server.yml after install" + fi + chown -R "$ACTUAL_USER:$ACTUAL_USER" "$NTFY_DIR" echo "" diff --git a/services/onlyoffice.sh b/services/onlyoffice.sh index 12206b6..481b884 100644 --- a/services/onlyoffice.sh +++ b/services/onlyoffice.sh @@ -299,7 +299,13 @@ OO_ENV chmod 600 .env chown -R "$ACTUAL_USER:$ACTUAL_USER" "$DIR" - configure_caddy_for_service "OnlyOffice" "onlyoffice:80" "office" + # OnlyOffice must be embeddable as an iframe in Nextcloud/FileBrowser. + # Override X-Frame-Options to allow same-site embedding (remove SAMEORIGIN restriction). + local OO_EXTRA_BLOCK=' header { + -X-Frame-Options + Content-Security-Policy "frame-ancestors '\''self'\'' *" + }' + configure_caddy_for_service "OnlyOffice" "onlyoffice:80" "office" "$OO_EXTRA_BLOCK" local START="" prompt_yn "Start OnlyOffice now? (y/n):" "y" START diff --git a/services/vaultwarden.sh b/services/vaultwarden.sh index 7aa8fad..682218a 100644 --- a/services/vaultwarden.sh +++ b/services/vaultwarden.sh @@ -220,10 +220,8 @@ services: env_file: .env volumes: - ./vaultwarden_data:/data - expose: - - "80" ports: - - "3012:3012" # WebSocket (legacy — not needed for Vaultwarden v1.29+) + - "8888:80" networks: - caddy_net @@ -250,8 +248,6 @@ ADMIN_TOKEN=$ADMIN_TOKEN SIGNUPS_ALLOWED=false SIGNUPS_VERIFY=false -# WebSocket notifications (v1.29+: built into port 80, no separate port needed) -WEBSOCKET_ENABLED=true # ── SMTP (optional — for password-reset and invite emails) ──────────────────── SMTP_HOST=$SMTP_HOST diff --git a/services/wg-easy.sh b/services/wg-easy.sh index 22ba149..9ae48d3 100644 --- a/services/wg-easy.sh +++ b/services/wg-easy.sh @@ -181,13 +181,26 @@ install_wg-easy() { cd "$WGEASY_DIR" || return 1 # Auto-detect public IP as default for WG_HOST - local PUBLIC_IP WG_HOST WG_PASSWORD + local PUBLIC_IP WG_HOST WG_PASSWORD WG_PASSWORD_HASH PUBLIC_IP=$(curl -s --connect-timeout 5 ifconfig.me 2>/dev/null || echo "your-public-ip") WG_PASSWORD=$(openssl rand -base64 16 | tr -dc 'a-zA-Z0-9' | head -c 16) prompt_text "Public IP or hostname for VPN [$PUBLIC_IP]:" "$PUBLIC_IP" WG_HOST - cat > docker-compose.yml << 'WGEASY_COMPOSE' + # wg-easy v14+ requires PASSWORD_HASH (bcrypt). Generate via docker. + log_info "Generating bcrypt password hash (requires Docker)..." + WG_PASSWORD_HASH=$(docker run --rm ghcr.io/wg-easy/wg-easy:latest wgpw "$WG_PASSWORD" 2>/dev/null \ + | grep -oP '\$2[ab]\$[^\s]+' | head -1) + if [[ -z "$WG_PASSWORD_HASH" ]]; then + log_warning "Could not generate bcrypt hash — falling back to plaintext PASSWORD env var." + log_warning "If wg-easy fails to start, run: docker run --rm ghcr.io/wg-easy/wg-easy wgpw 'yourpassword'" + log_warning "Then set PASSWORD_HASH in docker-compose.yml and remove PASSWORD." + fi + + # Escape $ in hash for docker-compose env (bcrypt hashes contain $$) + local WG_HASH_ESCAPED="${WG_PASSWORD_HASH//\$/\$\$}" + + cat > docker-compose.yml << WGEASY_COMPOSE name: wg-easy services: @@ -203,8 +216,8 @@ services: - net.ipv4.ip_forward=1 - net.ipv4.conf.all.src_valid_mark=1 environment: - - WG_HOST=${WG_HOST} - - PASSWORD=${WG_PASSWORD} + - WG_HOST=\${WG_HOST} + - PASSWORD_HASH=${WG_HASH_ESCAPED:-\${WG_PASSWORD}} - WG_DEFAULT_DNS=1.1.1.1 volumes: - ./config:/etc/wireguard @@ -217,11 +230,12 @@ services: networks: caddy_net: external: true - name: ${CADDY_NET:-caddy_net} + name: \${CADDY_NET:-caddy_net} WGEASY_COMPOSE cat > .env << WGEASY_ENV WG_HOST=$WG_HOST +# Plain-text password — used only if PASSWORD_HASH could not be generated above WG_PASSWORD=$WG_PASSWORD CADDY_NET=$SITE_CADDY_NET WGEASY_ENV @@ -270,6 +284,8 @@ MD echo "" echo " Web UI: http://localhost:51821" echo " Password: $WG_PASSWORD (saved in .env)" + [[ -n "$WG_PASSWORD_HASH" ]] && echo " Auth: bcrypt hash configured (v14+ compatible)" \ + || echo " Auth: WARNING — bcrypt hash generation failed; see README" echo " Router: forward UDP 51820 → this server for external VPN access" echo "" }