How I build a VPN-Protected Socks5 Proxy

Share on:

Running a Kubernetes cluster on Raspberry Pis using K3s is a fantastic way to build a powerful and flexible home lab environment. When combined with Portainer for managing your Kubernetes deployments, it becomes even easier to deploy and manage your applications. Recently, I set up a Socks5 proxy that routes all its traffic through a VPN on my K3s cluster, and I want to share the steps I took to accomplish this.

My Setup

Here's a quick overview of the setup I used:

  • Hardware: A cluster of three Raspberry Pis running K3s.
  • Management: Portainer installed on top of the K3s cluster for easy management of Kubernetes resources.
  • Goal: Deploy a Socks5 proxy using the serjs/go-socks5-proxy image, ensuring all its traffic is routed through a VPN provided by the qmcgaw/gluetun container.

Step 1: Creating the Kubernetes Deployment

First, I created a Kubernetes Deployment that included both the Gluetun VPN and the Socks5 proxy containers. Since both containers needed to share the same network namespace to ensure that all traffic from the proxy is routed through the VPN, I configured them to run within the same Pod.

Here’s the YAML file I used:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vpn-proxy
  labels:
    app: vpn-proxy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vpn-proxy
  template:
    metadata:
      labels:
        app: vpn-proxy
    spec:
      containers:
      - name: gluetun
        image: qmcgaw/gluetun
        ports:
        - containerPort: 8080
        env:
        - name: VPN_SERVICE_PROVIDER
          value: "protonvpn"
        - name: VPN_TYPE
          value: "wireguard"
        - name: WIREGUARD_PRIVATE_KEY
          value: "{hidden}"
        - name: SERVER_COUNTRIES
          value: "Netherlands"
        - name: VPN_PORT_FORWARDING_PROVIDER
          value: "protonvpn"
        securityContext:
          capabilities:
            add: ["NET_ADMIN"]
      - name: socks5-proxy
        image: serjs/go-socks5-proxy:latest
        ports:
        - containerPort: 1080
        securityContext:
          capabilities:
            add: ["NET_ADMIN"]
        env:
        - name: PROXY_UPSTREAM
          value: "http://localhost:8080"  # Use localhost to route traffic through Gluetun

Explanation

  • Single Pod with Multiple Containers: Both the Gluetun VPN and Socks5 proxy run in the same Pod, allowing them to share the same network namespace. This setup simplifies routing, as the Socks5 proxy can send its traffic through the VPN by referencing localhost.
  • Environment Variables: I configured the Gluetun container using environment variables to connect to a ProtonVPN server via WireGuard. I replaced {hidden} with my actual WireGuard private key.

Step 2: Exposing the Socks5 Proxy

To make the Socks5 proxy accessible, I exposed it via a Kubernetes Service. Here’s the service configuration I used:

apiVersion: v1
kind: Service
metadata:
  name: socks5-proxy-service
spec:
  selector:
    app: vpn-proxy
  ports:
    - protocol: TCP
      port: 1080
      targetPort: 1080
  type: LoadBalancer

Explanation

  • Service Type: I used the LoadBalancer service type to expose the Socks5 proxy externally. On K3s, this service type exposes the proxy on the IP addresses of all the nodes in the cluster.
  • Port Configuration: The service listens on port 1080, which is the standard port for Socks5 proxies.

Step 3: Deploying via Portainer

With the YAML configurations ready, I used Portainer to deploy them to my K3s cluster. Here’s how I did it:

  1. Accessing Portainer: I logged into my Portainer instance.
  2. Deploying: I used Portainer's 'Custom template' feature to upload and deploy the YAML file to my K3s cluster.

Portainer handled the deployment, ensuring that the Pods and Services were correctly set up on my Raspberry Pi cluster.

Step 4: Verifying the Deployment

After deploying the setup, I verified that everything was working as expected:

  1. Checking the Pods: I used Portainer to check the status of the Pods, ensuring that both the Gluetun and Socks5 proxy containers were running within the same Pod.
  2. Viewing Logs: I reviewed the logs of the Gluetun container directly in Portainer to confirm that the VPN connection was successfully established.
  3. Testing Connectivity: I connected to the Socks5 proxy using the external IP address provided by the service. All traffic routed through the proxy was securely tunneled through the VPN.

Conclusion

Setting up a VPN-protected Socks5 proxy on a Raspberry Pi K3s cluster using Portainer was straightforward and effective. By running both the Gluetun and Socks5 proxy containers in the same Pod, I was able to ensure that all outgoing traffic from the proxy was routed securely through the VPN.

Next Steps

  • Scaling: I plan to explore scaling this setup to handle more traffic or provide redundancy.
  • Security: Adding authentication to the Socks5 proxy is on my to-do list to prevent unauthorized access.
  • Monitoring: Setting up monitoring tools to track the performance and availability of my VPN-protected proxy service will be the next step in optimizing my setup.

This setup has provided me with a secure, flexible, and private network service that runs efficiently on my Raspberry Pi cluster, all managed conveniently through Portainer.