{"id":24950,"date":"2026-10-03T10:56:46","date_gmt":"2026-10-03T14:56:46","guid":{"rendered":"https:\/\/nuxx.net\/blog\/?p=24950"},"modified":"2026-10-03T10:56:46","modified_gmt":"2026-10-03T14:56:46","slug":"clanker-home-nuxx-net","status":"publish","type":"post","link":"https:\/\/nuxx.net\/blog\/2026\/10\/03\/clanker-home-nuxx-net\/","title":{"rendered":"clanker.home.nuxx.net"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/10\/Screenshot-2026-10-03-at-10.50.11-AM-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"550\" src=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/10\/Screenshot-2026-10-03-at-10.50.11-AM-1-1024x550.png\" alt=\"\" class=\"wp-image-24954\" srcset=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/10\/Screenshot-2026-10-03-at-10.50.11-AM-1-1024x550.png 1024w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/10\/Screenshot-2026-10-03-at-10.50.11-AM-1-300x161.png 300w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/10\/Screenshot-2026-10-03-at-10.50.11-AM-1-768x413.png 768w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/10\/Screenshot-2026-10-03-at-10.50.11-AM-1-1536x826.png 1536w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/10\/Screenshot-2026-10-03-at-10.50.11-AM-1-2048x1101.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Running Claude Code on a remote machine via ssh.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Due to still-unresolved feelings of how-much-of-this-work-is-really-mine when using AI tools, I&#8217;m trying to make it as obvious as possible when I use them, and give away as much of the output as possible. I also like what I get out of the tools, but I don&#8217;t trust the tools themselves.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As Apple is beginning to allude to (or&#8230; perhaps outright states) with their <a href=\"https:\/\/developer.apple.com\/news\/?id=p6zjojqw\">Updates to Full Disk Access in macOS<\/a> article, AI tools with unbounded access on end user devices are becoming a problem. And no, in-model guardrails (eg: prompts not to touch certain files) are not sufficient; the model can&#8217;t really constrain the model. So, other layers below &#8212; like in the OS  &#8212; are needed to restrict access and maintain control and boundaries.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I&#8217;ve taken a little bit different approach to this: a separate computer. I took an old computer, dropped a simple Ubuntu install on it, disabled the GUI, and I <a href=\"https:\/\/en.wikipedia.org\/wiki\/Secure_Shell\">ssh<\/a> into it to run <a href=\"https:\/\/claude.com\/product\/claude-code\">Claude Code<\/a> (or other AI tools) under <a href=\"https:\/\/github.com\/tmux\/tmux\/wiki\">tmux<\/a>. While it does have an ssh key for accessing one specific server (as part of the <a href=\"https:\/\/trailmaps.app\">trailmaps.app<\/a> work I&#8217;m using it for), it can&#8217;t get anywhere else; access to it is essentially a one-way door.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is all very intentional, because then it doesn&#8217;t have direct\/implied access to anything else. Sure, it could &#8220;hack&#8221; it&#8217;s way into other things, but for now this feels like a sufficient guardrail. I can (and do) turn it off when I&#8217;m not using it as well. It gets backed up periodically (via <a href=\"https:\/\/nuxx.net\/blog\/2022\/11\/28\/borgbackup-repository-on-dsm-7-0\/\" data-type=\"post\" data-id=\"19556\">borg to my NAS)<\/a> so I should even be able to wipe it and restore things, should I lose confidence in the installed OS.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lots and lots of the web development tools I&#8217;ve been using can run headless on it, automatically, but every once in a while it&#8217;s nice to give it access to something else via an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Model_Context_Protocol\">MCP server<\/a>. This is easy, and can also be controlled, by giving the agent a path to the MCP via a very controlled SSH tunnel.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, for the <a href=\"https:\/\/webkit.org\/blog\/18136\/introducing-the-safari-mcp-server-for-web-developers\/\">Safari MCP server<\/a> I have a script that I run on my Mac which uses <code>socat<\/code> to run <code>safaridriver<\/code> locally then plumbs it through a specific port via an SSH tunnel to <code>clanker<\/code>. The result is that Claude Code can then access the MCP via a local TCP port, which in turn can drive a real copy of Safari on a remote machine.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nice and isolated, while still giving access to useful tools but only as I set up the tunnel. I just have to plumb them through one at a time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For now, at least, this works well for me.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/sh\n# safari-mcp-tunnel \u2014 serve Safari's MCP server to a remote Claude Code.\n#\n# Usage:\n#   safari-mcp-tunnel            start the listener and open the SSH tunnel\n#   safari-mcp-tunnel --serve    (internal) run safaridriver --mcp on stdio\n#\n# On the remote host, register the client end once with:\n#   claude mcp add safari -s user -- socat STDIO TCP:127.0.0.1:7391\n\nset -eu\n\nPORT=7391\nREMOTE=username@remoteserver.local\nSAFARIDRIVER=\/usr\/bin\/safaridriver\n\n# --- child mode: this is what socat execs for each connection ---------------\nif &#91; \"${1:-}\" = \"--serve\" ]; then\n    exec \"$SAFARIDRIVER\" --mcp\nfi\n\n# --- parent mode ------------------------------------------------------------\n# socat needs an absolute path to re-invoke this script, since $0 may be a\n# bare name when we were found on PATH.\nSELF=$(cd \"$(dirname \"$0\")\" &amp;&amp; pwd)\/$(basename \"$0\")\n\n&#91; -x \"$SAFARIDRIVER\" ] || { echo \"no safaridriver at $SAFARIDRIVER\" >&amp;2; exit 1; }\ncommand -v socat >\/dev\/null || { echo \"socat not installed\" >&amp;2; exit 1; }\n\n# ,pipes is load-bearing: the default socketpair has an 8K buffer on macOS and\n# silently truncates large tool responses like get_page_content.\nsocat TCP-LISTEN:$PORT,bind=127.0.0.1,reuseaddr,fork \"EXEC:$SELF --serve,pipes\" &amp;\nSOCAT=$!\ntrap 'kill $SOCAT 2>\/dev\/null || true' EXIT INT TERM\n\n# Wait for the listener before handing the port to ssh.\nwhile ! nc -z 127.0.0.1 $PORT 2>\/dev\/null; do\n    kill -0 $SOCAT 2>\/dev\/null || { echo \"socat failed to start\" >&amp;2; exit 1; }\n    sleep 0.2\ndone\n\n# ExitOnForwardFailure catches a stale binding on the remote end, which would\n# otherwise leave the MCP server looking connected but dead.\nssh -o ExitOnForwardFailure=yes -R $PORT:127.0.0.1:$PORT \"$REMOTE\"<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Due to still-unresolved feelings of how-much-of-this-work-is-really-mine when using AI tools, I&#8217;m trying to make it as obvious as possible when I use them, and give away as much of the output as possible. I also like what I get out of the tools, but I don&#8217;t trust the tools themselves. As Apple is beginning to\u2026<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[],"class_list":["post-24950","post","type-post","status-publish","format-standard","hentry","category-computers"],"_links":{"self":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts\/24950","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/comments?post=24950"}],"version-history":[{"count":1,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts\/24950\/revisions"}],"predecessor-version":[{"id":24955,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts\/24950\/revisions\/24955"}],"wp:attachment":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/media?parent=24950"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/categories?post=24950"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/tags?post=24950"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}