# Make Umbrel Apps Available via Custom Domains with a Valid SSL Certificate Inside Your Tailnet on Umbrel OS 2.0

**URL:** <https://community.umbrel.com/t/make-umbrel-apps-available-via-custom-domains-with-a-valid-ssl-certificate-inside-your-tailnet-on-umbrel-os-2-0/25621>\
**Category:** Guides\
**Created:** [October 12, 2026, 7:44am UTC](https://community.umbrel.com/t/make-umbrel-apps-available-via-custom-domains-with-a-valid-ssl-certificate-inside-your-tailnet-on-umbrel-os-2-0/25621 "2026-10-12T07:44:14Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![faultbendfold](https://avatars.discourse-cdn.com/v4/letter/f/e99b99/32.png) [@faultbendfold](https://community.umbrel.com/u/faultbendfold)\
**Post date:** [October 12, 2026, 7:44am UTC](https://community.umbrel.com/t/make-umbrel-apps-available-via-custom-domains-with-a-valid-ssl-certificate-inside-your-tailnet-on-umbrel-os-2-0/25621/1 "2026-10-12T07:44:14Z")

</div>

This guide explains how to make apps on **umbrelOS 2.0** accessible exclusively within a **Tailscale tailnet** using custom HTTPS subdomains.

**German Version of this guide is in the next comment!**

Example:

```plaintext
https://excalidraw.example.com
https://immich.example.com
https://umbrel.example.com

```

The services remain **unreachable from the public internet.**

## Target architecture

```plaintext
*.example.com
      │ DNS: Umbrel's Tailscale IP
      ▼
100.x.y.z:443
      │ Tailscale Serve (TCP forwarder)
      ▼
Umbrel LAN IP:40443
      │ Nginx Proxy Manager
      ▼
docker-host:<Umbrel app port>
      │ Umbrel App Gateway
      ▼
Umbrel app

```

## Requirements

- umbrelOS 2.0
- Tailscale app installed on the Umbrel
- Nginx Proxy Manager installed on the Umbrel
- your own domain with access to its DNS settings
- a certificate for the domain configured in Nginx Proxy Manager:

```plaintext
example.com
*.example.com

```

- all devices that should access the apps are members of the same tailnet

> **No public router port forwarding is required. Tailscale Funnel is not required either.**

## 1. Determine the IP addresses

Two addresses are needed for the configuration:

- **local Umbrel LAN IP** , for example `192.168.178.12`
- **Umbrel Tailscale IP** , for example `100.x.y.z`

The Tailscale IP is reachable only from within the tailnet.

## 2. Configure DNS

Create a wildcard A record with your DNS provider:

```plaintext
Type: A
Hostname: *.example.com
Value: 100.x.y.z
TTL: 1 hour

```

Optionally, point the apex domain to the Umbrel as well:

```plaintext
Type: A
Hostname: @
Value: 100.x.y.z

```

Replace `100.x.y.z` with your own Tailscale IP.

### Important: use a DNS record, not web forwarding

Your domain provider must use a real **DNS A record**. HTTP or domain forwarding is unsuitable because it can change the hostname. Nginx Proxy Manager needs the original hostname to route the request to the correct Proxy Host.

Remove any conflicting wildcard A, AAAA, or CNAME records.

## 3. Understand Nginx Proxy Manager

The Umbrel version of Nginx Proxy Manager uses these ports by default:

```plaintext
Management interface: Port 4498
HTTP entry point: Port 40080
HTTPS entry point: Port 40443

```

The management interface is normally available at:

```plaintext
http://umbrel.local:4498

```

Because NPM does not listen directly on host port 443, Tailscale must forward incoming tailnet connections from port 443 to port 40443.

## 4. Forward Tailscale port 443 to NPM

First, check the current configuration in the Tailscale app terminal:

```bash
tailscale serve status

```

If no Serve configuration exists, the output is:

```plaintext
No serve config

```

Then configure the TCP forwarder:

```bash
tailscale serve --bg --tcp=443 tcp://192.168.178.12:40443

```

Replace `192.168.178.12` with the Umbrel’s local LAN IP.

Verify the configuration:

```bash
tailscale serve status

```

The output should look similar to this:

```plaintext
Available within your tailnet:

|-- tcp://100.x.y.z:443
|--> tcp://192.168.178.12:40443

```

### What the TCP forwarder does

```plaintext
Tailscale IP:443 → Umbrel LAN IP:40443

```

The forwarder does not terminate the TLS connection. The TLS certificate is still served by Nginx Proxy Manager.

### Remove the forwarder when port forwarding is no longer needed

```bash
tailscale serve --tcp=443 off

```

## 5. Effect on the Umbrel dashboard

The TCP forwarder takes over the entire port 443 of the Tailscale IP. Therefore, the same address cannot provide both the Umbrel dashboard directly and NPM at the same time:

```plaintext
https://100.x.y.z

```

After enabling the forwarder, this address reaches NPM instead of the dashboard directly.

The clean solution is to create a dedicated NPM Proxy Host for the Umbrel dashboard, for example:

```plaintext
https://umbrel.example.com

```

## 6. Determine an Umbrel app’s port

The relevant port is defined in the app’s `umbrel-app.yml`, for example:

```yaml
port: 4422

```

This port is the public entry point of the Umbrel App Gateway and is the correct target port for NPM.

Do not confuse it with internal container ports. An app may internally use port 80 or 4000 while Umbrel exposes it through port 4422:

```plaintext
NPM → Umbrel port 4422 → App Gateway → container port 80

```

The port can often also be read from the app’s local launch URL:

```plaintext
http://umbrel.local:4422

```

## 7. Create a Proxy Host for an Umbrel app

In Nginx Proxy Manager, go to:

```plaintext
Hosts → Proxy Hosts → Add Proxy Host

```

Using Excalidraw as an example:

```plaintext
Domain Names: excalidraw.example.com
Scheme: http
Forward Hostname / IP: docker-host
Forward Port: 4422

```

Recommended options:

- enable `Block Common Exploits`
- enable `Websockets Support` if the app uses WebSockets

### Why `docker-host`?

The Umbrel version of NPM includes a `docker-host` companion container. It makes the Umbrel host’s ports available to NPM, so the LAN IP does not have to be entered separately for every Proxy Host.

If `docker-host` is unavailable in a different installation, use the Umbrel LAN IP instead:

```plaintext
Forward Hostname / IP: 192.168.178.12

```

## 8. Configure SSL in NPM

In the Proxy Host’s **SSL** tab:

- select the existing wildcard certificate
- enable `Force SSL`
- enable `HTTP/2 Support`
- leave HSTS disabled initially

The certificate must match the requested hostname, for example:

```plaintext
*.example.com

```

A certificate installed only on a server operated by the domain provider is not automatically used by NPM. The certificate must be available in NPM itself.

## 9. Umbrel App Proxy Authentication

umbrelOS 2.0 frequently protects most apps with its own dashboard login. When using a custom domain, this may cause the Umbrel dashboard or login page to appear instead of the app.

Based on my experience, this option must be disabled to access the app directly through NPM.

Internally, this is represented in `settings.yml`, for example:

```yaml
appProxyAuthEnabled: false

```

### Security notice

If Umbrel authentication is disabled and the app has no authentication of its own, every member of the tailnet can access the app.

Only disable authentication if:

- the tailnet contains trusted members only, or
- NPM provides an additional Access List or HTTP authentication, or
- the app has its own secure authentication

## 10. Make the Umbrel dashboard available via a subdomain

Create an additional Proxy Host:

```plaintext
Domain Names: umbrel.example.com
Scheme: http
Forward Hostname / IP: docker-host
Forward Port: 80

```

Recommended options:

- enable `Websockets Support`
- enable `Block Common Exploits`
- select the wildcard certificate
- enable `Force SSL`
- enable `HTTP/2 Support`

The dashboard is then available at:

```plaintext
https://umbrel.example.com

```

## 11. Common problems and solutions

### The Umbrel dashboard appears instead of the app

Possible causes:

1. Umbrel App Proxy Authentication is still enabled.
2. NPM uses the wrong target port.
3. The browser is using a previously cached redirect.
4. The domain uses web forwarding instead of a DNS A record.
5. The request reaches the Umbrel dashboard directly on port 443 instead of reaching NPM.

Diagnostic steps:

```plaintext
http://umbrel.local:<APP-PORT>

```

If the app appears there, the app and its Umbrel port are working.

Then test NPM directly:

```plaintext
https://app.example.com:40443

```

If that works, the problem is the Tailscale forwarder from port 443 to port 40443.

Also test in a private browser window to rule out cached redirects.

### NPM shows “Bad Gateway” or error 502

Check:

- Is the app running?
- Is the port from `umbrel-app.yml` correct?
- Does `http://umbrel.local:<APP-PORT>` work directly?
- Is `docker-host` used as the Forward Host?
- If `docker-host` does not work, try the Umbrel LAN IP.

### Port mapping entered as a custom environment variable

An entry such as:

```yaml
Ports: '8182:4422'

```

is not a Docker port mapping. It only creates an environment variable named `Ports` inside the container.

A real Compose port mapping would use the `ports` key. However, Compose files generated by Umbrel should not be edited manually because changes may be overwritten during updates or restarts.

NPM normally does not require an additional port mapping. The official app port from `umbrel-app.yml` is sufficient.

### Direct access through the tailnet IP no longer works

This is expected after configuring the TCP forwarder:

```plaintext
Tailscale IP:443 → NPM:40443

```

Port 443 on a single IP cannot be used directly by both the dashboard and NPM at the same time. The dashboard should therefore also be configured as a dedicated subdomain in NPM.

### DNS does not work on individual devices

Check:

- The device is connected to Tailscale.
- The DNS A record returns the correct `100.x.y.z` address.
- No conflicting AAAA record exists.
- The router, browser, or DNS resolver does not block private or CGNAT addresses through DNS rebinding protection.
- The DNS cache has been cleared or the TTL has expired.

## 12. Checklist for each additional app

1. Determine the app port from `umbrel-app.yml` or its local app URL.
2. Test the app locally at `http://umbrel.local:<PORT>`.
3. Disable Umbrel App Proxy Authentication if necessary.
4. Create an NPM Proxy Host:

```plaintext
Domain: app.example.com
Scheme: http
Forward Host: docker-host
Forward Port: <APP-PORT>

```

1. Select the wildcard certificate.
2. Enable Force SSL.
3. Enable WebSockets if required.
4. Test from a device connected to the tailnet.
5. Check whether the app has its own authentication.

## 13. Security model

This configuration does not make the apps publicly accessible. However, they are accessible to every device and user whose Tailscale access rules allow access to the Umbrel.

Recommendations:

- restrict Tailscale ACLs or Grants
- remove tailnet members that are no longer needed
- use strong app passwords
- use NPM Access Lists for unprotected apps
- disable Umbrel authentication only when necessary
- do not forward ports 80, 443, 40080, or 40443 on the internet router
- do not enable Tailscale Funnel when private access only is intended
