Secure Remote Ollama Access with Tailscale

Reach your Ollama fleet from anywhere over Tailscale, without exposing a single inference node to the public internet.

The safest simple way to use an Ollama fleet away from home or the office is to expose one Ollama Herd router through a private Tailscale network, not every Ollama node through public port forwarding. Your laptop, automation server, or phone reaches one stable endpoint; Herd continues routing requests to the available machines behind it.

Tailscale encrypts traffic between Tailnet devices. Tailscale Serve can also give the router a private HTTPS name, while Tailnet access controls decide which users or devices may reach it.

Do not use Tailscale Funnel for a private Ollama API. Funnel makes a local service reachable from the broader internet. Use Serve for Tailnet-only access unless you have deliberately added application authentication, rate limiting, and public-gateway controls.

Architecture

Remote laptop / n8n / Open WebUI
             |
             | encrypted Tailnet connection
             v
      Ollama Herd router :11435
         one private endpoint
        /         |         \
       v          v          v
  Ollama node  Ollama node  embedding / MLX node
     LAN or Tailnet-connected fleet

The router is the only address remote clients need. Inference nodes can remain on a trusted LAN, or every node can join the Tailnet for a fully private overlay network.

Choose one of two designs

Design A: Put every fleet machine on Tailscale

Use this when nodes are spread across locations, the LAN is untrusted, or you want one consistent network.

  • Install Tailscale on the router, every node, and every client.
  • Bind the router to its Tailscale IP.
  • Start each node with an explicit Tailnet router URL.
  • Restrict port 11435 with Tailnet access controls.

This design does not depend on mDNS, which normally stays within a local broadcast domain.

Design B: Put only the router on Tailscale

Use this when all inference nodes are already on one trusted LAN.

  • Node agents discover or reach the router over the LAN.
  • Remote clients reach the same router over its Tailscale address or Tailscale Serve URL.
  • The host firewall limits who can reach port 11435.

This is the least disruptive option, but the router still listens on a LAN interface unless you add more specific binding or firewall rules.

Prerequisites

  • A working Ollama Herd fleet
  • Tailscale installed on the router and remote client
  • Tailscale installed on every node for Design A
  • Permission to edit Tailnet access controls when restrictions are required

Verify the local fleet first:

curl -s http://localhost:11435/fleet/status | python3 -m json.tool

Design A: all fleet machines on the Tailnet

Step 1: get the router's Tailscale address

On the router machine:

tailscale ip -4

Example result:

100.96.12.34

Treat that as an example only. Each Tailnet assigns its own stable address.

Step 2: bind Herd to the Tailscale IP

Ollama Herd's default bind address is 0.0.0.0, which listens on every interface. For a Tailnet-only router, bind it to the Tailscale address:

FLEET_HOST=100.96.12.34 herd

For a background service, put the setting in the service environment or Herd environment file rather than a temporary shell.

Verify on the router:

curl -s http://100.96.12.34:11435/api/tags | python3 -m json.tool

Step 3: connect every node directly

On each fleet node:

herd-node --router-url http://100.96.12.34:11435

The traffic is HTTP at the application layer, but it travels inside Tailscale's encrypted network connection.

Check that every node appears:

curl -s http://100.96.12.34:11435/fleet/status | python3 -m json.tool

Step 4: connect a remote client

From another Tailnet device:

curl -i http://100.96.12.34:11435/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama3.2:3b",
    "messages": [{"role": "user", "content": "Reply with remote access working."}],
    "stream": false
  }'

A successful response and an X-Fleet-Node header prove that the remote request reached the router and was handled by a fleet node.

Design B: trusted LAN nodes, Tailnet clients

Run Herd normally on the router:

herd

The default router bind is 0.0.0.0:11435, so the same service can accept node traffic over the LAN and client traffic over Tailscale. Confirm that the operating-system firewall allows only the required LAN and Tailscale sources.

Remote clients can use the router's Tailscale IP:

http://100.96.12.34:11435

The LAN nodes can continue using mDNS or an explicit LAN URL.

This design exposes only one inference API to the Tailnet. Do not separately expose each node's Ollama port unless a specific maintenance workflow requires it.

Add a private HTTPS name with Tailscale Serve

Some clients prefer or require an HTTPS URL. Tailscale Serve proxies a private Tailnet URL to a local backend. Current Tailscale documentation limits HTTP reverse-proxy targets to localhost, so Herd must answer on 127.0.0.1:11435 for this layout.

Herd's default 0.0.0.0:11435 bind includes localhost. Confirm the local path first:

curl -s http://127.0.0.1:11435/api/tags | python3 -m json.tool

Then create the persistent Serve proxy:

tailscale serve --bg http://127.0.0.1:11435

If Design A binds Herd only to its 100.x.x.x Tailscale address, use the direct Tailnet URL instead of Serve, or change the router layout so Herd is also reachable on localhost. Do not silently broaden the bind without reviewing the host firewall and LAN exposure.

Check the assigned URL:

tailscale serve status

It will resemble:

https://ollama-router.example-tailnet.ts.net

Test it from another Tailnet device:

curl -s https://ollama-router.example-tailnet.ts.net/api/tags \
  | python3 -m json.tool

Tailscale Serve requires Tailnet HTTPS support. Tailscale notes that HTTPS certificate names are recorded in public Certificate Transparency logs, even though access to the service remains restricted by the Tailnet. Use a non-sensitive machine name.

Direct Tailnet IP or Serve URL?

Option Advantages Tradeoffs
http://100.x.x.x:11435 Minimal layers, stable address, encrypted by Tailscale Some clients warn because the URL itself is HTTP
https://name.tailnet.ts.net through Serve Browser-friendly HTTPS, MagicDNS name, Tailnet access controls Requires HTTPS setup; certificate hostname is publicly logged

Use the direct IP for service-to-service calls when plain HTTP URLs are accepted. Use Serve when a client insists on HTTPS or a readable private hostname improves operations.

Restrict access with Tailnet grants

Do not assume that every Tailnet member should use the AI router or view its dashboard. Limit the destination ports to the users or devices that need them.

A conceptual grants policy looks like this:

{
  "groups": {
    "group:ai-users": [
      "alice@example.com",
      "bob@example.com"
    ]
  },
  "tagOwners": {
    "tag:ollama-herd": ["autogroup:admin"]
  },
  "grants": [
    {
      "src": ["group:ai-users"],
      "dst": ["tag:ollama-herd"],
      "ip": ["tcp:11435", "tcp:443"]
    }
  ]
}

Tag the router as tag:ollama-herd, adapt the identities and ports, and validate the policy in the Tailscale admin console. When using only Tailscale Serve, port 443 may be sufficient for clients. Keep direct port 11435 only when clients use the raw Tailnet address.

Access controls protect the network path. They do not create per-request application roles inside Herd.

Configure common clients

OpenAI-compatible SDK

from openai import OpenAI

client = OpenAI(
    base_url="https://ollama-router.example-tailnet.ts.net/v1",
    api_key="not-needed",
)

response = client.chat.completions.create(
    model="llama3.2:3b",
    messages=[{"role": "user", "content": "Hello from the road"}],
)

print(response.choices[0].message.content)

Open WebUI

Set its Ollama connection to either:

http://100.96.12.34:11435

or:

https://ollama-router.example-tailnet.ts.net

n8n

Use the same URL as the Base URL in the Ollama credential. If n8n is in Docker, verify that its container can resolve and route to the Tailnet name or IP.

Ollama API client

curl https://ollama-router.example-tailnet.ts.net/api/chat \
  -d '{
    "model": "llama3.2:3b",
    "messages": [{"role": "user", "content": "Hello"}],
    "stream": false
  }'

Security checklist

  • Expose the Herd router, not every Ollama node.
  • Keep the service private to the Tailnet.
  • Use Tailnet grants or access controls for least privilege.
  • Do not use Funnel for a private AI API.
  • Do not enable full request-body debug capture on a shared or untrusted gateway; it records prompts and responses.
  • Protect the dashboard because it reveals node, model, workload, and performance information.
  • Treat a lost or unmanaged client device as a credential risk and remove it from the Tailnet.
  • Use an authenticated reverse proxy when application-level user identity, audit, quotas, or keys are required.
  • Review whether models or tools can perform privileged actions before granting broad remote access.

Troubleshooting

The Tailnet IP works on the router but not remotely

Check:

tailscale status
tailscale ping 100.96.12.34

Then confirm Herd is listening on the Tailscale address and that access controls permit the destination port.

Nodes disappear after binding Herd to the Tailscale IP

Every node must be on Tailscale and must use the explicit Tailnet router URL. LAN mDNS discovery will not automatically cross into an overlay network.

herd-node --router-url http://100.96.12.34:11435

Tailscale Serve returns an error

Confirm Herd works locally:

curl -s http://127.0.0.1:11435/api/tags

Then inspect Serve:

tailscale serve status

Reset and recreate the proxy when the target is wrong:

tailscale serve reset
curl -s http://127.0.0.1:11435/api/tags | python3 -m json.tool
tailscale serve --bg http://127.0.0.1:11435

If the local curl fails because Herd is bound only to a Tailscale IP, keep using the direct http://100.x.x.x:11435 route or revise the bind and firewall policy before enabling Serve.

The HTTPS hostname does not resolve

Confirm MagicDNS and HTTPS support are enabled for the Tailnet and that the client uses Tailscale DNS.

A client connects but model requests fail

The network path is working. Check Herd separately:

curl -s https://ollama-router.example-tailnet.ts.net/fleet/status \
  | python3 -m json.tool

Look for offline nodes, missing models, memory pressure, queue saturation, or a model name that does not exactly match the fleet list.

The dashboard is reachable by too many people

Narrow the Tailnet grant or place an authenticated proxy in front of the dashboard. Network membership is not the same as authorization to view operational data.

Frequently asked questions

Is HTTP over a Tailscale IP encrypted?

Yes. Tailscale encrypts the network connection between Tailnet devices. HTTPS is still useful for client compatibility, service identity, and browser expectations.

Should I set OLLAMA_HOST=0.0.0.0 on every node?

Not for remote client access. Remote clients only need the Herd router. Node agents can proxy or reach their local Ollama instance as designed. Minimize exposed services.

Does Tailscale replace Herd?

No. Tailscale provides private connectivity and identity at the network layer. Herd discovers and routes inference workloads across machines. They are complementary.

Does Herd authenticate individual users?

The core router is designed for a trusted network boundary. Tailnet access controls restrict which devices or users can connect, but application-level roles, API keys, quotas, and per-user authorization require an additional gateway when needed.

Can the fleet span two locations?

Yes, when every participating node can reach the router over Tailscale and node agents use an explicit router URL. Measure WAN latency before placing tightly coupled interactive workloads across distant nodes.

Why not use port forwarding?

Public port forwarding exposes a service that is normally designed for local use and may not have the authentication, rate limiting, and abuse controls expected of a public API. A private overlay network is a safer default.

Related Reading