<!DOCTYPE HTML>
<html>
<head>
<title>plan9 - mounting-9p over drawterm</title>
<style media="screen, handheld">
body { display: flex; flex-wrap: wrap; font-family: sans;}
header { flex-basis: 100%; flex-shrink: 0; }
article { flex-basis: 60%; padding-left: 1em; }
footer { flex-basis: 100%; flex-shrink: 0; }
header nav { display: flex; justify-content: space-between; }
nav a, header a { text-decoration: none ; color: inherit; }
header h1 span { margin-left: 1em; font-size: 50%; font-style: italic; }
.mainContent > nav { flex-basis: content; padding-right: 1vw; min-width: 16em; }
nav ul { display: flex; flex-direction: column; list-style-type: none; list-style-position: outside; padding-left: 0; }
nav li ul { padding-left: 0.6em }
footer { display: flex; justify-content: space-between; }
/* cut here to leave vanity behind */
body { margin:0; padding: 0; font-size: 84%; font-family: Helvetica, Verdana, Arial, 'Liberation Sans', FreeSans, sans-serif; }
a { text-decoration: none; color: }
a:hover { text-decoration: underline; }
.thisPage { color: black; }
/* header and top bar */
header nav { background-color: rgb(100,135,220); color: white; padding: 0.3em; border-bottom: 2px solid black; font-size: 91%; }
header h1 { background-color: #ff6d06; color: black; margin: 0; border-bottom: 2px solid black; font-weight: normal; padding: 0.25ex; font-size: 233%; }
header a:hover { text-decoration: none; }
/* sidebar */
.mainContent > nav { border-right: 1px solid #ddd; padding: 0; }
.mainContent > nav > div { border-bottom: 1px solid #ddd; }
.mainContent > nav > div a { color: rgb(0, 102, 204); display: block; text-transform: capitalize; font-weight: bold; padding: 0.25em 1ex 0.25em 2mm; font-size: 102%}
.mainContent > nav > div a:hover { color: white; background-color: rgb(100,135,220); border-left: black solid 0.2em; text-decoration: none; }
.mainContent > nav > div p { font-weight: bold; margin: 0 0 0.5em 2mm; padding: 1em 0 0 0; }
/* main copy */
article { padding: 0.5ex 0 5vh 1vw; }
article h1, article h2 { color: rgb(0,102,204); font-weight: bold; margin: 2em 0 0 0; border-bottom: 2px solid rgb(0,102,204); }
article h3, article h4, article h5 { color: rgb(0,102,204); font-weight: bold; margin: 2em 0 0 0; }
article h6, article h7, article h8 { color: rgb(0,102,204); font-weight: bold; margin: 2em 0 0 0; }
article a { color: rgb(0,102,204); }
article a:hover { color: rgb(100,135,220); }
article pre { font-size: 1.2em; }
/* footer */
footer { color: white; background-color: rgb(100,135,220); }
footer a { color: inherit; }
footer div { padding: 1em; }
/* tables */
table { border: 1px solid rgba(128,128,128,0.5); padding: 0; }
th { color: white; background-color: rgb(100,135,220); }
tr:nth-child(odd) { background-color: rgba(128,128,128,0.1) }
/* modifications */
img {
max-width: 100%;
border: 1px solid black;
}
body {
}
header h1 {
background-color: #c2d2c6;
}
html {
font-size: 1.2em;
}
header nav, footer {
background-color: #442a13;
}
code > pre {
border: 2px solid #442a13;
background-color: #c2d2c6;
width: max-content;
padding: 0 0.5em;
}
.mainContent > nav > div a, article a:hover {
color: #442a13;
}
.mainContent > nav > div a:hover {
color: #442a13;
background-color: #c2d2c6;
}
article h1, article h2 {
color: #c48f3b;
border-bottom: 2px solid #442a13;
}
article a, .thisPage, footer, header nav {
color: #c48f3b;
}
footer {
padding: 0.5em;
flex-shrink: 1;
flex-basis: unset;
}
header {
flex-basis: unset;
}
html {
display: flex;
min-height: 100%;
}
body {
flex-direction: column;
flex: 1;
background-color: #e3dfd7;
}
.mainContent {
display: flex;
flex-grow: 1;
} </style>
<link rel="shortcut icon" href="https://images.pmikkelsen.com/favicon.ico" type="image/vnd.microsoft.icon">
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<header>
<nav>
<div class="left">
<a href="https://pmikkelsen.com">notes</a> |
<a href="https://git.pmikkelsen.com">git</a> |
<a href="https://images.pmikkelsen.com">images</a> |
<a href="https://files.pmikkelsen.com">files</a> |
<a href="https://prolog.pmikkelsen.com">PProlog</a> |
<a href="https://apl.pmikkelsen.com">APL9</a> |
<a href="https://aplwc.org">aplwc</a>
</div>
<div class="right">
<a href="https://git.sr.ht/~pmikkelsen">sourcehut</a> |
<a href="https://9front.org">9front</a> |
<a href="https://openbsd.org">OpenBSD</a> |
<a href="https://dyalog.com">Dyalog</a>
</div>
</nav>
<h1><a href="../index.html">Peter's website <span id="headerSubTitle">- random notes</span></a></h1>
</header>
<div class=mainContent>
<nav id="side-bar">
<div>
<ul>
<li><a href="../APL-and-J/index.html">› APL and J/</a></li>
<li><a href="../OpenBSD/index.html">› OpenBSD/</a></li>
<li><a href="../contact.html">› contact</a></li>
<li><a href="../facts/index.html">› facts/</a></li>
<li><a href="../haskell/index.html">› haskell/</a></li>
<li><a href="../linux/index.html">› linux/</a></li>
<li><a href="../mainframe/index.html">› mainframe/</a></li>
<li><a href="../me/index.html">› me/</a></li>
<li><a href="../opinions/index.html">› opinions/</a></li>
<li><a href="index.html" class="thisPage">»<i> plan9/</i></a></li>
<li><ul>
<li><a href="basic_9p_server.html">› basic 9p server</a></li>
<li><a href="discord.html">› discord</a></li>
<li><a href="dns.html">› dns</a></li>
<li><a href="fonts.html">› fonts</a></li>
<li><a href="lets_encrypt.html">› lets encrypt</a></li>
<li><a href="mounting-9p-over-drawterm.html" class="thisPage">»<i> mounting 9p over drawterm</i></a></li>
<li><a href="network_booting.html">› network booting</a></li>
<li><a href="trellofs.html">› trellofs</a></li>
<li><a href="using_irc.html">› using irc</a></li>
<li><a href="webfs-websocket.html">› webfs websocket</a></li>
</ul></li>
<li><a href="../prolog/index.html">› prolog/</a></li>
<li><a href="../web/index.html">› web/</a></li>
</ul>
</div>
</nav>
<article>
<h1>Mounting a 9P connection over drawterm</h1>
<p>I sometimes use drawterm on linux to connect to my 9front server. While it is possible to access the host system's files under <code>/mnt/term</code>, there is no builtin way to access the remote system's file under linux. Now, why would anybody want to do this? In my case, I often want to write some code under 9front, but for languages which aren't supported such as prolog in this case, so there are three options as I see it:</p>
<ul>
<li>
Store the files on the host machine, and access them under <code>/mnt/term</code>.
</li><li>
Store the files on the server and somehow mount the server's filesystem on the host.
</li><li>
Store the files on a third machine that both the host and server can access.
</li>
</ul>
<p>Option number two seems best for me, so I asked around and it seems like the best tool to mount a 9P connection on linux is <a href="https://github.com/bunny351/9pfs">9pfs</a>.</p>
<h2>How it works</h2>
<p>Before I could mount the connection, I had to serve it somehow. Normally I already serve 9P directly from my server's filesystem, but that requires some authentication that 9pfs does not support, so I had to serve it without authentication. Serving directly to the internet without authentication is of course pretty dumb since everyone can then access my files, so thanks to a hint from hiro, I figured out that it is actually possible to use the host's network stack on the server by binding <code>/mnt/term/net</code> over <code>/net</code>.</p>
<p>I'll just show the final script below and explain it afterwards:</p>
<code><pre>
#!/bin/rc
rfork n
bind /mnt/term/net /net
aux/listen1 -t tcp!*!12335 /bin/exportfs -r / &
os mkdir -p /tmp/drawterm
os 9pfs localhost -p 12335 /tmp/drawterm
</pre></code>
<p>So the first thing that happens is that I bind the host's network in, and from that point on, every network connection in this namespace actually goes out from the host instead of from the server!</p>
<p>Then <code>exportfs</code> is started and it is serving the <code>/</code> directory over 9P at port 12335. The <code>os</code> command runs a command on the host, so it just creates the folder that the system will be mounted to, and then uses <code>9pfs</code> to actually mount it. The nice thing here is that <code>9pfs</code> just connects to localhost.</p>
<h2>Using it</h2>
<p>As I said in the beginning, I did this to be able to edit files on the 9front server, and run compilers/interpreters on linux. The <code>os</code> command goes a long way, but the following script makes it even easier (I have this installed as <code>linux</code>):</p>
<code><pre>
#!/bin/rc
dir=/tmp/drawterm/`{pwd}
os -d $dir $*
</pre></code>
<p>This means I can just go into any directory on the server, type <code>linux ghci</code> and I get a haskell repl running in the correct directory, as seen in the gif below.</p>
<p><a href="https://images.pmikkelsen.com/linuxreverse.gif" /><img src="https://images.pmikkelsen.com/linuxreverse.gif" alt="An animated gif showing ghci loading a file on the 9front server" /></a></p>
<h2>Final notes</h2>
<p>The bind net trick still blows my mind a bit, since it is so trivial, yet so powerful. It is also fun to think about how one would do this on other systems than plan9, which I can't even imagine.</p>
</article>
</div>
<footer>
<a href="http://werc.cat-v.org">Powered by werc</a> © Peter Mikkelsen 2019-2025
</footer>
</body></html>