Skip to content

Instantly share code, notes, and snippets.

@shawnyeager
Last active January 25, 2026 09:53
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.

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