Self-Hosted Proxy Server “Tinyproxy” in Kubernetes installieren

Jannik Zinkl
Jannik Zinkl
  • 2023-03-28
  • 10 mins
Blog Images

In diesem kurzem Tutorial setzen wir einen eigenen Proxy Server auf, der verwendet werden kann um den Internet Traffic von Endgeräten umzuleiten. Damit kann z.B. Geoblocking umgangen werden, da man immer mit der gleichen IP Adresse im Internet unterwegs ist. Damit geht man auch immer mit einer statischen IP Adresse ins Internet und kann den Zugang zu Websites auf IP-Adresslevel einschränken.

Der Service ist sehr klein und kostet kaum Ressourcen. Wir benutzen “Tinyproxy” und hosten den Service in Kubernetes.

Anwendungsfälle für einen Internetproxy

Wenn es um die Konfiguration von Netzwerkverbindungen oder das Umgehen von Geoblockings geht, ist der Einsatz von Proxy-Servern eine gängige Praxis. Sie dienen dazu, den Datenverkehr zu kontrollieren, die Privatsphäre zu schützen und den Netzwerkzugriff auf bestimmte Websites zu beschränken. In diesem Zusammenhang ist Tinyproxy eine hervorragende Option für alle, die nach einem schnellen und schlanken Proxy-Server suchen. Als Bonus werden wir in diesem Artikel noch das passende Proxy.pac File erstellen, mit dem “Split-Tunnel” aufgebaut werden können, damit nur bestimmte Anwendungen über den Proxy laufen.

Was ist Tinyproxy?

Tinyproxy ist ein Open-Source-Proxy-Server, der entwickelt wurde, um einen schnellen und effizienten Datenverkehr zu ermöglichen. Im Vergleich zu anderen Proxy-Servern ist Tinyproxy sehr schlank und benötigt nur wenige Systemressourcen, was es zu einer idealen Wahl für den Einsatz auf kleineren Systemen macht. Er ist in der Lage, HTTP- und HTTPS-Anfragen zu verarbeiten und ermöglicht die einfache Konfiguration von Proxy-Einstellungen für Webbrowser und andere Anwendungen.

Tinyproxy ist sehr reduziert im Funktionsumfang, weshalb er leider aktuell auch nur HTTP/1 unterstützt und sicherlich auch an anderen Stellen Mängel aufweist. Dafür ist er allerdings einfach im Setup und hat in unseren Tests auch langfristig überzeugt.

Tinyproxy in Kubernetes

Wir werden das vorgefertigte Docker Image von Kalaksy verwenden um den Service in Kubernetes zu hosten. Für die Konfiguration wird eine Configmap angelegt und für den Zugriff aus dem Internet ein NodePort. Theoretisch wäre hier auch ein HTTP Ingress denkbar - da wir hier allerdings diverse Probleme mit automatischen Healthchecks hatten, sind wir einfach auf Nodeports umgeschwenkt.

Das Setup wurde mit Rancher aufgesetzt, weshalb man hier die typischen Annotations wiederfindet. Im Prinzip ist das Deployment allerdings sehr simpel und kann einfach nachgebaut und an die eigenen Anforderungen angepasst werden.

Deployment File

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
  labels:
    workload.user.cattle.io/workloadselector: apps.deployment-vpn-proxy-services-tinyproxy
  name: tinyproxy
  namespace: vpn-proxy-services
spec:
  progressDeadlineSeconds: 600
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      workload.user.cattle.io/workloadselector: apps.deployment-vpn-proxy-services-tinyproxy
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      annotations:
      labels:
        workload.user.cattle.io/workloadselector: apps.deployment-vpn-proxy-services-tinyproxy
    spec:
      containers:
      - image: kalaksi/tinyproxy
        imagePullPolicy: Always
        name: container-0
        ports:
        - containerPort: 8888
          name: web
          protocol: TCP
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /etc/tinyproxy/tinyproxy.conf
          name: vol-2tvbi
          readOnly: true
          subPath: tinyproxy.conf
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      volumes:
      - configMap:
          defaultMode: 420
          name: config
        name: vol-2tvbi

Um eine gewisse Verfügbarkeit zu ermöglichen wurden direkt zwei Replikas aktiviert. Weiterhin wird das Configfile als Volume unter /etc/tinyproxy/tinyproxy.confeingehängt.

Konfiguration

Das Konfigurationsfile ist ebenfalls sehr simpel. Alle möglichen Einstellungen finden sich auf der Website des Tinyproxy Projekts.

Für unseren sehr simplen Webproxy verwenden wir nur die nötigsten Einstellungen. Es empfiehlt sich hier zumindest eine Basic-Auth Authentifizierung einzubauen. Wenn der Proxy z.B. in den Mac Einstellungen direkt als Proxy eingetragen wird, ist die Userbility leider nicht mehr sehr gut, da hier jede App einzeln nach Zugriff auf den Schlüsselbund fragt um Nutzername und Passwort des Proxies zu erhalten. Proxy .pac Files unterstützen ebenfalls keine hardkodierten Berechtigungen. Als mögliche Einschränkung könnte man noch mit Domain allow / deny Listen arbeiten um die Arbeit des Proxies auf bestimmte Seiten zu beschränken. Das mögliche Betrugspotential ist damit weiter reduziert. In unserem Fall arbeitet wir einfach mit einem sehr hohen Port, der im Normalfall von betrügerischen Portscannern ausgelassen wird.

# config.yml
apiVersion: v1
data:
  tinyproxy.conf: |-
    Port 8888
    Timeout 600
kind: ConfigMap
metadata:
  name: config
  namespace: vpn-proxy-services

Der “Listen-Port” ist die einzige verpflichtende Einstellung. Alles weitere belassen wir auf den default-Werten.

NodePort Service

Zuletzt noch der passende Nodeport:

apiVersion: v1
kind: Service
metadata:
  annotations:
    field.cattle.io/targetWorkloadIds: '["vpn-proxy-services/tinyproxy"]'
    management.cattle.io/ui-managed: "true"
  name: tinyproxy-nodeport
  namespace: vpn-proxy-services
  ownerReferences:
  - apiVersion: apps/v1
    controller: true
    kind: Deployment
    name: tinyproxy
    uid: 18c6e0df-bb3b-4e68-b380-a92b775bfcf3
spec:
  externalTrafficPolicy: Cluster
  ports:
  - name: web
    # Hier kann ein passender Port aus dem NodePort Bereich des Kubelets gewählt werden
		nodePort: 32479
    port: 8888
    protocol: TCP
    targetPort: 8888
  selector:
    workload.user.cattle.io/workloadselector: apps.deployment-vpn-proxy-services-tinyproxy
  sessionAffinity: None
  type: NodePort

Setup testen

Der TinyProxy sollte jetzt über die IP-Adresse von jeglichem Worker erreichbar sein. Der Port wurde gesetzt - als Beispiel 116.116.566.56:32579

Mit Curl lässt sich das Setup testen:

https_proxy=http://116.116.566.56:32579/ curl https://trieb.work

Die Website sollte laden und in den Tinyproxy Logs sollten die Requests sichtbar sein. Der Proxyserver kann jetzt so in den Einstellungen der Betriebssysteme vorgenommen werden. Der gesamte Traffic wird dann entsprechend über den Proxy geleitet. Wenn man nur bestimmte Pages über den Proxy schicken möchte, also eine Art “Split-Tunnel” aufbauen, findet man mit dem Proxy.pac File eine einfache Lösung.

Bonus: Ein passendes proxy .pac File

Ein Proxy-Auto-Config-File, oder kurz PAC-File, ist eine JavaScript-Datei, die von Webbrowsern verwendet wird, um zu entscheiden, ob ein bestimmter Webbrowser-Request direkt mit der Ziel-Website verbunden oder ob der Request an einen Proxy-Server weitergeleitet werden soll. PAC-Files werden oft verwendet, um eine “Split-Tunnel”-Konfiguration zu erstellen, bei der nur bestimmte Anwendungen oder Seiten über den Proxy geleitet werden. Ein PAC-File besteht aus einer Reihe von JavaScript-Funktionen, die Entscheidungen auf der Grundlage von Informationen wie der Ziel-URL oder der IP-Adresse des Clients treffen, und einer Funktion, die den Proxy-Server zurückgibt, der verwendet werden soll, wenn der Request an den Proxy-Server weitergeleitet werden soll. Das PAC-File muss auf einem Webserver gehostet werden, was es für simple Setups schon wieder unnötig kompliziert macht. In unserem Beispiel hosten wir das PAC-File auf Vercel - es sollte aber theoretisch auch z.B. über den Mac eigenen Webserver auf Localhost liegen können.

Ein simples PAC-File welches die wichtigsten Microsoft Office 365 Anwendungen über den Proxyserver leitet und damit z.B. Geoblocking auf IP-Basis umgeht:

const hostRegexList = ["office.com", "microsoft365.com", "login.microsoftonline.com", "msftauth.net", "microsoftazuread-sso.com", "login.live.com"]

const match = (url) => {

  return hostRegexList.some((x) => {
    const matcher = url.match(x)
    if (matcher && matcher[0]) return true
    return false
  })

}
function FindProxyForURL(url, host) {
  if (match(url)) {
    return "PROXY 116.116.566.56:32579";
  } else {
    return "DIRECT"
  }
}

Das Proxy .pac File liefert immer entweder “PROXY” oder “DIRECT” zurück. Es können simple Javascript Funktionen verwendet werden um ein Matching zu realisieren.

Um ein Proxy.pac File bei Windows einzustellen, muss man in den Einstellungen der Netzwerkverbindung den Pfad zum Proxy.pac File angeben. Dazu wählt man unter "Proxyserver" die Option "Automatische Proxy-Konfigurations-URL verwenden" und gibt den Pfad zum Proxy.pac File ein.

Bei Mac OS kann man das Proxy.pac File in den Einstellungen unter "Netzwerk" -> "Proxies" -> "Automatische Proxy-Konfiguration" angeben. Dort kann man den Pfad zum Proxy.pac File eintragen.

Bei iOS muss man in den Einstellungen unter "WLAN" das WLAN-Netzwerk auswählen, für das man den Proxy verwenden möchte. Dort kann man unter "HTTP-Proxy" die Option "Automatisch" auswählen und den Pfad zum Proxy.pac File eintragen.

Jannik Zinkl
Jannik Zinkl

Entrepreneur & Cloud Architect with a passion for Climate Tech