AIAI Coding AgentsLLMSelf-Hosting

Ollama over Tailscale: Use Your Home GPU from Anywhere, Safely (Linux, Windows, Mac)

Before you start

  • 19 min read

Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#

You keep Ollama and its GPU at home, join both machines to a private Tailscale network, and your laptop talks to the models from anywhere over an encrypted connection, with no port open on the internet.

Ollama official logo

Logo: the official Ollama project (github.com/ollama/ollama, MIT licence)

Ollama has no login of its own. Anyone who can reach port 11434 can use your GPU, pull models and delete them. So the safe design is simple: do not put that port on the internet at all. Tailscale gives each of your devices a private address and a name, and only your signed-in devices can reach it.

If you do not have Ollama yet, install it first with our Ollama guide. This guide starts where that one ends.

At a glance#

  • What you get: https://gpu-box.tailnet-name.ts.net works from your laptop, phone or office PC. Open WebUI, Continue and OpenCode can use it like a local Ollama.
  • Time needed: about 25 minutes.
  • Difficulty: medium. A few settings on the GPU machine, one command to publish HTTPS.
  • You need: a machine with Ollama (ideally with a GPU), a laptop, a free Tailscale account, and admin rights on the GPU machine.
  • Never: open or forward port 11434 on your router. Never use a public tunnel for it.
WhatValue
Ollamav0.40.11, released 24 Oct 2026 (GitHub releases); Docker image ollama/ollama:0.40.11
Tailscalev1.104.2, released 21 Oct 2026 (GitHub releases); Docker image tailscale/tailscale:v1.104.2
Ports11434 (Ollama, tailnet only), 443 (HTTPS from tailscale serve, tailnet only)
CostTailscale personal plan is free for a small tailnet (check current limits on the pricing page)
Official docsOllama FAQ, Tailscale Serve

Why this version? We looked at the Ollama issue tracker for v0.40.11. We found a few narrow open bugs (for example an intermittent chat error on macOS, issue #19293) but no install failures or data-loss reports. So the guide uses the latest release. Your rollback tag is 0.40.10.

How it fits together#

Your app sends an HTTPS request to the GPU machine's Tailscale name, Tailscale checks your access rule, and tailscale serve hands the request to Ollama, which runs the model on the GPU.

How the laptop reaches the GPU box: the app on the laptop sends an HTTPS request to the Tailscale client, which sends it over WireGuard to the tailnet access rule, which allows it to tailscale serve on the GPU box, which proxies it to Ollama on port 11434, which loads the model on the GPU

Three layers protect you, each one enough to stop a stranger:

  1. Tailscale: only devices signed in to your tailnet can even see the machine.
  2. Access rules (grants): inside the tailnet, only the people and devices you name can reach it.
  3. Firewall: the GPU machine itself refuses port 11434 from anything but the tailnet.

Before you start#

You need Ollama working locally on the GPU machine and a Tailscale account.

SystemGPU machineLaptop (client)
LinuxOllama as a systemd service, NVIDIA or AMD driversTailscale client
WindowsOllama app (OllamaSetup.exe), NVIDIA or AMD driversTailscale client
MacOllama app (Apple Silicon uses the built-in GPU)Tailscale client

Check your tools on the GPU machine:

Run in terminalbash
ollama --version
curl http://localhost:11434

Expected: a version line, and the text Ollama is running.

Checklist:

  • [ ] Ollama answers on localhost:11434 on the GPU machine
  • [ ] You can sign in to login.tailscale.com (Google, Microsoft, GitHub or Apple login)
  • [ ] You have admin rights on the GPU machine (sudo, administrator)
  • [ ] You know what you will change (the OLLAMA_HOST setting and one firewall rule)

Tested on 2026-10-26: not run. Commands checked against the official Ollama and Tailscale docs and source at the release tags (see Sources).

Step 1: Put Tailscale on both machines#

Install the Tailscale client on the GPU machine and on the laptop, and sign in to the same account on both.

Linux#

Run in terminalbash
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

Open the link it prints and sign in.

Windows (PowerShell)#

Run in terminalpowershell
winget install --id Tailscale.Tailscale

Start Tailscale from the Start menu and sign in. Open a new PowerShell window afterwards so the tailscale command is found.

Mac (Terminal)#

Install Tailscale from the Mac App Store or from tailscale.com/download, open it and sign in. The command-line tool lives inside the app:

Codebash
/Applications/Tailscale.app/Contents/MacOS/Tailscale status

On the laptop use the installer for its system. Then give the GPU machine a short name, like gpu-box, on the machines page of the admin console (rename it from the three-dot menu).

Check it worked#

On the laptop:

Run in terminalbash
tailscale status
tailscale ping gpu-box

Expected: both machines are listed, and the ping answers pong from gpu-box ....

Potential issue: short names like gpu-box only work when MagicDNS is on. It is on by default for new tailnets. Look at the DNS page if the name does not resolve.

Step 2: Make Ollama listen beyond localhost#

By default Ollama only listens on 127.0.0.1:11434. Set OLLAMA_HOST so it accepts the connections that Tailscale forwards.

There is a second reason to do this. When Ollama listens on loopback only, it rejects requests whose Host name is not local (a check in its source code, allowedHostsMiddleware). tailscale serve passes the original name gpu-box.tailnet-name.ts.net through, so a loopback-only Ollama answers 403 Forbidden. With 0.0.0.0 the check is off. That is why we open the listener here and close the door with a firewall in Step 3.

Linux#

Run in terminalbash
sudo systemctl edit ollama.service

In the editor add these two lines, save and exit:

File contentini
[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"
Run in terminalbash
sudo systemctl daemon-reload
sudo systemctl restart ollama

Windows (PowerShell)#

Quit Ollama from the tray icon first. Then set a user variable and start Ollama again from the Start menu:

Run in terminalpowershell
setx OLLAMA_HOST "0.0.0.0:11434"

Mac (Terminal)#

Run in terminalbash
launchctl setenv OLLAMA_HOST "0.0.0.0:11434"

Then quit the Ollama app and open it again.

Check it worked#

On the GPU machine, find its Tailscale address and ask Ollama through it:

Run in terminalbash
tailscale ip -4
curl http://<TAILSCALE_IP>:11434

Expected: Ollama is running. Right now other devices on your home network can reach it too. Step 3 closes that.

Step 3: Close port 11434 to everything except the tailnet#

Allow port 11434 only from Tailscale and block it from your home network. Tailscale devices use addresses in 100.64.0.0/10.

Linux#

This uses ufw. Order matters: the allow rule comes first.

Run in terminalbash
sudo ufw allow in on tailscale0 to any port 11434 proto tcp
sudo ufw deny 11434/tcp
sudo ufw status numbered

Windows (PowerShell, as administrator)#

Codepowershell
New-NetFirewallRule -DisplayName "Ollama from tailnet only" -Direction Inbound -Protocol TCP -LocalPort 11434 -RemoteAddress 100.64.0.0/10 -Action Allow
New-NetFirewallRule -DisplayName "Ollama block home network" -Direction Inbound -Protocol TCP -LocalPort 11434 -RemoteAddress LocalSubnet -Action Block
Get-NetFirewallRule -DisplayName "*ollama*" | Select-Object DisplayName, Enabled, Action

The Ollama installer may add its own allow rule. A block rule wins over an allow rule in Windows Firewall (VERIFY on your build).

Mac (Terminal)#

The macOS firewall works per app, not per network. Turn it on in System Settings > Network > Firewall and block incoming connections you do not need. A Mac that travels is better as a client; put the GPU on a Linux or Windows machine. VERIFY the firewall behaviour on your macOS version.

Check it worked#

From another device on your home Wi-Fi that is not in the tailnet (or with Tailscale switched off):

Run in terminalbash
curl --max-time 5 http://<LAN_IP_OF_GPU_BOX>:11434

Expected: no answer (timeout). From the laptop with Tailscale on, curl http://gpu-box:11434 still answers Ollama is running.

Step 4: Turn on HTTPS inside the tailnet#

tailscale serve gives Ollama an https:// address with a real certificate that only your tailnet can reach. Plain http over Tailscale is already encrypted by WireGuard, but many apps and browsers want https.

First, in the DNS page, make sure MagicDNS is on and click Enable HTTPS. Read the note: the certificate names of your machines go on a public log, so do not give a machine a name with private words in it. Then, on the GPU machine:

Linux#

Run in terminalbash
sudo tailscale serve --bg 11434
tailscale serve status

Windows (PowerShell)#

Run in terminalpowershell
tailscale serve --bg 11434
tailscale serve status

Mac (Terminal)#

Codebash
/Applications/Tailscale.app/Contents/MacOS/Tailscale serve --bg 11434
/Applications/Tailscale.app/Contents/MacOS/Tailscale serve status

If Serve is not enabled on your tailnet yet, the command prints a link. Open it and approve. The command is described in the tailscale serve reference. --bg keeps it running after you close the terminal.

Check it worked#

From the laptop:

Run in terminalbash
curl https://gpu-box.tailnet-name.ts.net/api/tags

Expected: a JSON list of your models ({"models":[...]}). Your real name is shown under tailscale serve status.

To stop publishing: tailscale serve reset. Do not use tailscale funnel: Funnel publishes to the whole internet, which is exactly what we are avoiding.

Step 5: Limit who inside the tailnet can connect#

By default every device in a personal tailnet can reach every other one. Add a rule so only you reach the GPU machine's HTTPS port.

Open the Access controls page. Tags need an owner, so the policy has a tagOwners part:

File contentjson
{
  "tagOwners": {
    "tag:gpu": ["autogroup:admin"]
  },
  "groups": {
    "group:ai-users": ["[email protected]"]
  },
  "grants": [
    {
      "src": ["group:ai-users"],
      "dst": ["tag:gpu"],
      "ip": ["tcp:443"]
    }
  ]
}

Then, on the machines page, add the tag tag:gpu to the GPU machine. Keep any other grants you already need. Grants are deny-by-default: what no grant allows is blocked. Merge this with your existing policy, do not paste over it, or you can lock yourself out. See the grants reference.

Note: a tagged machine is owned by the tag, not by your user. Check its machine page (key expiry) after tagging.

The policy is edited in the browser, the same on every system. The test commands differ:

Linux#

Run in terminalbash
curl --max-time 5 https://gpu-box.tailnet-name.ts.net/api/tags

Windows (PowerShell)#

Run in terminalpowershell
curl.exe --max-time 5 https://gpu-box.tailnet-name.ts.net/api/tags

Mac (Terminal)#

Same command as Linux.

Check it worked#

From a device of another user (or a test account) the command above should time out. From your own laptop it works.

Step 6: Connect Open WebUI, Continue and OpenCode#

Every client needs one thing: the base address https://gpu-box.tailnet-name.ts.net (no :11434, no path).

ClientSetting
Open WebUIEnvironment OLLAMA_BASE_URL=https://gpu-box.tailnet-name.ts.net, or Admin Settings > Connections > Ollama
ContinueIn config.yaml, a model with provider: ollama and apiBase: https://gpu-box.tailnet-name.ts.net
OpenCodeIn opencode.json, an OpenAI-compatible provider with baseURL: https://gpu-box.tailnet-name.ts.net/v1
Ollama CLI on the laptopSet OLLAMA_HOST=https://gpu-box.tailnet-name.ts.net (VERIFY: the CLI accepts a full URL)

Continue example:

File contentyaml
models:
  - name: Remote Llama
    provider: ollama
    model: llama3.2
    apiBase: https://gpu-box.tailnet-name.ts.net

OpenCode example (VERIFY the field names against your OpenCode version):

File contentjson
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "ollama-remote": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Ollama (home GPU)",
      "options": { "baseURL": "https://gpu-box.tailnet-name.ts.net/v1" },
      "models": { "llama3.2": { "name": "Llama 3.2" } }
    }
  }
}

Open WebUI on the laptop, in Docker, pointing at the remote Ollama. The laptop must be signed in to Tailscale.

Linux#

Run in terminalbash
mkdir -p ~/docker_volumes/open-webui-remote/data && cd ~/docker_volumes/open-webui-remote

Windows (PowerShell)#

Codepowershell
New-Item -ItemType Directory -Force "$HOME\docker_volumes\open-webui-remote\data" | Out-Null
Set-Location "$HOME\docker_volumes\open-webui-remote"

Mac (Terminal)#

Same commands as Linux.

Save this as docker-compose.yml and start it with docker compose up -d. Pin the image to a release tag as in our Open WebUI guides before you rely on it.

File contentyaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui-remote
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:8080"
    environment:
      OLLAMA_BASE_URL: https://gpu-box.tailnet-name.ts.net
    volumes:
      - ./data:/app/backend/data

Check it worked#

Open http://localhost:3000. The model list shows the models from the GPU machine. In a terminal, curl https://gpu-box.tailnet-name.ts.net/api/tags lists them as well. If the container cannot resolve the tailnet name, see Troubleshooting.

Option: Ollama and Tailscale together in Docker (sidecar)#

If Ollama runs in Docker, run Tailscale as a sidecar container and publish no port at all. Ollama shares the Tailscale container's network, so it only exists inside the tailnet. This also avoids the Docker habit of bypassing ufw rules with published ports.

Linux#

Run in terminalbash
mkdir -p ~/docker_volumes/ollama-ts/{ollama_data,ts_state,ts_config}
cd ~/docker_volumes/ollama-ts

Windows (PowerShell)#

Codepowershell
$d = "$HOME\docker_volumes\ollama-ts"
"ollama_data","ts_state","ts_config" | ForEach-Object { New-Item -ItemType Directory -Force "$d\$_" | Out-Null }
Set-Location $d

Mac (Terminal)#

Docker on a Mac cannot use the GPU, so on a Mac use the native app and Steps 1 to 6. For a CPU-only test use the Linux commands.

Create an auth key on the Keys page (one-use, tag tag:gpu) and keep it in .env:

Run in terminalbash
echo "TS_AUTHKEY=<YOUR_AUTH_KEY>" > .env
chmod 600 .env

On Windows, create .env with the same line in Notepad. Then save ts_config/serve.json (the container fills in ${TS_CERT_DOMAIN} itself):

File contentjson
{
  "TCP": { "443": { "HTTPS": true } },
  "Web": {
    "${TS_CERT_DOMAIN}:443": {
      "Handlers": { "/": { "Proxy": "http://127.0.0.1:11434" } }
    }
  }
}

And docker-compose.yml:

File contentyaml
services:
  tailscale:
    image: tailscale/tailscale:v1.104.2
    container_name: ts-ollama
    hostname: gpu-box
    restart: unless-stopped
    environment:
      TS_AUTHKEY: ${TS_AUTHKEY}
      TS_EXTRA_ARGS: --advertise-tags=tag:gpu
      TS_STATE_DIR: /var/lib/tailscale
      TS_SERVE_CONFIG: /config/serve.json
    volumes:
      - ./ts_state:/var/lib/tailscale
      - ./ts_config:/config

  ollama:
    image: ollama/ollama:0.40.11
    container_name: ollama
    restart: unless-stopped
    network_mode: service:tailscale
    depends_on:
      - tailscale
    environment:
      OLLAMA_HOST: 0.0.0.0:11434
    volumes:
      - ./ollama_data:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

The deploy block is for NVIDIA with the NVIDIA Container Toolkit installed (see the Ollama Docker docs). For AMD use the ollama/ollama:0.40.11-rocm image and the /dev/kfd and /dev/dri devices instead. Remove the block to run on the CPU.

Run in terminalbash
docker compose up -d
docker exec ollama ollama pull llama3.2

Check it worked#

Run in terminalbash
docker compose ps
docker logs ts-ollama --tail 20

Expected: both containers running, and gpu-box appears in your Tailscale machines list. From the laptop curl https://gpu-box.tailnet-name.ts.net/api/tags answers. No port is published, so nothing on your home network can reach Ollama.

Put it behind HTTPS (with or without Traefik)#

The route above, tailscale serve, is the one we recommend: no domain, no ports, no certificates to renew. This section is for people who also front Ollama on their home network with a proxy (for example to give the whole house one address). Ollama has no login, so a proxy for Ollama must add one, and must stay on your private network, never the internet.

With Traefik#

Use this when Traefik already runs on a server you control and the name resolves only inside your network. Ollama runs in Docker on the external proxy network. The labels are our example, not from the official docs (VERIFY against your Traefik setup):

Run in terminalbash
docker network create proxy
File contentyaml
  ollama:
    image: ollama/ollama:0.40.11
    container_name: ollama
    restart: unless-stopped
    volumes:
      - ./ollama_data:/root/.ollama
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.docker.network=proxy
      - traefik.http.routers.ollama.rule=Host(`ollama.home.example`)
      - traefik.http.routers.ollama.entrypoints=https
      - traefik.http.routers.ollama.tls=true
      - traefik.http.routers.ollama.middlewares=ollama-auth
      - traefik.http.middlewares.ollama-auth.basicauth.users=${OLLAMA_BASIC_AUTH}
      - traefik.http.services.ollama.loadbalancer.server.port=11434

networks:
  proxy:
    external: true

Create the user and hash once with htpasswd -nb you '<A_LONG_PASSWORD>'. In a .env file double every $ in the hash ($$). Do not add a ports: entry for Ollama.

Without Traefik: Caddy#

Choose Caddy if you have no Traefik yet and run one small server.

CaseResultYou do
Public domainAutomatic Let's EncryptDNS A record to the server, ports 80 and 443 open (not recommended for Ollama)
Home onlytls internal (local certificate)Trust Caddy's root certificate on each device

For a home network use the home-only Caddyfile. It asks for a password and tells Ollama the request comes from localhost, as the Ollama FAQ suggests for proxies. Get the password hash with caddy hash-password.

File contenttext
ollama.home.arpa {
    tls internal
    basic_auth {
        you <PASTE_THE_HASH_HERE>
    }
    reverse_proxy localhost:11434 {
        header_up Host localhost:11434
    }
}

Public domain variant, for reference only (do not do this for Ollama without a password and a good reason):

File contenttext
ollama.example.com {
    basic_auth {
        you <PASTE_THE_HASH_HERE>
    }
    reverse_proxy localhost:11434
}

Trust the root certificate (pki/authorities/local/root.crt in Caddy's data directory):

Run in terminalbash
# Linux: on the Caddy machine
sudo caddy trust
# other Linux devices, with root.crt copied over
sudo cp root.crt /usr/local/share/ca-certificates/caddy-root.crt && sudo update-ca-certificates
# Windows (PowerShell as administrator)
certutil -addstore -f ROOT root.crt
# Mac
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain root.crt

Run Caddy (Linux: install from the official apt repository on caddyserver.com/docs/install first):

Run in terminalbash
# Linux
sudo systemctl reload caddy
# Windows (PowerShell)
winget install CaddyServer.Caddy
caddy run
# Mac
brew install caddy && caddy run

Or with Docker, save this in ~/docker_volumes/caddy next to the Caddyfile (use reverse_proxy ollama:11434 when Ollama is on the same Docker network):

File contentyaml
services:
  caddy:
    image: caddy:2.11.7
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./caddy_data:/data
      - ./caddy_config:/config

Check it worked: curl -I -u you https://ollama.home.arpa answers HTTP/2 200 after you enter the password. Streaming answers (the model typing word by word) work through Caddy by default.

Why not open port 11434 to the internet?#

Because Ollama has no login, and open Ollama ports get found by scanners. Anyone who finds yours can burn your GPU, read your model list and delete models. A router port forward, a published Docker port (-p 11434:11434 writes its own firewall rules and bypasses ufw), or a public tunnel all create that exposure. Tailscale keeps the port private and needs no router change at all.

Security and testing#

Keep the keys private, keep the port tailnet-only and test from outside.

  • Auth keys in .env, mode 600. Use one-use or expiring keys, with a tag. Delete a key in the admin console if it leaks.
  • Do not use Funnel for Ollama. Check tailscale serve status shows no Funnel line.
  • Docker ports: publish nothing for Ollama, or bind to loopback (127.0.0.1:11434:11434).
  • Device approval and key expiry: turn them on in the admin console if other people share your tailnet.
  • Browsers: Ollama allows browser calls only from local origins by default. If a web app on another name must call it, set OLLAMA_ORIGINS to that exact address. Never use *.

Tests:

Run in terminalbash
tailscale status
tailscale serve status
curl -I https://gpu-box.tailnet-name.ts.net/api/tags

Expected: both devices connected, the Serve line marked as tailnet only, and HTTP/2 200. Then run the outside test from Step 3 again.

Troubleshooting#

ProblemSolution
403 Forbidden from the ts.net nameOllama listens on loopback only. Set OLLAMA_HOST=0.0.0.0:11434 (Step 2) and restart Ollama
curl: (7) Failed to connect on :11434Ollama is not running, or a firewall blocks the tailnet. Check systemctl status ollama and the firewall rule
could not resolve host: gpu-boxMagicDNS is off or the laptop is not signed in. Run tailscale status and check the DNS page
Error: could not connect to ollama server, run 'ollama serve' to start itThe CLI points at the wrong address. Check OLLAMA_HOST on that machine
Serve is not enabled on your tailnetOpen the link the command prints and approve Serve (VERIFY exact wording)
HTTPS certificate warningEnable HTTPS on the DNS page and use the full ...ts.net name, not the short name
Open WebUI shows no modelsThe container cannot reach the tailnet name. Test curl on the same machine, or run Tailscale as a sidecar for it
Works at home, not awayCheck tailscale status on the laptop and try tailscale ping gpu-box
Nobody can connect after a policy changeA grant is missing. Restore the previous policy from its history on the Access controls page

Windows: the setting seems ignored#

If OLLAMA_HOST seems to be ignored on Windows, quit Ollama from the tray and start it again. A running app does not read changed variables. Check the value with:

File contentpowershell
[Environment]::GetEnvironmentVariable("OLLAMA_HOST","User")

Known bugs#

Open on GitHub at the time of writing (read 2026-10-26):

  • ollama #19293: /api/chat sometimes fails with a 500 right after a long reply (macOS, 0.40.8 and 0.40.11). Retry the request.
  • ollama #19276: one report of Ollama not working after a fresh install. We did not see others confirm it.
  • If 0.40.11 misbehaves for you, roll back to 0.40.10 (Docker tag, or OLLAMA_VERSION=0.40.10 with the Linux install script).

Updates and backups#

Update Ollama and Tailscale like any other app, and back up your Tailscale state and your model list.

Native installs: Ollama updates itself on Windows and Mac; on Linux run curl -fsSL https://ollama.com/install.sh | sh again. Tailscale updates through your package manager, winget or the app.

Docker sidecar: change both image tags, then:

Run in terminalbash
cd ~/docker_volumes/ollama-ts
docker compose pull && docker compose up -d

Backup script (Linux/Mac). The state folder keeps the machine's identity, so you can come back without a new login. Models are big and can be pulled again, so save the model list instead of the files:

Run in terminalbash
cd ~/docker_volumes/ollama-ts
mkdir -p backups
docker exec ollama ollama list > backups/models-$(date +%F).txt
tar czf backups/ts-state-$(date +%F).tgz ts_state ts_config docker-compose.yml

Keep .env out of shared backups. Schedule: cron at 03:00 (0 3 * * * <path-to-script>). Windows: Task Scheduler running the same steps in PowerShell with Compress-Archive.

Restore test#

Do this once, before you need it:

Run in terminalbash
mkdir -p /tmp/restore && tar xzf ~/docker_volumes/ollama-ts/backups/ts-state-*.tgz -C /tmp/restore
ls /tmp/restore/ts_state

You should see the Tailscale state files. If the machine is ever lost, restore the folders, add .env, run docker compose up -d, then pull the models listed in the models-*.txt file. Clean up with rm -rf /tmp/restore.

Performance and resources#

Tailscale adds little to each request; the GPU and the model decide the speed. We did not measure numbers ourselves.

  • Latency: the first token takes a little longer away from home because of the network round trip. Streaming hides most of it.
  • Direct or relayed: tailscale status shows whether the laptop talks to the GPU box directly or through a relay. A direct path is faster.
  • Keep models loaded: set OLLAMA_KEEP_ALIVE on the GPU machine so the next request does not wait for a reload.
  • Fit in VRAM: a model that fits in GPU memory is much faster than one that spills to the CPU. ollama ps shows how a loaded model is split.
  • Watch it:
Run in terminalbash
docker stats --no-stream ollama ts-ollama
nvidia-smi

FAQ#

Do I need a paid Tailscale plan? The free personal plan is enough for this. Check the current limits on the Tailscale pricing page.

Can my phone use it too? Yes. Install Tailscale on the phone, sign in, and any app that takes an Ollama address can use the https:// name.

Why does the guide use 0.0.0.0 if the goal is a private port? Because tailscale serve forwards the original host name and Ollama refuses that on loopback. 0.0.0.0 plus the firewall rule is the combination that works. In the sidecar setup nothing outside the tailnet can reach the container at all.

Can I use a public tunnel instead? We do not recommend it. A public address needs its own login and protection in front of Ollama. A private tailnet needs none of that.

What if my GPU machine sleeps? It disappears from the tailnet. Turn off sleep on the GPU machine, or wake it with Wake-on-LAN from another always-on device.

Does this also work for LM Studio or llama.cpp? The Tailscale parts are the same. The listen setting and the Host check are Ollama specific.

Sources#

Checked against the official docs and source on 2026-10-26. Not run by DIY Lab Hub. Items marked VERIFY are not confirmed in the official docs.