en

Kubernetes K3s for Tor Hidden Services

K3s is a lightweight Kubernetes distribution ideal for single-server or small-cluster deployments. Combining K3s with Tor hidden service workloads provides container orchestration with .onion networking. This guide covers deploying Tor as a sidecar in K3s pods, managing hidden service keys via Kubernetes Secrets, and exposing Kubernetes services via .onion addresses.

Need this done for your project?

We implement, you ship. Async, documented, done in days.

Start a Brief

K3s Installation and Tor Integration Architecture

Install K3s on a single server: curl -sfL https://get.k3s.io | sh (this installs k3s with built-in kubectl). K3s runs a full Kubernetes control plane and worker node on one server with minimal resources. The Tor integration architecture for K3s: deploy a Tor DaemonSet (running a Tor daemon pod on each node) or a Tor sidecar container in each pod that needs .onion access. The DaemonSet approach runs one Tor process per node and is suitable when many pods need Tor access. The sidecar approach runs a Tor container alongside each application container in the same pod, suitable for isolation per workload. The Tor container in either approach shares the pod's localhost network namespace with the application container. The application connects to 127.0.0.1:9050 for SOCKS5 proxy or receives connections forwarded from the .onion address on localhost.

Managing Hidden Service Keys with Kubernetes Secrets

Hidden service private keys must persist across pod restarts to maintain the same .onion address. Kubernetes Secrets store the private key data securely. Create a Kubernetes Secret from the hidden service key file: kubectl create secret generic tor-hs-keys --from-file=private_key=/path/to/private_key --from-file=hostname=/path/to/hostname. Mount this Secret as a volume in the Tor container: volumeMounts with mountPath pointing to the HiddenServiceDir configured in torrc. The Tor container reads keys from the mounted Secret. When the pod restarts, the same keys are mounted and the .onion address remains constant. Secret encryption at rest: K3s supports encrypting Secrets using AES-CBC or AES-GCM. Configure encryption in K3s's configuration to protect hidden service keys even if the etcd database is accessed directly.

ConfigMap for torrc in Kubernetes

Store the Tor configuration (torrc) in a Kubernetes ConfigMap: kubectl create configmap tor-config --from-file=torrc=/path/to/torrc. Mount the ConfigMap as a volume in the Tor container at /etc/tor/torrc. This approach allows updating the Tor configuration without rebuilding the container image - edit the ConfigMap and restart the pod. The torrc content for a K3s Tor sidecar: HiddenServiceDir /tor-keys, HiddenServicePort 80 127.0.0.1:8080, SocksPort 9050, ExitPolicy reject *:*. The ExitPolicy rejects all exit traffic (ensuring this is a client-only Tor instance, not a relay). The HiddenServiceDir must match the volume mount path for the Secret containing the keys.

Service Discovery for .onion Workloads in K3s

Kubernetes services abstract pod IPs behind stable endpoints. For .onion services in K3s: the Tor container knows the application container's address as 127.0.0.1 (shared pod network namespace). For service discovery between different pods: configure Tor's SOCKS5 proxy (on the Tor DaemonSet) as the cluster-wide proxy for Tor network access. Application pods that need to call other .onion services configure their HTTP clients to use socks5://tor-proxy-service:9050 (where tor-proxy-service is the K3s Service name for the DaemonSet's Tor pods). This enables pod-to-pod communication via .onion addresses within the cluster. For external .onion services: the same proxy configuration routes external .onion requests through the cluster's Tor DaemonSet.

Persistent Storage for .onion Applications in K3s

K3s includes a built-in local storage provisioner. For .onion application data that must persist: create PersistentVolumeClaims (PVCs) backed by local storage. The PVC provides a directory on the node's filesystem that persists across pod restarts. For database workloads: deploy PostgreSQL or MariaDB as StatefulSets with PVCs for data persistence. The database pod uses a Tor sidecar if it needs .onion connectivity. Application pods connect to the database via Kubernetes internal DNS (postgres-service.default.svc.cluster.local) - this internal communication does not need Tor. Only external connections (reaching .onion services outside the cluster, or exposing services to external .onion clients) require Tor. Backup: use Velero (K8s backup tool) with a storage backend accessible via .onion (configure Velero's S3-compatible backend to use an .onion Minio instance).

Why Anubiz Host

100% async — no calls, no meetings
Delivered in days, not weeks
Full documentation included
Production-grade from day one
Security-first approach
Post-delivery support included

Ready to get started?

Skip the research. Tell us what you need, and we'll scope it, implement it, and hand it back — fully documented and production-ready.

Anubiz Chat AI

Online