# Apply: kubectl apply -f manifests/media/qbittorrent.yaml # Delete: kubectl delete -f manifests/media/qbittorrent.yaml # Description: qBittorrent deployment with Ingress at qbittorrent.home.arpa. apiVersion: v1 kind: Namespace metadata: name: downloads --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: qbittorrent-config namespace: downloads annotations: helm.sh/resource-policy: keep spec: accessModes: - ReadWriteOnce storageClassName: local-path resources: requests: storage: 1Gi --- apiVersion: apps/v1 kind: Deployment metadata: name: qbittorrent namespace: downloads spec: replicas: 1 selector: matchLabels: app: qbittorrent template: metadata: labels: app: qbittorrent spec: nodeSelector: node-role: storage containers: - name: gluetun image: qmcgaw/gluetun:latest securityContext: capabilities: add: - NET_ADMIN env: - name: VPN_SERVICE_PROVIDER value: private internet access - name: VPN_TYPE value: openvpn - name: SERVER_REGIONS value: Hong Kong - name: OPENVPN_USER valueFrom: secretKeyRef: name: pia-credentials key: OPENVPN_USER - name: OPENVPN_PASSWORD valueFrom: secretKeyRef: name: pia-credentials key: OPENVPN_PASSWORD - name: FIREWALL_OUTBOUND_SUBNETS value: "10.42.0.0/16,10.43.0.0/16,192.168.7.0/24" - name: BLOCK_IPV6 value: "on" volumeMounts: - name: tun mountPath: /dev/net/tun - name: qbittorrent image: lscr.io/linuxserver/qbittorrent:5.2.0 ports: - containerPort: 8080 env: - name: PUID value: "1000" - name: PGID value: "1000" - name: TZ value: "Asia/Tokyo" - name: WEBUI_PORT value: "8080" volumeMounts: - name: config mountPath: /config - name: torrents mountPath: /mnt/storage/torrents - name: ip-reporter image: python:3-alpine ports: - containerPort: 8888 command: - python3 - -c - | import http.server, urllib.request class Handler(http.server.BaseHTTPRequestHandler): def do_GET(self): try: ip = urllib.request.urlopen('https://ipinfo.io/ip').read().decode().strip() except Exception as e: ip = f'error: {e}' body = f'''
🌐 VPN IP: {ip} '''.encode() self.send_response(200) self.send_header('Content-Type', 'text/html; charset=utf-8') self.send_header('Content-Length', len(body)) self.send_header('Content-Security-Policy', 'frame-ancestors *') self.end_headers() self.wfile.write(body) def log_message(self, *a): pass http.server.HTTPServer(('0.0.0.0', 8888), Handler).serve_forever() volumes: - name: tun hostPath: path: /dev/net/tun type: CharDevice - name: config persistentVolumeClaim: claimName: qbittorrent-config - name: torrents hostPath: path: /mnt/storage/torrents type: Directory --- apiVersion: v1 kind: Service metadata: name: qbittorrent namespace: downloads spec: selector: app: qbittorrent ports: - name: web port: 80 targetPort: 8080 - name: ip-reporter port: 8888 targetPort: 8888 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: qbittorrent namespace: downloads annotations: traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.tls: "true" cert-manager.io/cluster-issuer: internal-ca-issuer spec: ingressClassName: traefik tls: - secretName: qbittorrent-tls hosts: - qbittorrent.home.arpa rules: - host: qbittorrent.home.arpa http: paths: - path: / pathType: Prefix backend: service: name: qbittorrent port: number: 80 --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: gluetun-tls namespace: downloads spec: secretName: gluetun-tls issuerRef: name: internal-ca-issuer kind: ClusterIssuer dnsNames: - gluetun.home.arpa --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: gluetun-api namespace: downloads spec: entryPoints: - websecure routes: - match: Host(`gluetun.home.arpa`) kind: Rule services: - name: qbittorrent port: 8888 tls: secretName: gluetun-tls