Skip to content

Instantly share code, notes, and snippets.

@shawnyeager
Last active July 9, 2026 08:24
Show Gist options
  • Select an option

  • Save shawnyeager/752ce43e4f8d97f55cd9db397544873f to your computer and use it in GitHub Desktop.

Select an option

Save shawnyeager/752ce43e4f8d97f55cd9db397544873f to your computer and use it in GitHub Desktop.
Run OpenCode as a persistent systemd service with Tailscale access

OpenCode Web Server Setup

Run OpenCode as a persistent background service, accessible from any device via Tailscale.

Why?

  • Access from anywhere — Start a task from your phone, check results from your laptop
  • Sessions persist — Close the browser, come back later, your session is still there
  • Multiple clients — Terminal TUI and browser can connect to the same session simultaneously
  • Survives crashes — systemd restarts the server automatically

Prerequisites

  • Linux with systemd (always-on laptop, home server, VPS, etc.)
  • OpenCode installed and authenticated
  • Tailscale connected to your tailnet

Overview

Phone (via Tailscale)  ───────────┐
                                  │
Laptop terminal (opencode attach) ├──▶  opencode web (:4096)  ──▶  LLM
                                  │         (systemd)
Browser (local network)  ─────────┘

Resource usage: ~330MB RAM idle, negligible CPU.

Quick Reference

Task Command
Attach from terminal opencode attach http://localhost:4096
Access remotely http://[machine].[tailnet].ts.net:4096
Check service status systemctl --user status opencode-web
View logs journalctl --user -u opencode-web -f
Restart service systemctl --user restart opencode-web
Stop service systemctl --user stop opencode-web

Setup

1. Find your OpenCode path

which opencode

2. Create systemd user service

mkdir -p ~/.config/systemd/user

Create ~/.config/systemd/user/opencode-web.service:

[Unit]
Description=OpenCode Web Server
After=network.target

[Service]
Type=simple
WorkingDirectory=%h
ExecStart=/path/to/opencode web --port 4096 --hostname 0.0.0.0
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target

Replace /path/to/opencode with the output from step 1.

Note: WorkingDirectory=%h starts in your home directory. Change this to a specific project path if needed.

Port: 4096 is arbitrary — use any available port.

3. Enable lingering (keeps service running after logout)

loginctl enable-linger $USER

4. Enable and start

systemctl --user daemon-reload
systemctl --user enable opencode-web
systemctl --user start opencode-web

5. Verify

curl http://localhost:4096/global/health

Should return: {"healthy":true,"version":"x.x.x"}

Usage

From terminal

opencode attach http://localhost:4096

Full TUI experience, same session as web. Detach with Ctrl+C.

From phone/browser

Open http://[your-tailscale-hostname]:4096

serve vs web

Command Web UI Use case
opencode serve API only Terminal-first via attach
opencode web Full browser UI Phone/tablet friendly

Use web if you want browser access.

Upgrades

After upgrading OpenCode, restart the service to use the new version:

systemctl --user restart opencode-web

The running service continues using the old binary until restarted.

Troubleshooting

Service won't start (exit code 203)

Wrong executable path:

which opencode
journalctl --user -u opencode-web -n 20

Port already in use

lsof -i :4096
pkill -f "opencode web"
systemctl --user restart opencode-web

Can't connect via Tailscale

  1. Verify Tailscale is running: tailscale status
  2. Check firewall isn't blocking the port
  3. Verify --hostname 0.0.0.0 is set

Optional: Password Protection

Add to the [Service] section:

Environment=OPENCODE_SERVER_USERNAME=your-username
Environment=OPENCODE_SERVER_PASSWORD=your-password

Username defaults to opencode if not set.

With Tailscale, usually unnecessary — your tailnet is already private.

@pdjohntony

Copy link
Copy Markdown

Thanks for this. FYI after doing this opencode couldn't run apps installed in my local user bin, like uv and prek, so I had to add that the service config.

Environment=PATH=/home/USER/.local/bin:/usr/local/bin:/usr/bin:/bin

@festoney8

Copy link
Copy Markdown

Same as what above said, if you're using MCP such as uvx or gopls tool, you need to set Environment or EnvironmentFile (making sure the value includes the important paths from your $PATH).
Or you'll run into "Method not found" issues such as the following opencode log:

ERROR 2026-05-27T15:21:47 +327ms service=mcp clientName=context7 error=MCP error -32601: Method not found failed to get prompts
ERROR 2026-05-27T15:21:47 +60ms service=mcp clientName=gh_grep error=MCP error -32601: Method not found failed to get prompts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment