Business VPN

The open source, self-hosted business VPN

Octelium is a free and open source, self-hosted zero trust access platform. For a team it behaves as a zero-config VPN with single sign-on: people install one client, sign in with the accounts they already have, and reach the internal resources they are authorized for by name. What each of them may reach is decided per request rather than by the network they land on.

  • Free and open source
  • Designed for self-hosting
  • Works with your existing SSO
service.yaml
A ServiceEach internal resource is a Service with a stable private address and DNS name.
A Service. Each internal resource is a Service with a stable private address and DNS name.
kind: Service
metadata:
  name: wiki
spec:
  mode: HTTP
  config:
    upstream:
      url: http://10.0.6.18:3000
Your identity provider. People sign in with the accounts they already have, through OpenID Connect or SAML 2.0.
kind: IdentityProvider
metadata:
  name: okta
spec:
  oidc:
    issuerURL: https://acme.okta.com
    clientID: 0oa1abcdefghij
    clientSecret:
      fromSecret: okta-client-secret
A Policy. Groups from your identity provider decide what each team can reach.
kind: Policy
metadata:
  name: employees
spec:
  rules:
    - effect: ALLOW
      condition:
        all:
          of:
            - match: ctx.user.spec.type == "HUMAN"
            - match: '"employees" in ctx.user.spec.groups'
service-private.yaml
A private resourceA resource behind NAT in any environment, reached over the tunnel through a single stable route.
A private resource. A resource behind NAT in any environment, reached over the tunnel through a single stable route.
kind: Service
metadata:
  name: wiki
spec:
  mode: HTTP
  config:
    upstream:
      url: http://10.0.6.18:3000
The same resource, clientlessly. One added field publishes the very same Service over HTTPS, for people with nothing installed.
kind: Service
metadata:
  name: wiki
spec:
  mode: HTTP
  isPublic: true
  config:
    upstream:
      url: http://10.0.6.18:3000
A group of resources. A Namespace groups Services and can carry the Policies that apply to all of them.
kind: Namespace
metadata:
  name: internal
spec:
  authorization:
    policies:
      - employees
    inlinePolicies:
      - spec:
          rules:
            - effect: DENY
              condition:
                match: '"contractors" in
                  ctx.user.spec.groups'
policy-context.yaml
Identity and contextDevice posture, session type and group membership are attributes in the same expression.
Identity and context. Device posture, session type and group membership are attributes in the same expression.
kind: Policy
metadata:
  name: sensitive
spec:
  rules:
    - effect: ALLOW
      condition:
        all:
          of:
            - match: ctx.user.spec.type == "HUMAN"
            - match: ctx.session.status.type == "CLIENT"
            - match: ctx.device.status.osType in ["MAC", "WINDOWS"]
            - match: '"finance" in ctx.user.spec.groups'
The request itself. Method, path, headers and serialized JSON body are all part of the request context.
kind: Policy
metadata:
  name: read-only
spec:
  rules:
    - effect: ALLOW
      condition:
        all:
          of:
            - match: ctx.request.http.method == "GET"
            - match: ctx.request.http.path.startsWith("/docs")
            - match: '"employees" in ctx.user.spec.groups'
Enforced multi-factor. An Authenticator can be required after sign-in, independently of what the provider enforces.
kind: ClusterConfig
metadata:
  name: cluster-config
spec:
  authenticator:
    authenticationEnforcementRules:
      - condition:
          match: ctx.session.status.isBrowser
        effect: ENFORCE
      - condition:
          match: '"finance" in ctx.user.spec.groups'
        effect: ENFORCE
Secretless access

Credentials that are never distributed

Application-layer credentials are stored in the Cluster as Secrets and injected into the upstream connection once a request is authorized. A tunnel on its own does nothing about the API keys, database passwords and private keys that a team accumulates.

Read the secretless access guide
saas.yaml
A SaaS APIAn API key is injected upstream after authorization, so a team reaches a SaaS API without holding it.
A SaaS API. An API key is injected upstream after authorization, so a team reaches a SaaS API without holding it.
kind: Service
metadata:
  name: stripe
spec:
  mode: HTTP
  config:
    upstream:
      url: https://api.stripe.com
    http:
      auth:
        bearer:
          fromSecret: stripe-api-key
A database. The upstream password stays in the Cluster, and the Service forces the database user.
kind: Service
metadata:
  name: pg-prod
spec:
  mode: POSTGRES
  port: 5432
  config:
    upstream:
      url: postgres://10.0.4.21:5432
    postgres:
      user: analytics_ro
      database: analytics
      auth:
        password:
          fromSecret: pg-password
SSH. No private keys or passwords are distributed, and no PKI has to be operated.
kind: Service
metadata:
  name: bastion
spec:
  mode: SSH
  port: 22
  config:
    upstream:
      url: ssh://10.0.2.14
    ssh:
      user: deploy
      auth:
        privateKey:
          fromSecret: bastion-key
idp-workload.yaml
Secretless workload identityWorkloads authenticate with OIDC assertions issued by the platform running them.
Secretless workload identity. Workloads authenticate with OIDC assertions issued by the platform running them.
kind: IdentityProvider
metadata:
  name: github-actions
spec:
  oidcIdentityToken:
    issuerURL: https://token.actions.githubusercontent.com
    audience: https://example.com
A workload User. A CI job or a server is a User with the same groups, Policies and audit trail as a person.
kind: User
metadata:
  name: ci-runner
spec:
  type: WORKLOAD
  groups:
    - ci
An LLM gateway. Model providers are reached through the same identity, Policies and auditing as everything else.
kind: Service
metadata:
  name: openai
spec:
  mode: LLM
  isPublic: true
  config:
    upstream:
      url: https://api.openai.com
    llm:
      protocol: OPENAI
      auth:
        bearer:
          fromSecret: openai-api-key
Visibility and auditing

Real-time visibility at the application layer

OpenTelemetry-ready, application-layer aware, structured auditing and visibility emitted to your OpenTelemetry OTLP receivers, where they can be exported to your log management and SIEM tools.

Read about visibility and auditing
AccessLogOTLP
ALLOWlinus@acme.compg-prod.dbPOSTGRESquery: select id, email from users limit 50
ALLOWci-runnerprod-k8sKUBERNETESverb=list resource=pods namespace=production
DENYagent-07tools-mcpMCPtools/call name=transfer policy=mcp-tools
ALLOWjane@acme.combastionSSHsession recorded, upstream user=deploy
ALLOWagent-07openaiLLMCHAT_COMPLETIONS model=gpt-5-mini tokens=1284
octeliumctl
octeliumctl apply ./cluster
$ octeliumctl apply ./cluster
Secret: okta-client-secret Updated
Secret: pg-password Updated
IdentityProvider: okta Updated
Policy: employees Created
Group: employees Created
Group: finance Updated
Service: wiki.internal Created
Service: bastion Created
Service: pg-prod.db Created
Namespace: internal Created
Cluster Core resources successfully applied
 7 resources created
 3 resources updated

 ClusterConfig updated
Day to day

What it looks like from each side

A business VPN is used by everyone in the organization and operated by a small number of people. These are the two experiences it has to serve at once.

For the people using it

One client, one sign-in, and resources that are reachable by name.

  • Install the octelium client on Windows, macOS or Linux, or use nothing at all for resources published in a browser.
  • Sign in with the same account and the same multi-factor prompts they already use elsewhere.
  • Reach every authorized resource by a stable private name, with no routes, addresses or profiles to configure.
  • Never receive an API key, a database password or an SSH private key in order to do their job.
  • Ask for time-bound access to something they do not normally need, and have it approved rather than granted permanently.
For the team running it

One declarative configuration, reviewable in Git and reproducible.

  • Define Services, Policies, Groups and Secrets in YAML and apply the whole Cluster state with a single command.
  • Express access as attributes of identity, device and request rather than as addresses, subnets and firewall rules.
  • Hold every upstream credential in the Cluster, so offboarding is a Policy change rather than a rotation exercise.
  • Stream identity-aware, application-layer audit logs over OpenTelemetry into the SIEM the organization already runs.
  • Scale Gateways horizontally on Kubernetes instead of sizing an appliance to peak concurrent users.
Questions

Frequently asked

What does a person actually install?
One CLI, the octelium client, on Windows, macOS or Linux. Running octelium connect signs them in through your identity provider and brings up the tunnel. From then on every resource they are authorized for has a stable private name that resolves automatically, so there is nothing to configure per resource and nothing to reconfigure when an upstream address changes.
Do people have to install anything at all?
Not necessarily. HTTP-based resources can be published clientlessly over HTTPS, where a person signs in through your identity provider in a browser and reaches the application directly. The same Service can be reachable both ways at once, under the same Policies, which is useful for contractors, unmanaged devices and mobile access.
Can I keep my existing identity provider?
Yes. Any OpenID Connect or SAML 2.0 identity provider is supported, as well as GitHub OAuth2. Group membership from the provider drives access decisions. Octelium additionally provides native FIDO2 and WebAuthn passkeys, TOTP and TPM 2.0 authenticators that can be required through policy on sensitive Services, independently of what the identity provider itself enforces.
What happens when somebody leaves?
Removing them in your identity provider ends their ability to authenticate, and their Sessions can be revoked directly. Because upstream credentials such as API keys, database passwords and SSH private keys are held by the Cluster and never distributed, there is no separate rotation exercise across every system that person could reach.
Does it need dedicated hardware?
No. An Octelium Cluster runs on Kubernetes, on infrastructure you already operate. The quick installer provisions a complete single-node Cluster, including Kubernetes itself, on one fresh Linux VM with 2 vCPUs, 2 GB of RAM and a domain you own, which is enough for a small team. Larger deployments run on scalable managed or on-premise Kubernetes installations, where Gateways scale horizontally.
Is Octelium free and open source?
Yes. Octelium is free and open source and is designed for single-tenant self-hosting. There is no proprietary cloud-based control plane, and it is not a limited edition of a separate paid product. An enterprise package is available for organizations that need capabilities such as a web console, SCIM provisioning and secret encryption at rest, and it is free for personal, homelab and evaluation use.
Get started

Deploy Octelium on your own infrastructure in minutes

Free and open source. Self-hosted. No vendor lock-in.