{"id":48814096,"url":"https://github.com/gautada/vpn","last_synced_at":"2026-04-14T10:03:20.275Z","repository":{"id":104445368,"uuid":"324179092","full_name":"gautada/vpn","owner":"gautada","description":"A basic VPN container","archived":false,"fork":false,"pushed_at":"2026-02-26T19:32:38.000Z","size":7,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-28T03:55:44.973Z","etag":null,"topics":["container","network"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gautada.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-12-24T14:55:25.000Z","updated_at":"2026-02-27T01:45:17.000Z","dependencies_parsed_at":"2023-03-30T08:51:56.505Z","dependency_job_id":null,"html_url":"https://github.com/gautada/vpn","commit_stats":null,"previous_names":["gautada/vpn"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/gautada/vpn","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gautada%2Fvpn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gautada%2Fvpn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gautada%2Fvpn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gautada%2Fvpn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gautada","download_url":"https://codeload.github.com/gautada/vpn/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gautada%2Fvpn/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31791177,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T02:24:21.117Z","status":"ssl_error","status_checked_at":"2026-04-14T02:24:20.627Z","response_time":153,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["container","network"],"created_at":"2026-04-14T10:03:19.516Z","updated_at":"2026-04-14T10:03:20.270Z","avatar_url":"https://github.com/gautada.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vpn\n\nA containerised L2TP/IPsec VPN server that runs on the `gautada/debian` base image inside a Kubernetes cluster. Exposes a native system-VPN endpoint over the internet — no third-party app required. Connects macOS and iOS devices to your home network using the built-in VPN client on each platform.\n\n[![Build](https://github.com/gautada/vpn/actions/workflows/build.yml/badge.svg)](https://github.com/gautada/vpn/actions/workflows/build.yml)\n[![Image Version](https://ghcr.io/gautada/vpn)](https://github.com/gautada/vpn/pkgs/container/vpn)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\n---\n\n## About\n\n`gautada/vpn` runs an L2TP/IPsec server using [Libreswan](https://libreswan.org/) (IKE daemon) and [xl2tpd](https://github.com/xelerance/xl2tpd) (L2TP daemon), protected by [Fail2Ban](https://www.fail2ban.org/).\n\nKey properties:\n\n- **Protocol:** L2TP over IPsec (PSK) — natively supported by macOS and iOS with no extra software\n- **Base image:** [`gautada/debian`](https://github.com/gautada/debian) — the shared Debian 13 foundation for the entire container fleet\n- **Runtime:** Kubernetes — designed as a `Deployment` with a `LoadBalancer` service for internet exposure\n- **Role:** Home network gateway — k8s pods can already reach the home network; this container extends that access to external macOS and iOS clients\n\n---\n\n## Prerequisites\n\n- Kubernetes cluster (1.27+) with a `LoadBalancer` provider (or a `NodePort` on a publicly routable node)\n- A public IP address assigned to the LoadBalancer service\n- Required environment variables set as a Kubernetes `Secret` (see [Configuration](#configuration))\n- Container image from `ghcr.io/gautada/vpn`\n\n**`gautada/*` dependencies:**\n\n| Image | Purpose |\n|---|---|\n| [`gautada/debian`](https://github.com/gautada/debian) | Base OS image |\n\n---\n\n## Deployment\n\n### 1. Create the credentials Secret\n\n```bash\nkubectl create secret generic vpn-credentials \\\n  --from-literal=VPN_IPSEC_PSK='\u003cyour-ipsec-psk\u003e' \\\n  --from-literal=VPN_USER='\u003cyour-vpn-username\u003e' \\\n  --from-literal=VPN_PASSWORD='\u003cyour-vpn-password\u003e'\n```\n\n### 2. Apply the Deployment and Service\n\n```yaml\n# vpn.yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: vpn\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: vpn\n  template:\n    metadata:\n      labels:\n        app: vpn\n    spec:\n      containers:\n        - name: vpn\n          image: ghcr.io/gautada/vpn:latest\n          securityContext:\n            privileged: true        # required for iptables and kernel modules\n          envFrom:\n            - secretRef:\n                name: vpn-credentials\n          env:\n            - name: VPN_PUBLIC_IP\n              value: \"\u003cyour-public-ip\u003e\"  # set explicitly; auto-detect is unreliable in k8s\n          ports:\n            - containerPort: 500\n              protocol: UDP\n              name: ike\n            - containerPort: 4500\n              protocol: UDP\n              name: ike-nat\n            - containerPort: 1701\n              protocol: UDP\n              name: l2tp\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: vpn\nspec:\n  type: LoadBalancer\n  selector:\n    app: vpn\n  ports:\n    - name: ike\n      port: 500\n      targetPort: 500\n      protocol: UDP\n    - name: ike-nat\n      port: 4500\n      targetPort: 4500\n      protocol: UDP\n    - name: l2tp\n      port: 1701\n      targetPort: 1701\n      protocol: UDP\n```\n\n```bash\nkubectl apply -f vpn.yaml\n```\n\n### 3. Confirm the service is running\n\n```bash\nkubectl get pods -l app=vpn\nkubectl get svc vpn\n```\n\nThe `EXTERNAL-IP` column of the service is your VPN server address.\n\n---\n\n## Configuration\n\n| Variable | Required | Default | Description |\n|---|---|---|---|\n| `VPN_IPSEC_PSK` | ✅ | — | IPsec pre-shared key |\n| `VPN_USER` | ✅ | — | VPN username |\n| `VPN_PASSWORD` | ✅ | — | VPN password |\n| `VPN_PUBLIC_IP` | Recommended | auto-detect | Server's public IP address. Set explicitly in k8s — auto-detect is unreliable. |\n| `VPN_DNS_SRV1` | ❌ | `8.8.8.8` | Primary DNS server pushed to VPN clients |\n| `VPN_DNS_SRV2` | ❌ | `8.8.4.4` | Secondary DNS server pushed to VPN clients |\n| `VPN_L2TP_NET` | ❌ | `192.168.42.0/24` | L2TP internal network |\n| `VPN_L2TP_LOCAL` | ❌ | `192.168.42.1` | L2TP local (server-side) IP |\n| `VPN_L2TP_POOL` | ❌ | `192.168.42.10-192.168.42.250` | IP range assigned to L2TP clients |\n| `VPN_XAUTH_NET` | ❌ | `192.168.43.0/24` | IKEv1 XAuth internal network |\n| `VPN_XAUTH_POOL` | ❌ | `192.168.43.10-192.168.43.250` | IP range assigned to XAuth clients |\n\n---\n\n## Usage\n\n### macOS\n\n1. Open **System Settings → VPN → Add VPN Configuration → L2TP over IPSec**\n2. Fill in the fields:\n   - **Server Address:** Your `EXTERNAL-IP` from `kubectl get svc vpn`\n   - **Account Name:** Value of `VPN_USER`\n3. Click **Authentication Settings…**\n   - **Password:** Value of `VPN_PASSWORD`\n   - **Shared Secret:** Value of `VPN_IPSEC_PSK`\n4. Tick **Send all traffic over VPN connection** if you want full tunnel\n5. Click **Connect**\n\n### iOS\n\n1. Open **Settings → General → VPN \u0026 Device Management → VPN → Add VPN Configuration**\n2. Set **Type** to **L2TP**\n3. Fill in the fields:\n   - **Description:** Home VPN (or any label)\n   - **Server:** Your `EXTERNAL-IP` from `kubectl get svc vpn`\n   - **Account:** Value of `VPN_USER`\n   - **Password:** Value of `VPN_PASSWORD`\n   - **Secret:** Value of `VPN_IPSEC_PSK`\n4. Tap **Done**, then toggle the VPN on\n\n---\n\n## Architecture\n\n```\nInternet\n   │\n   ▼\nLoadBalancer Service (UDP 500, 4500, 1701)\n   │\n   ▼\nvpn Pod  (gautada/vpn)\n   ├── Libreswan (ipsec) — IKE / IPsec keying\n   ├── xl2tpd — L2TP tunnel daemon\n   └── Fail2Ban — brute-force protection\n   │\n   ▼\nk8s cluster network → home network\n```\n\n**Container fleet position:**\n\n| Layer | Image |\n|---|---|\n| OS base | [`gautada/debian`](https://github.com/gautada/debian) |\n| VPN (this repo) | [`gautada/vpn`](https://github.com/gautada/vpn) |\n| Mesh overlay (separate) | [`gautada/tailscale`](https://github.com/gautada/tailscale) |\n\n`gautada/tailscale` handles Tailscale-based mesh access (a separate concern). This container handles the internet-facing native-VPN endpoint.\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgautada%2Fvpn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgautada%2Fvpn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgautada%2Fvpn/lists"}