From 7de8955c4f09531a88578be6c1b720fbc9961ee8 Mon Sep 17 00:00:00 2001 From: Deivid Soto Date: Wed, 20 May 2026 23:27:34 +0200 Subject: [PATCH] feat(vpn): local config_file for self-hosted/personal VPN testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit downloads.vpn.config_file = path to a WireGuard .conf read directly by the daemon (skips the web fetch). Lets you point unarr at your own WireGuard server / personal VPN and split-tunnel torrent traffic through it without the web provisioning plumbing — for testing and self-hosted setups. --- internal/cmd/daemon.go | 14 +++++++++++++- internal/config/config.go | 5 +++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/internal/cmd/daemon.go b/internal/cmd/daemon.go index 5a31c0d..771e9b4 100644 --- a/internal/cmd/daemon.go +++ b/internal/cmd/daemon.go @@ -199,7 +199,19 @@ func runDaemonStart() error { // the torrent client so peer + tracker traffic routes through it. Failure is // non-fatal — log and download in the clear (better than refusing to run). var vpnTunnel *vpn.Tunnel - if cfg.Download.VPN.Enabled { + if cfg.Download.VPN.ConfigFile != "" { + // Self-hosted / personal-VPN mode: read a local .conf directly. + raw, rerr := os.ReadFile(cfg.Download.VPN.ConfigFile) + if rerr != nil { + log.Printf("[vpn] could not read config_file %q (%v) — downloading in the clear", cfg.Download.VPN.ConfigFile, rerr) + } else if t, uerr := vpn.Up(string(raw)); uerr != nil { + log.Printf("[vpn] tunnel failed to start from config_file (%v) — downloading in the clear", uerr) + } else { + vpnTunnel = t + defer vpnTunnel.Close() + log.Printf("[vpn] managed VPN active (local config_file) — torrent traffic split-tunnelled through WireGuard") + } + } else if cfg.Download.VPN.Enabled { apiURL := cfg.Auth.APIURL if apiURL == "" { apiURL = "https://torrentclaw.com" diff --git a/internal/config/config.go b/internal/config/config.go index b07f69d..9f46b53 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -63,6 +63,11 @@ type DownloadConfig struct { // add-on on the account; otherwise the daemon logs and downloads in the clear. type VPNConfig struct { Enabled bool `toml:"enabled"` + // ConfigFile, when set, makes the daemon read a local WireGuard .conf instead + // of fetching one from the web API. For self-hosted / personal-VPN testing: + // point it at a peer .conf from your own WireGuard server and the torrent + // client split-tunnels through it with no web/provider plumbing. + ConfigFile string `toml:"config_file"` } // TranscodeConfig controls real-time transcoding for the in-browser player