Remote access and hosting for your homelab
Octelium is a free and open source, self-hosted zero trust access platform. It reaches everything on your home network from anywhere without forwarding a port, publishes what you want on your own domain with a managed certificate, and can deploy and host containerized applications itself.
- Free and open source
- No port forwarding
- Runs on a small VM
kind: Service
metadata:
name: jellyfin
spec:
mode: WEB
isPublic: true
config:
upstream:
url: http://192.168.1.30:8096
user: naskind: Policy
metadata:
name: household
spec:
rules:
- effect: ALLOW
condition:
all:
of:
- match: ctx.user.spec.type == "HUMAN"
- match: '"household" in ctx.user.spec.groups'kind: Service
metadata:
name: blog
spec:
mode: WEB
isPublic: true
isAnonymous: true
config:
upstream:
container:
port: 3000
image: ghcr.io/me/blog:latestA unified secure access platform
A homelab gets the same platform an organization does. Each capability is described in detail below, in the same order.
- Unified access platform
One architecture for client-based zero-config VPN-like access over WireGuard and QUIC tunnels and clientless access over browsers for humans and OAuth2 access for workloads.
Read more - L7-aware access control
Identity-based, application-layer aware ABAC access control with policy-as-code via CEL and OPA, applied on a per-request basis.
Read more - Secretless access
Dynamic secretless access where teams and AI agents access protected infrastructure without ever holding a credential.
Read more - Unified identity management
Teams, workloads and AI agents share the same model for identity management, access control, and auditing.
Read more - Real-time visibility and auditing
OpenTelemetry-native, real-time, application-layer-aware visibility and structured logging.
Read more - GitOps-friendly management
Octelium is administered like Kubernetes. Define your resources in YAML files, store them in a Git repository.
Read more
Reach it privately, publish it publicly, or both
Each resource is represented by a Service, which is served by an identity-aware proxy that abstracts away the network details of the upstream behind it. Where that upstream lives, and whether the internet can see it, are two separate fields.
- A Service upstream can be an address that is only reachable from the side of a connected host, so a NAS, a Pi or a container at home is served over its own outbound tunnel with no port forwarded.
- The same Service is reachable over a client-based WireGuard or QUIC tunnel with a stable private name, and clientlessly over HTTPS for a browser on a phone, a tablet or a television.
- Anonymous public access publishes an HTTP-based Service to the internet with authentication switched off, which turns the Cluster into a host for a personal site or a public API.
kind: Service
metadata:
name: jellyfin
spec:
mode: WEB
config:
upstream:
url: http://192.168.1.30:8096
user: naskind: Service
metadata:
name: jellyfin
spec:
mode: WEB
isPublic: true
config:
upstream:
url: http://192.168.1.30:8096
user: naskind: Service
metadata:
name: pihole-dns
spec:
mode: DNS
port: 53
config:
upstream:
url: dns://192.168.1.5
user: nasLayer-7 aware access control with policy-as-code
Access is authorized on a per-request basis, using CEL or Open Policy Agent, against the identity behind the request and the content of the request itself. Sharing one thing with someone does not share everything else.
- Groups keep household, guests and your own automation on separate sets of resources, and Policies attach to a Service, a Namespace, a User or a Group.
- Application-layer-aware access control that includes HTTP methods, paths, headers and serialized JSON body content, SSH users, Kubernetes verbs, resources and namespaces, and PostgreSQL and MySQL users and databases.
- Anonymous Services can enable anonymous authorization, which keeps them publicly reachable while still filtering on the request itself.
kind: Policy
metadata:
name: guests
spec:
rules:
- effect: ALLOW
condition:
all:
of:
- match: ctx.request.http.method == "GET"
- match: '"guests" in ctx.user.spec.groups'kind: Policy
metadata:
name: dns-com-only
spec:
rules:
- effect: ALLOW
condition:
match: ctx.request.dns.name.endsWith(".com.") &&
ctx.request.dns.typeID == 1kind: Service
metadata:
name: blog
spec:
mode: HTTP
isPublic: true
isAnonymous: true
config:
upstream:
url: http://192.168.1.40:3000
user: nas
authorization:
enableAnonymous: true
inlinePolicies:
- spec:
rules:
- effect: ALLOW
condition:
match: ctx.request.http.method == "GET"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. Nothing has to be pasted into a bookmark, a script or a shared note.
- Covers SSH passwords and private keys, PostgreSQL and MySQL passwords, HTTP API keys and access tokens, kubeconfigs and mTLS client certificates.
- Paid third-party APIs are covered as well, so a key you are billed for can be used by your own tools and by guests without being copied anywhere.
- Which upstream account and credential are used can be selected per request from identity, so your own devices and a guest reach the same Service with different privileges.
kind: Service
metadata:
name: nas-ssh
spec:
mode: SSH
port: 22
config:
upstream:
url: ssh://192.168.1.30
user: nas
ssh:
user: admin
auth:
privateKey:
fromSecret: nas-keykind: Service
metadata:
name: pg-home
spec:
mode: POSTGRES
port: 5432
config:
upstream:
url: postgres://192.168.1.35:5432
user: nas
postgres:
user: app
database: app
auth:
password:
fromSecret: pg-passwordkind: Service
metadata:
name: weather
spec:
mode: HTTP
isPublic: true
config:
upstream:
url: https://api.weather.example
http:
auth:
bearer:
fromSecret: weather-api-keyA unified identity model for humans and workloads
Human and workload Users share the same identity management, authentication, access control and visibility model. The machine serving your resources, the script that backs them up and the person watching a film are all identities in the same system.
- GitHub OAuth2 works as an identity provider out of the box, as does any OpenID Connect or SAML 2.0 provider, including a self-hosted Keycloak, Authentik or Dex.
- Native FIDO2 and WebAuthn passkeys, TOTP and TPM 2.0 authenticators are built in, so a hardware key can be required without running a separate MFA service.
- Scripts and automation authenticate with authentication tokens, OAuth2 client credentials or federated OIDC assertions, so nothing needs a stored password.
- A locally hosted OpenAI-compatible inference server can be fronted by the LLM gateway mode exactly as a hosted provider would be.
kind: IdentityProvider
metadata:
name: github
spec:
github:
clientID: Iv1.0123456789abcdef
clientSecret:
fromSecret: github-oauth2kind: User
metadata:
name: nas
spec:
type: WORKLOAD
groups:
- servingkind: Service
metadata:
name: ollama
spec:
mode: LLM
isPublic: true
config:
upstream:
url: http://192.168.1.50:11434
user: nas
llm:
protocol: OPENAIReal-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.
- Application-layer detail includes HTTP requests and responses, database queries, SSH session recordings, DNS question names, and LLM operations and token usage.
- Logs are exported over OTLP, which fits whatever you already run at home, whether that is a Grafana stack, an OpenSearch instance or a single collector writing to disk.
- Because the Cluster is yours, the record of who reached what stays inside your own boundary rather than in a provider's console.
A platform that also deploys your applications
A Cluster runs on Kubernetes and uses it to scale its own data plane, place Service proxies across Gateways, and run containerized applications that the Cluster itself deploys.
- Managed containers deploy, scale and serve a container image as the Service upstream, which covers a static site, a Next.js or Vite application or any small service, with no machine at home involved.
- Public DNS records and TLS certificates for published Services are managed by the Cluster, so putting something on your own domain is not a separate certificate workflow.
- The Cluster is managed declaratively. Resources are defined in YAML, kept in a Git repository, and applied with a single octeliumctl apply that reproduces the entire Cluster state.
$ octeliumctl apply ./cluster
Secret: nas-key Updated
Secret: github-oauth2 Updated
IdentityProvider: github Created
Policy: household Created
Group: household Created
Group: guests Updated
Service: jellyfin Created
Service: blog Created
Service: pihole-dns Created
User: nas Created
Cluster Core resources successfully applied
7 resources created
3 resources updated
ClusterConfig updatedThe things a homelab ends up needing, and what serves each
Most homelabs accumulate a tunnel, a reverse proxy, a certificate tool, a dynamic DNS client, an authentication portal and a pile of forwarded ports. These are the needs behind that, next to the mechanism in an Octelium Cluster that serves each one.
- 01
Reaching things at home from anywhere
A connected host serves the upstream over its own outbound tunnel, so nothing is port forwarded, no dynamic DNS is needed and the router configuration is untouched. That works for a NAS, a Raspberry Pi, a container or a laptop.
Read more - 02
Publishing something to the internet
The very same Service can be published over HTTPS on your own domain, either behind authentication or anonymously for a personal site or a public API, with the public DNS record and the TLS certificate managed by the Cluster.
Read more - 03
Hosting the application itself
There does not have to be a machine at home at all. Managed containers deploy, scale and serve a container image as the Service upstream, which covers a static site, a Next.js or Vite application or any small service.
Read more - 04
Logging in without another password
GitHub OAuth2 works as an identity provider out of the box, as does any OpenID Connect or SAML 2.0 provider, including a self-hosted Keycloak, Authentik or Dex that the Cluster can also serve.
Read more - 05
Letting other people in, carefully
Family, guests and your own automation can be separate Users in separate Groups with separate Policies, so sharing a media server does not also share the router, the NAS shell or the database.
Read more - 06
Shell access to small devices
The embedded SSH mode serves SSH from inside the octelium client itself, without a standalone SSH server on the host and without root privileges, which suits fleets of containers and small devices.
Read more - 07
Your own DNS, reachable remotely
A DNS Service puts a home resolver such as Pi-hole behind identity and can authorize on the question name and record type, so ad filtering follows you off the home network.
Read more - 08
A remote development environment
A code server or a remote IDE endpoint is just another Service, reachable in a browser or over the tunnel, with the upstream credential held by the Cluster rather than typed into a bookmark.
Read more
The point is not that each of these is hard on its own. It is that they are usually six separate pieces of software with six configurations, and here they are fields on the same resource.
The same platform capabilities ship with every deployment, whichever way you use it.
Frequently asked
- What does it take to run this at home?
- 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. That is enough for personal and homelab use. The Cluster itself is normally on a cheap cloud VM with a public address, while the resources it protects stay at home behind NAT.
- Do I have to forward ports or run dynamic DNS?
- No. A Service upstream can be an address that is only reachable from the side of a connected client. That client runs octelium connect with the --serve or --serve-all flag and serves the resource to the Cluster over its own outbound tunnel, so nothing inbound is opened on the home network and no dynamic DNS record has to track a changing address.
- Can I host a public website with it?
- Yes. Anonymous public access publishes an HTTP-based Service to the internet with authentication and authorization switched off, which makes the Cluster a hosting platform for a personal site or a public API. Anonymous authorization can then still be enabled so the Service filters on path, method, headers and body content while staying publicly reachable.
- Is the enterprise package needed for personal use?
- No. Octelium is free and open source and complete on its own. The enterprise package adds capabilities such as a web console, SCIM provisioning and secret encryption at rest, and it is free for personal, homelab and evaluation use.
- Do I need to know Kubernetes?
- No. An Octelium Cluster runs on top of Kubernetes, but you do not need Kubernetes experience to install, operate or use it. Day-to-day management is a set of YAML resources and a single octeliumctl apply, in the same shape as the examples on this page.
- Can family members use it without installing anything?
- Yes. HTTP-based resources can be published clientlessly, so a media server or a dashboard opens in an ordinary browser on a phone, a tablet or a television after a normal sign-in. The octelium client is only needed for protocols a browser cannot speak, such as SSH, databases and generic TCP and UDP.
Related solutions
ngrok alternative
Publish a local service on your own domain and your own infrastructure, with identity and policy in front of it.
Read moreSelf-hosted PaaS
Deploy, scale and serve containerized applications that the Cluster itself runs, with or without public access.
Read moreWireGuard remote access VPN
Zero-config WireGuard tunnels with a single stable route, dual-stack addressing and automatic private DNS.
Read moreDeploy Octelium on your own infrastructure in minutes
Free and open source. Self-hosted. No vendor lock-in.