# Octelium as a Self-Hosted ngrok Alternative

> Octelium documentation. Canonical page: <https://octelium.com/docs/octelium/latest/management/guide/service/http/open-source-self-hosted-ngrok-alternative>.

## Overview

Octelium can very easily operate as a scalable self-hosted, free and open source alternative to ngrok, Cloudflare Tunnel and similar tunneling-based remote access commercial products. When used as a gateway to your HTTP-based applications, Octelium provides the following:

- A scalable infrastructure to provide clientless access to any HTTP-based resource behind NAT from anywhere (e.g. private clouds, your own laptop, IoT, etc...).
- Secure clientless BeyondCorp access for human *Users* via Octelium's OpenID Connect and SAML 2.0 *IdentityProviders* (read more [here](https://octelium.com/docs/octelium/latest/management/core/identity-providers.md)) as well as for your workload *Users* via OAuth2 client credentials (read more [here](https://octelium.com/docs/octelium/latest/management/core/credential.md#oauth2-client-credentials)) and bearer access tokens (read more [here](https://octelium.com/docs/octelium/latest/management/core/credential.md#access-tokens))..
- Anonymous public access to your websites, APIs and webhooks (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/anonymous-access.md)).
- Deploy and scale your containerized applications as Octelium *Services* (read more about managed containers [here](https://octelium.com/docs/octelium/latest/management/core/service/managed-containers.md))
- Dynamic identity-based, context-aware, L7 aware, on a per-request basis, centralized access control via policy-as-code with CEL and OPA (read more about *Policies* and access control [here](https://octelium.com/docs/octelium/latest/management/core/policy.md)).
- Dynamic L7-aware routing to upstreams and advanced request/response header and body manipulation.
- OpenTelemetry-native, identity-based, L7 aware visibility and auditing.
- Zero-config private client-based access from anywhere by humans as well as workloads via the `octelium` clients and containers (read more about connecting to *Clusters* [here](https://octelium.com/docs/octelium/latest/user/cli/connect.md)).
- GitOps-friendly declarative, programmable management (read more [here](https://octelium.com/docs/octelium/latest/management/core/overview.md)).

*Diagram: OcteliumNgrok.* [View the diagram on the canonical HTML page](https://octelium.com/docs/octelium/latest/management/guide/service/http/open-source-self-hosted-ngrok-alternative).

> **Note:**
>
> This guide provides a very concise overview of Octelium's capabilities as a FOSS self-hosted ngrok/Cloudflare Tunnel alternative. You can read a more general tutorial about Octelium management [here](https://octelium.com/docs/octelium/latest/overview/management.md). You can also see the quick installation guide [here](https://octelium.com/docs/octelium/latest/overview/quick-install.md).

## A Simple Example

Let's assume in this guide that the *User*, `john`, wants to share some HTTP-based resource (e.g. web app, API, etc...) running on his laptop. Let's first create the *User* `john` in a YAML file as follows:

```yaml
kind: User
metadata:
  name: john
spec:
  type: HUMAN
  email: john@example.com
```

Now we assume the the resource to be served from `john`'s machine is listening to the address `localhost:8080`. We simply create the *Service* for our internal resource with the name `svc1` in separate `services.yaml` file as follows:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: HTTP
  isPublic: true
  isAnonymous: true
  config:
    upstream:
      url: http://localhost:8080
      # !mark
      user: john
```

> **Note:**
>
> This highlighted `user` field tells the *Cluster* that the upstream is served by a connection owned by that *User*. This enables any *User* to remotely serve any *Service*'s upstream behind NAT from anywhere (e.g. private clouds, Kubernetes clusters, laptops, IoT devices, etc...).

You can now apply the creation of both the *User* and *Service* as follows (read more about using `octeliumctl apply` [here](https://octelium.com/docs/octelium/latest/management/core/overview.md)):

```bash
export OCTELIUM_DOMAIN=<DOMAIN>
octeliumctl apply /PATH/TO/YAML_FILE_OR_PARENT_DIRECTORY
```

Now for `john` to actually serve the *Service* `svc1` from his side, `john` needs to connect to the *Cluster* via the `octelium connect` CLI command and adds the `--serve` flag as follows:

```bash
export OCTELIUM_DOMAIN=<DOMAIN>
octelium connect --serve svc1
```

You can also serve multiple *Services* simultaneously as follows:

```bash
octelium connect --serve svc1 --serve svc2
```

Also you can also serve all *Services* assigned to be served by the *User* via the `--serve-all` flag as follows:

```bash
octelium connect --serve-all
```

> **Note:**
>
> You can have several `octelium` clients serving the same *Service* upstream. In such case, the *Service* will load balance among all the upstreams served by all the available connected `octelium` clients. For example, you might use this to serve an upstream from a deployment in remote Kubernetes cluster that runs multiple replicas `octelium` containers or when you want to have a *Service* whose upstreams can be running in several clouds/servers. In fact you can even have a single *Service* that has multiple upstreams served by multiple *User* (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/overview.md#load-balancing)).

## Containerized Applications

You are not restricted to serving remote upstreams behind NAT from anywhere, you can also deploy your containers and serve them as Octelium *Services* (read more about managed containers [here](https://octelium.com/docs/octelium/latest/management/core/service/managed-containers.md)). Here is an example:

```yaml
kind: Service
metadata:
  name: anonymous-nginx
spec:
  mode: WEB
  isPublic: true
  isAnonymous: true
  config:
    upstream:
      container:
        image: nginx
        port: 80
```

You can also deploy your Docker images stored in private container registries (see a more detailed example [here](https://octelium.com/docs/octelium/latest/management/guide/service/http/nextjs-vite.md)). Here is an example:

```yaml
kind: Service
metadata:
  name: my-webapp
spec:
  mode: WEB
  isPublic: true
  isAnonymous: true
  config:
    upstream:
      container:
        port: 3000
        image: ghcr.io/<ORG>/<IMAGE>:<TAG>
        command:
        - npm
        args:
        - run
        - start
        replicas: 3
        credentials:
          usernamePassword:
            username: <USERNAME>
            password:
              fromSecret: registry-password
```

## Authenticated Access

Back to our initial example, the above *Service* configuration, namely the `isAnonymous` field, allows access for anonymous access over the internet. This could be useful for hosting and testing public websites, APIs, webhooks, etc.... However, you might want to only restrict the *Service* access to the *Cluster*'s *Users* who can access the *Service* after authenticating to a web-based *IdentityProvider* (e.g. OpenID Connect, SAML 2.0, GitHub OAuth2) via their browsers (read more [here](https://octelium.com/docs/octelium/latest/management/core/identity-providers.md)). You can do so by removing the `isAnonymous` field and adding *Policies* for who is allowed to access the *Service* (read more about *Policies* and access control [here](https://octelium.com/docs/octelium/latest/management/core/policy.md)). Here is an example:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: HTTP
  isPublic: true
  config:
    upstream:
      url: http://localhost:8080
      user: john
  # !mark(1:2)
  authorization:
    policies: ["allow-all"]
```

## Access Control

The above configuration allows access only for any authenticated *User*. However, you might want to control access in a more fine-grained way and not just allow access to all *Users*. Octelium actually provides a rich layer-7 aware, identity-based, context-aware ABAC access control on a per-request basis where you can control access based on the HTTP request's path, method, and even serialized JSON body content using policy-as-code with CEL and Open Policy Agent (OPA) (You can read more in detail about *Policies* and access control [here](https://octelium.com/docs/octelium/latest/management/core/policy.md)). Here is another more detailed example:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: HTTP
  isPublic: true
  config:
    upstream:
      url: http://localhost:8080
      user: john
  authorization:
    inlinePolicies:
      - spec:
          rules:
            - effect: ALLOW
              condition:
                all:
                  of:
                    - match: ctx.user.spec.email.endsWith("@example.com")
                    - match: ctx.request.http.path.startsWith("/apis")
                    - match: ctx.request.http.method in ["GET", "POST", "PUT", "DELETE"]
                    - match: ctx.request.http.uri == "/apis/users?name=john"
                    - match: ctx.request.http.queryParams.name == "john"
                    - match: ctx.request.http.headers["x-custom-header"] == "this-value"
                    - match: ctx.request.http.scheme == "http"
                    - match: string(ctx.request.http.body).toLower().contains("value1")
                    - match: ctx.request.http.bodyMap.key1 == "value1"
```

Now authorized *Users*, once authenticated for example by Github OAuth2, OpenID Connect or SAML *IdentityProviders* such as Okta or Azure AD/Microsoft Entra ID (read more [here](https://octelium.com/docs/octelium/latest/management/core/identity-providers.md)), can access the *Service* `svc1` either via the client-based private mode via the `octelium connect` command (read more [here](https://octelium.com/docs/octelium/latest/user/cli/connect.md)) as follows:

```bash
export OCTELIUM_DOMAIN=<DOMAIN>

# Now connect to the Cluster via the detached mode
octelium connect -d
# OR
sudo -E octelium connect

curl http://svc1:8080
```

Authorized *Users* can also access the *Service* via the clientless (i.e. BeyondCorp) mode (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/clientless.md)). For example, if the *Service* is a web app, `HUMAN` *Users* (read more about *User* management [here](https://octelium.com/docs/octelium/latest/management/core/user.md)) can simply access the *Service* via their browsers at the public URL `https://svc1.<DOMAIN>`. Authorized `WORKLOAD` *Users* can also access the *Service* in a clientless way via standard OAuth2 client credential flow (read more [here](https://octelium.com/docs/octelium/latest/management/core/credential.md#oauth2-client-credentials)) or even directly via bearer access tokens (read more [here](https://octelium.com/docs/octelium/latest/management/core/credential.md#access-tokens)).

## Dynamic Configuration

Octelium also allows you to dynamically route to an upstream based on the identity and the access context via policy-as-code (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/dynamic-config.md)). Here is an example of dynamic routing to an upstream based on the HTTP request path prefix:

```yaml
kind: Service
metadata:
  name: my-api
spec:
  mode: HTTP
  isPublic: true
  dynamicConfig:
    configs:
      - name: v1
        upstream:
          url: http://localhost:8080
          user: user-1
      - name: v2
        upstream:
          url: http://localhost:8080
          user: user-2
    rules:
      - condition:
          match: 'ctx.request.http.path.startsWith("/v1")'
        configName: v1
      - condition:
          match: 'ctx.request.http.path.startsWith("/v2")'
        configName: v2
```

## Observability

Octelium also provides OpenTelemetry-ready, application-layer L7 aware visibility and access logging in real time (see an example for HTTP [here](https://octelium.com/docs/octelium/latest/management/core/service/http.md#visibility)). You can read more about visibility [here](https://octelium.com/docs/octelium/latest/management/core/visibility.md).

```json
{
  "apiVersion": "core/v1",
  "kind": "AccessLog",
  "metadata": {
    // Omitted for brevity
  },
  "entry": {
      // Omitted for brevity
    },
    "info": {
      "http": {
        "request": {
          "path": "/",
          "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
          "method": "GET",
          "uri": "/?arg=value"
        },
        "response": {
          "code": 200,
          "bodyBytes": "615",
          "body": "PCFET0NUWV...",
          "contentType": "text/html"
        },
        "httpVersion": "HTTP11"
      }
    }
  }
}
```

This was a very short guide to show you how to use Octelium to deploy, scale, route and provide secure access as well as anonymous public access to any webapp containers. Here are a few more related features that you might be interested in:

- Routing not just by request paths, but also by header keys and values, request body content including JSON (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/http.md#json-request-body)).
- Request/response header manipulation (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/http.md#header-manipulation)).
- Cross-Origin Resource Sharing (CORS) (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/http.md#cross-origin-resource-sharing-cors)).
- gRPC mode (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/http.md#grpc-mode)).
- Secretless access to upstreams and injecting bearer, basic, or custom authentication header credentials (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/http.md#secretless-access)).
- Application layer-aware ABAC access control via policy-as-code using CEL and Open Policy Agent (read more [here](https://octelium.com/docs/octelium/latest/management/core/policy.md)).
- OpenTelemetry-ready, application-layer L7 aware auditing and visibility (read more [here](https://octelium.com/docs/octelium/latest/management/core/visibility.md)).
