What if you could leave your AI working while you’re out and about, with no laptop on you and no need to be at home? Sounds like hype, but it isn’t. You can absolutely run OpenCode on a VPS, access it from your phone through a decent web interface, and keep it running 24/7 without paying for some extra mobile app subscription.
And there are two traps I want to save you from right away: using only a terminal on your phone is painful and a tiny VPS runs out of steam fast. I tested it with a 2 GB RAM server and it works for messing around, but the moment you ask it to do several things at once, lag kicks in, CPU usage spikes, and the whole experience stops being pleasant.
So in this post we’re going to do it properly: with a web UI, synced config, no public ports exposed, and the service staying alive even after you close the SSH session.
What we’re building exactly
The idea is very simple:
- OpenCode installed on a VPS so the heavy lifting happens in the cloud.
- OpenCode web UI so you can use it from your phone without suffering through a terminal on a tiny screen.
- Configuration sync between your computer and the server so you don’t have to duplicate settings, models, and plugins.
- Tailscale for private access, without opening ports to the internet.
- systemd so OpenCode keeps running even if you close SSH or reboot the server.
The final result is a private URL like http://your-tailscale-hostname:4096 that only works inside your Tailscale network. Open it in your phone browser and you’re in.
What you need before you start
Before touching anything, get this ready:
- A Linux VPS. If you can, go for 4 GB of RAM or more. With 2 GB it can boot, but I wouldn’t call it a good setup for serious agent work.
- Your main computer with OpenCode already configured, if you want to take advantage of sync.
- A GitHub account for the sync plugin.
- A Tailscale account so your phone and server can join the same private network.
- The Tailscale app on your phone.
If you still don’t have a server, here are two blog posts that fit perfectly here:
Tip: if your budget is tight, cut back on disk before you cut back on RAM. For a comfortable OpenCode setup from your phone, RAM is what will hurt first.
Step 1: Install OpenCode on the VPS
First, install OpenCode on the server.
curl -fsSL https://opencode.ai/install | bash
When it’s done, check where the binary ended up:
which opencode
It should return something like this:
/root/.opencode/bin/opencode
Save that path because we’ll use it later in the systemd service.
Heads up: there was one important detail in the recording. Right after installation,
which opencodedidn’t return the correct path until the SSH session was closed and reopened. If that happens to you, don’t overthink it: reconnect and try again.
If you also want to verify the command responds:
opencode --version
Step 2: Set up config sync
This is one of the most useful parts and one of the least explained. If you already use OpenCode on your computer, it makes no sense to configure models, providers, and preferences from scratch again on the VPS.
The goal is to use the sync plugin so your config lives in a private GitHub repo and you can link it from any machine.
2.1 Install GitHub CLI on the VPS
On Ubuntu or Debian you can do it like this:
sudo apt update
sudo apt install -y gh
Then sign in:
gh auth login
Choose GitHub.com, HTTPS, and whichever auth method you prefer. In the video it’s done with a personal token, which works great if you want to leave the VPS fully ready with access to your repos.
2.2 Enable the sync plugin in OpenCode
On the VPS, create or edit this file:
mkdir -p ~/.config/opencode
nano ~/.config/opencode/opencode.json
Paste this in:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-synced"]
}
Now open OpenCode once so it can generate its files and detect the plugin:
opencode
Exit when it finishes initializing and that’s it.
2.3 Enable the same plugin on your main computer
Do the exact same thing on your main machine: open your global OpenCode file and add the opencode-synced plugin.
If the file doesn’t exist, create it. The structure is the same:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-synced"]
}
2.4 Initialize sync from your main computer
This is where it makes sense to create the private repo, because your main computer is where your good config already lives.
Open OpenCode on your main machine and run the sync command. Depending on your version or plugin, it may show up as a slash command or a normal command. If you type sync in OpenCode, the client itself should suggest the correct name.
Usually you’ll use one of these forms:
/sync-init my-opencode-config
or:
sync init my-opencode-config
That creates a private GitHub repo with your configuration.
Then push the initial changes:
/sync-push
or:
sync push
2.5 Link the VPS to that repo
Now go back to the VPS, open OpenCode, and link the remote configuration:
/sync-link
or:
sync link
If everything goes well, the VPS pulls your config and you don’t have to repeat providers, models, or settings.
Important note: in the transcript you can see the plugin even suggests initializing secrets after linking. Read that carefully before accepting everything blindly. Syncing config makes sense. Syncing secrets and sessions depends a lot on how you work.
Step 3: Install Tailscale and join your private network
Now we get to the critical security piece. No opening ports to the internet to expose OpenCode. What we want is for the service to exist only inside your private network.
Install Tailscale:
curl -fsSL https://tailscale.com/install.sh | sh
And bring it up:
sudo tailscale up
It will give you a URL to sign in. Open it, authenticate, and the server joins your Tailscale network.
On your phone, do the same from the official Tailscale app. Install it on iPhone or Android, sign in with the same account you used on the VPS, and keep the connection active. There’s no trick there, but both devices need to be inside the same private network so the OpenCode web UI can respond later without exposing anything publicly.
Now get the server’s Tailscale hostname:
tailscale status --json 2>/dev/null | grep -o '"DNSName": "[^"]*"' | head -1
It should return something like this:
"DNSName": "my-vps.tailxxxxx.ts.net."
Copy it because we’ll use it in the phone browser in a minute.
Why this matters so much: with Tailscale you’re not exposing port
4096to the public internet. Only authenticated devices inside the same private network can reach OpenCode.
Step 4: Run OpenCode in web mode 24/7
This is where we go from a demo to something genuinely useful. We’re going to run it as a user service with systemd so it stays up even after you close the SSH session.
4.1 Create the user services folder
mkdir -p ~/.config/systemd/user
4.2 Create the service file
nano ~/.config/systemd/user/opencode-web.service
Paste this in and replace the ExecStart path with the one returned by which opencode:
[Unit]
Description=OpenCode Web Server
After=network.target
[Service]
Type=simple
WorkingDirectory=%h
ExecStart=/REAL/PATH/TO/opencode web --port 4096 --hostname 0.0.0.0
Restart=on-failure
RestartSec=5
Environment=PATH=%h/.local/bin:/usr/local/bin:/usr/bin:/bin
[Install]
WantedBy=default.target
Important details:
ExecStarthas to use your real path, not mine and not the example.--port 4096can be changed, but use a free port.--hostname 0.0.0.0is needed so the service is reachable through Tailscale.Restart=on-failuremakes it come back up if it crashes.
4.3 Enable linger for your user
This step is mandatory if you want the service to stay alive after closing SSH:
loginctl enable-linger $USER
Without this, you close the session and Linux kills your user processes. At that point, the whole setup is pointless.
4.4 Reload, enable, and start the service
systemctl --user daemon-reload
systemctl --user enable opencode-web
systemctl --user start opencode-web
4.5 Verify it’s running
systemctl --user status opencode-web
You should see something like:
Active: active (running)
And to make sure the interface actually responds:
curl -s http://localhost:4096/global/health
If everything went well, it should return:
{"healthy":true}
Step 5: Add username and password if you want an extra layer
Tailscale already protects a lot, but if you’re the kind of person who sleeps better with one more lock on the door, you can enable basic auth on the web UI.
Edit the service again:
nano ~/.config/systemd/user/opencode-web.service
Inside [Service], add these lines:
Environment=OPENCODE_SERVER_USERNAME=youruser
Environment=OPENCODE_SERVER_PASSWORD=yourpassword
Then reload and restart:
systemctl --user daemon-reload
systemctl --user restart opencode-web
Next time you open the web UI, it will ask for the username and password.
My take: if your phone is a device you carry around all day, this extra layer makes perfect sense.
Step 6: Access it from your phone
With Tailscale active on your phone, open the browser and go to:
http://YOUR_TAILSCALE_HOSTNAME:4096
For example:
http://my-vps.tailxxxxx.ts.net:4096
And that’s it, you now have the OpenCode web UI on your phone.
If you configured username and password, it will prompt you for them. If not, you’ll go straight in as long as you’re still connected to Tailscale.
The key thing here is this: that URL is not exposed to the world. It only works inside your Tailscale private network, so nobody outside can stumble into it.
Common problems and the stuff nobody tells you
1. A 2 GB RAM VPS can run out of breath
This isn’t theory. If you start throwing several tasks at it or use heavier models, the server chokes. My recommendation is simple: if you want something genuinely useful, go with 4 GB or more.
2. Coding from a phone terminal is torture
Yes, technically you can do it. But the moment you want to review changes, read diffs, or move around files, it becomes miserable. That’s why the web UI is the whole point of this setup.
3. If which opencode returns nothing, reconnect over SSH
It happens sometimes right after installation. Close the session, log back in, and try again.
4. The sync plugin is worth it, but review what you sync
Syncing config is great. Syncing secrets depends on your paranoia level, whether you share machines, and how clean you want each environment to stay.
5. loginctl enable-linger $USER is not optional
If you skip this, you close SSH, the process dies, and you start thinking systemd hates you. It doesn’t. You’re just missing that command.
Why this setup is actually useful
Once this is working, that’s when the interesting part begins. It’s not just the novelty of opening it from your phone. It’s the freedom to request quick changes to a project, review implementations while you’re away, launch a small commit, or even connect MCPs to deploy and inspect environments without always needing your laptop. And if a task takes a while, you just leave it running in the cloud while you do something else.
In the video there’s one example I especially like: connecting a Coolify MCP so you can deploy to a staging environment from your phone and validate whether the change actually works. For longer or more delicate tasks, I still prefer a computer, obviously. But for small changes, follow-up work, or quick validation, this opens up a lot of possibilities.
If you’re not comfortable with MCPs yet, here’s another post from the blog:
All tutorial commands together, ready to copy
Here’s the quick cheat sheet in logical order:
# Install OpenCode
curl -fsSL https://opencode.ai/install | bash
which opencode
opencode --version
# Install GitHub CLI for sync
sudo apt update
sudo apt install -y gh
gh auth login
# Create global OpenCode config with the sync plugin
mkdir -p ~/.config/opencode
nano ~/.config/opencode/opencode.json
opencode
# Install Tailscale
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
tailscale status --json 2>/dev/null | grep -o '"DNSName": "[^"]*"' | head -1
# Create user service for OpenCode Web
mkdir -p ~/.config/systemd/user
nano ~/.config/systemd/user/opencode-web.service
loginctl enable-linger $USER
systemctl --user daemon-reload
systemctl --user enable opencode-web
systemctl --user start opencode-web
systemctl --user status opencode-web
curl -s http://localhost:4096/global/health
# Optional: after adding username/password to the service
systemctl --user daemon-reload
systemctl --user restart opencode-web
And inside OpenCode, depending on the plugin version:
/sync-init my-opencode-config
/sync-push
/sync-link
or:
sync init my-opencode-config
sync push
sync link
Conclusion
Honestly, this is one of those setups that looks like a gimmick at first and then turns out to make a lot of sense. Not because you’re suddenly going to code from the beach like a stock-photo ad, but because it gives you real freedom: you can review things, launch tasks, and keep projects moving without always needing your laptop in front of you.
And if you do it with OpenCode, a decent VPS, Tailscale, and systemd, you end up with a very solid setup: secure, private, synced, and always on.
If you want, I can do a more advanced follow-up post with extra server hardening, firewall rules, SSH keys, and a more serious MCP deployment workflow.



What do you think?
Leave your opinion, question or suggestion. Comments are synced with GitHub Discussions .