Skip to content

Telegram notification proxy and Mullvad DNS (CT 107)

Deployed and validated 2026-10-25. telegram-proxy-01 is Debian 13.6 in unprivileged Proxmox LXC 107, at 192.168.10.171/24 (gateway 192.168.10.1) on VLAN 10. It is a narrow HTTPS CONNECT proxy for Uptime Kuma's Telegram notification provider and a Mullvad-backed DNS resolver for Trusted VLAN 20 when VPN mode is enabled. Do not put the Telegram bot token in files tracked by Git.

Architecture

Service Configuration Purpose
Tinyproxy 1.11.2 /etc/tinyproxy/tinyproxy.conf, listen 192.168.10.171:3128 Only source 192.168.10.158 (monitor-01) and loopback allowed; ConnectPort 443
Tinyproxy filter /etc/tinyproxy/telegram-allowed-domains containing api.telegram.org FilterType fnmatch, FilterDefaultDeny Yes, FilterURLs No; other CONNECT domains blocked
dnsmasq /etc/dnsmasq.d/mullvad-split-dns.conf Public requests → 10.64.0.1; home.arpa → router 192.168.10.1; cache-size 300
Container resolver /etc/resolv.conf managed by Proxmox nameserver 127.0.0.1, search home.arpa
DNS destination guard telegram_dns_guard nft table; enabled systemd unit Permits dnsmasq uid DNS upstream only to Mullvad or homelab router; blocks other classic port-53 outbound DNS
Trusted DNS listener access /root/trusted-dns-access.nft with trusted-dns-access.service enabled Allow VLAN 20 DNS TCP/UDP 53; drop other inbound DNS, with loopback permitted
Router inter-VLAN rule firewall.trusted_telegram_dns trusted 192.168.20.0/24 → lab 192.168.10.171:53 UDP/TCP
Router PBR and kill switch pbr.telegram_local, pbr.telegram_mullvad, /etc/nftables.d/31-telegram-mullvad-guard.nft CT 107 public egress via Mullvad; forwarding out university eth1 blocked

Tinyproxy uses Allow 192.168.10.158, Allow 127.0.0.1, ConnectPort 443, and filter api.telegram.org. Use fnmatch, not ere for that literal filter file; an earlier mismatch returned HTTP 403 for valid Telegram requests. Proxy is not a generic open Internet proxy.

The dnsmasq service listens on loopback and 192.168.10.171:53 (both TCP and UDP). A previous interface=lo/listen-address=127.0.0.1 was extended to interface=lo,eth0 and listen-address=127.0.0.1,192.168.10.171. It also opened IPv6 link-local listeners; additional listener hardening remains on the task list. Keep the input filter active before exposing port 53 remotely.

Uptime Kuma integration

Kuma is on monitor-01 (192.168.10.158) in Docker and was upgraded to louislam/uptime-kuma:2.5.7. Compose sets NOTIFICATION_PROXY=http://192.168.10.171:3128, while retaining NODE_EXTRA_CA_CERTS, the mounted public homelab CA, and uptime-kuma-data volume. Only provider requests using Kuma's shared notification proxy helper are proxied; ordinary monitor health checks remain on normal routing. The Telegram provider uses the default server URL https://api.telegram.org (do not put the proxy URL in Telegram Server URL). A Telegram Test message arrived and a real temporary monitor DOWN/UP workflow was tested after explicitly assigning the notification to that monitor; notification is configured for existing monitors.

The pre-upgrade Kuma 1.x data archive was verified at /opt/monitoring/backups/kuma-v1-20261025-130228/uptime-kuma-v1-data.tar.gz (on monitor-01), with a Compose backup. Migration finished, existing monitors persisted. See Monitoring.

Verification / troubleshooting

Run on monitor-01 (not PVE: Tinyproxy only allows its IP):

curl -4 -sS -o /dev/null -w '%{http_code}\n' \
  --max-time 10 --proxy http://192.168.10.171:3128 \
  https://api.telegram.org/
# Expected 302; proxy CONNECT succeeds, then Telegram root redirects.
curl -sS -o /dev/null -w '%{http_code}\n' \
  --max-time 10 --proxy http://192.168.10.171:3128 \
  https://example.com/
# Expected 403 from Tinyproxy filter.
docker exec uptime-kuma printenv NOTIFICATION_PROXY
docker logs uptime-kuma --since 30m 2>&1 | tail -60

Run on XPS in VLAN 20:

dig @192.168.10.171 api.telegram.org A +short
dig @192.168.10.171 pve.home.arpa A +short
dig +tcp @192.168.10.171 pve.home.arpa A +short
# Expected Telegram 149.154.166.110; internal pve 192.168.10.10 at deployment.

Run on PVE:

pct exec 107 -- systemctl is-active tinyproxy dnsmasq trusted-dns-access.service
pct exec 107 -- nft list table inet trusted_dns_access
pct exec 107 -- ss -lntup

Do not paste bot tokens or run commands that dump private UCI interface keys. For getUpdates, users must message the bot first; the chat ID is not the bot token. Telegram notification must actually be enabled on each monitor (or apply-to-existing-monitors option used); a successful provider test alone doesn't attach a notification to monitors.

Open checks

  • [ ] Verify CT 107 DNS input and output nft guards after a container reboot; check unit ordering and whether firewall state is preserved at startup.
  • [ ] Verify DNS listening on IPv4 only where intended, or filter IPv6 DNS listeners explicitly.
  • [ ] Confirm DNS access is restricted across other VLAN 10 peers and unapproved network sources.
  • [ ] Add monitoring of CT 107 proxy/DNS availability and ensure alert delivery does not depend exclusively on an unavailable path.