<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://brokenco.de//feed/by_tag/jails.xml" rel="self" type="application/atom+xml" /><link href="https://brokenco.de//" rel="alternate" type="text/html" /><updated>2026-05-03T00:12:50+00:00</updated><id>https://brokenco.de//feed/by_tag/jails.xml</id><title type="html">rtyler</title><subtitle>a moderately technical blog</subtitle><author><name>R. Tyler Croy</name></author><entry><title type="html">Solving a FreeBSD Jails issue: interface already exists</title><link href="https://brokenco.de//2023/11/12/interface-already-exists.html" rel="alternate" type="text/html" title="Solving a FreeBSD Jails issue: interface already exists" /><published>2023-11-12T00:00:00+00:00</published><updated>2023-11-12T00:00:00+00:00</updated><id>https://brokenco.de//2023/11/12/interface-already-exists</id><content type="html" xml:base="https://brokenco.de//2023/11/12/interface-already-exists.html"><![CDATA[<p>For a long time after I rebuilt my jails host, I could not restart a certain
number of jails due to an “interface already exists” error. For the life of me
I could not make sense of it, The services running in the jails were useful but
not <em>required</em> so I put off tinkering with it. I thought that I would magically
stumble into the solution in my sleep or something equally silly.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>watermelon# service jail start gitea
Starting jails: cannot start jail  "gitea":
ifconfig: interface epair14 already exists
jail: gitea: ifconfig epair14 create up: failed
.
watermelon# service jail stop gitea
Stopping jails:.
</code></pre></div></div>

<p>What perplexed me about this issue is that I would run <code class="language-plaintext highlighter-rouge">ifconfig epair14a</code>
after the failure to start the jail, and the interface would be there. “Surely
this must be a FreeBSD bug!”</p>

<p>The “eureka!” happened earlier today, not while I was sleeping, but rather
while I was solving other problems. “I bet there’s something fishy in the
configuration, I should just rewrite it” I thought to myself. Most esoteric
bugs are not bugs with the compiler, libraries, or operating systems. Usually
they’re the user doing something slightly stupid and not realizing it.</p>

<p>My jail configuration (<code class="language-plaintext highlighter-rouge">/etc/jail.conf</code>) resembled the following:</p>

<div class="language-conf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gitea</span> {
        $<span class="n">id</span> = <span class="s2">"14"</span>;
        $<span class="n">ip_addr</span> = <span class="s2">"10.10.10.${id}"</span>;

        <span class="n">vnet</span>.<span class="n">interface</span> = <span class="s2">"epair${id}b"</span>;

        <span class="n">exec</span>.<span class="n">prestart</span> = <span class="s2">"ifconfig epair${id} create up"</span>;
        <span class="n">exec</span>.<span class="n">prestart</span> += <span class="s2">"ifconfig epair${id}a up descr vnet-${name}"</span>;
        <span class="n">exec</span>.<span class="n">prestart</span> += <span class="s2">"ifconfig $public_bridge addm epair${id}a up"</span>;

        <span class="n">exec</span>.<span class="n">start</span> = <span class="s2">"/sbin/ifconfig epair${id}b ${ip_addr}"</span>;
        <span class="n">exec</span>.<span class="n">start</span> += <span class="s2">"/sbin/route add default ${public_gw}"</span>;
        <span class="n">exec</span>.<span class="n">start</span> += <span class="s2">"/bin/sh /etc/rc"</span>;

        <span class="n">exec</span>.<span class="n">prestop</span> = <span class="s2">"ifconfig epair${id}b -vnet ${name}"</span>;
        <span class="n">exec</span>.<span class="n">poststop</span> = <span class="s2">"ifconfig ${public_bridge} deletem epair${id}a"</span>;
        <span class="n">exec</span>.<span class="n">poststop</span> += <span class="s2">"ifconfig epair${id}a destroy"</span>;
}
</code></pre></div></div>

<p>Looking at the block and comparing it to other <em>functional</em> jails, I saw something missing: a <code class="language-plaintext highlighter-rouge">vnet;</code> declaration:</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gd">--- jail.conf   2023-11-12 20:09:03.028010000 -0800
</span><span class="gi">+++ /etc/jail.conf      2023-11-12 19:59:02.867271000 -0800
</span><span class="p">@@ -230,6 +230,7 @@</span>
        $id = "14";
        $ip_addr = "10.10.10.${id}";

+       vnet;
        vnet.interface = "epair${id}b";

        exec.prestart = "ifconfig epair${id} create up";
</code></pre></div></div>

<p>Sometimes you have to just walk away from a problem for a bit, but yeesh was that a silly one!</p>]]></content><author><name>R. Tyler Croy</name></author><category term="freebsd" /><category term="jails" /><summary type="html"><![CDATA[For a long time after I rebuilt my jails host, I could not restart a certain number of jails due to an “interface already exists” error. For the life of me I could not make sense of it, The services running in the jails were useful but not required so I put off tinkering with it. I thought that I would magically stumble into the solution in my sleep or something equally silly.]]></summary></entry><entry><title type="html">Increasing the density of the home lab with FreeBSD Jails</title><link href="https://brokenco.de//2021/06/06/high-density-homelab.html" rel="alternate" type="text/html" title="Increasing the density of the home lab with FreeBSD Jails" /><published>2021-06-06T00:00:00+00:00</published><updated>2021-06-06T00:00:00+00:00</updated><id>https://brokenco.de//2021/06/06/high-density-homelab</id><content type="html" xml:base="https://brokenco.de//2021/06/06/high-density-homelab.html"><![CDATA[<p>Investing the time to learn FreeBSD jails has led to a dramatic increase in the
number of services I run in my “home lab.”
<a href="https://docs.freebsd.org/en/books/handbook/jails/">Jails</a>, which I have
<a href="/tag/freebsd.html">written about before</a>, are effectively a lightweight
quasi-virtualization technique which I use to create multiple software-defined
networks to segment workloads. Jails have allowed me to change my “home lab”
dramatically, allowing me to <em>reduce</em> the number of machines and increase
hardware utilization. For now, the days of stacking machines, dangling
Raspberry Pis, or hiding laptops on the shelf are all gone. Almost all my needs
have been consolidated into a single FreeBSD machine running on a 4 year old
used workstation.</p>

<p>I have attempted to consolidate the home lab before, but not with this
level of success. There was the time I tried deploying a single-node
Kubernetes cluster, which worked for a time until some upgrade caused the
software-defined networking to break in a way I wasn’t interested in debugging
in my free time. Following that I tried to go “old school” and started spinning
up <code class="language-plaintext highlighter-rouge">libvirt</code>-based virtual machines which worked <em>well</em> for a long time. The
major downside of that approach is that I simply wasn’t able to get much
density because of the significant overhead for each virtual machine. At some
point you run out of memory to commit to each VM.</p>

<p>Converting virtual machines to FreeBSD Jails took a few hours over a weekend,
and since then the <strong>quantity</strong> of what is running has jumped dramatically. Originally I was running:</p>

<ul>
  <li><a href="https://nextcloud.com">Nextcloud</a> (Apache)</li>
  <li>MySQl</li>
  <li>Gopher server</li>
  <li><a href="https://torproject.org/">Tor</a> relay</li>
  <li><a href="https://gitea.io">Gitea</a></li>
</ul>

<p>I now <em>also</em> run:</p>

<ul>
  <li>Elasticsearch</li>
  <li>Graylog</li>
  <li>Icinga</li>
  <li>Icecast</li>
  <li>MongoDB</li>
  <li>Nginx</li>
  <li><a href="https://joinpeertube.org">Peertube</a></li>
  <li>PostgreSQL, which replaced MySQL for Nextcloud and is now running for multiple services.</li>
  <li>Redis</li>
  <li>Plus some personal web apps</li>
</ul>

<p>To accomplish this, I use ZFS and Jails <strong>heavily</strong>. All the jails run on a
striped and mirrored ZFS disk array which allows for better performance and
redundancy than my previous incantation. These services are low-utilization
which allows them to cooperate effectively within this machine’s 4 cores and
16GB of RAM.</p>

<h2 id="benefits">Benefits</h2>

<p>The higher utilization of this single machine, which is always-on, has a better
power consumption profile than running multiple machines. More power efficiency wasn’t my original motivation however, I was much more interested in some of the system administration benefits of bringing these services “under one roof.”</p>

<p><strong>Backups</strong> are <em>much</em> easier than before. I’m using some ZFS scripts to
perform automatic snapshots on daily/weekly/monthly basis. Separately from
those, I regularly push backups off-site and that’s trivial because at the
“host” machine level, not the jail level, I can access all the filesystems at
once.</p>

<p><strong>Security</strong> is much easier as well since Jails are obviously providing a level
of isolation. On top of that, I am using the <code class="language-plaintext highlighter-rouge">vnet</code> functionality in FreeBSD to
provide additional network segmentation, something I never did with physical or
virtual machines.</p>

<p><strong>Management</strong> is pretty straightforward with all these services running in
Jails. I typically do all my administration from the host rather than the jail
level. As such I can pretty easily shuffle configuration files around.
Unfortunately to date I haven’t found a good configuration management tool,
including my own <a href="https://github.com/rtyler/zap">tinkering</a> that provides a
Jails-aware set of tools for more automation.</p>

<h2 id="downsides">Downsides</h2>

<p>The most notable downside to this approach is that a hardware failure <em>could</em>
take me offline for a bit. These services are all dependent on a single power
supply (PSU) and CPU. As such a failure of either would require me to keep all
these services offline until that part could be replaced. For a home lab setup,
I’m not expecting to support a specific SLA, so I’m quite comfortable with this
risk.</p>

<p>I can imagine some security arguments that could be made, but frankly I think
this Jails approach is <em>much</em> better secured than my previous home lab setups.</p>

<hr />

<p>At present this machine has just under 10GB of RAM in use and a load average
that floats between 1.0 and 2.0. Despite all the services that are running, it
still uses <em>less</em> than my workstation with a few browsers open. To deploy your
own “home lab” set up in this way you absolutely <em>do not</em> need a high powered
machine. I would argue that a ZFS-based disk array is likely more important,
after all most home lab tasks, that aren’t video-encoding, tend to be more disk
I/O heavy rather than memory/CPU heavy.</p>

<p>This path isn’t quite entry-level simple, but if you have some systems
administration experience, I think <a href="https://freebsd.org">FreeBSD</a> with ZFS and
Jails is worth considering for your home or office lab.</p>]]></content><author><name>R. Tyler Croy</name></author><category term="freebsd" /><category term="jails" /><summary type="html"><![CDATA[Investing the time to learn FreeBSD jails has led to a dramatic increase in the number of services I run in my “home lab.” Jails, which I have written about before, are effectively a lightweight quasi-virtualization technique which I use to create multiple software-defined networks to segment workloads. Jails have allowed me to change my “home lab” dramatically, allowing me to reduce the number of machines and increase hardware utilization. For now, the days of stacking machines, dangling Raspberry Pis, or hiding laptops on the shelf are all gone. Almost all my needs have been consolidated into a single FreeBSD machine running on a 4 year old used workstation.]]></summary></entry><entry><title type="html">Using FreeBSD’s pkg(1) with an ‘offline’ jail</title><link href="https://brokenco.de//2021/02/02/freebsd-pkg-with-an-offline-jail.html" rel="alternate" type="text/html" title="Using FreeBSD’s pkg(1) with an ‘offline’ jail" /><published>2021-02-02T00:00:00+00:00</published><updated>2021-02-02T00:00:00+00:00</updated><id>https://brokenco.de//2021/02/02/freebsd-pkg-with-an-offline-jail</id><content type="html" xml:base="https://brokenco.de//2021/02/02/freebsd-pkg-with-an-offline-jail.html"><![CDATA[<p>In the modern era of highly connected software, I have been trying to “offline”
as many of my personal services as I can. The ideal scenario being a service
running in an environment where it cannot reach other nodes on the network, or
in some cases even route back to the public internet. To accomplish this I have
been working with <a href="https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/jails.html">FreeBSD
jails</a> a
quite a bit, creating a service per-jail in hopes of achieving high levels of
isolation between them. This approach has a pretty notable problem at first
glance: if you need to install software from remote sources in the jail, how do
you keep it “offline”?</p>

<p><strong>2021-02-14 update</strong> with more tips <a href="#update">below</a></p>

<p><em>Note: if you’re already familiar with how great FreeBSD jails are, you can skip <a href="#pkg">ahead</a></em></p>

<p>Without trying to start a flamewar, I think FreeBSD jails are basically what
Linux containers aspired to be when they grew up. In short:</p>

<blockquote>
  <p>The jail mechanism is an implementation of FreeBSD’s OS-level virtualisation
that allows system administrators to partition a FreeBSD-derived computer
system into several independent mini-systems called jails, all sharing the same
kernel, with very little overhead</p>
</blockquote>

<p><em>From <a href="https://en.wikipedia.org/wiki/FreeBSD_jail">Wikipedia</a></em></p>

<p>Since FreeBSD 12, FreeBSD jails can “natively” do something which I haven’t
seen done seriously in other container or virtualization stacks: <strong>provide full
network isolation</strong>. VNET allows attaching an entire virtualized network stack
to a jail, which allows you to delegate an actual hardware interface to a jail,
after which the host no longer sees the interface at all!</p>

<blockquote>
  <p>VNET is the name of a technique to virtualize the network stack.  The
basic idea is to change global resources most notably variables into per
network stack resources and have functions, sysctls, eventhandlers, etc.
access and handle them in the context of the correct instance.  Each
(virtual) network stack is attached to a prison, with vnet0 being the
unrestricted default network stack of the base system.</p>
</blockquote>

<p><em>From <code class="language-plaintext highlighter-rouge">vnet(9)</code></em></p>

<p>Using this capability you can set up entirely software-defined virtualized networks inside of FreeBSD jails for everything from network software testing (e.g. VPNs), to pre-flighting firewall changes in a simulated environment. If this sounds compelling to you, I recommend bouncing over to <a href="https://klarasystems.com/articles/virtualize-your-network-on-freebsd-with-vnet/">this blog post</a> to learn more.</p>

<p>FreeBSD has also supported
<a href="https://www.freebsd.org/doc/handbook/zfs-zfs.html">ZFS</a>
natively, including as the boot <code class="language-plaintext highlighter-rouge">/</code> partition for a number of major releases.
It should therefore be no surprise that jails integrate <em>very</em> well with ZFS.
In my setup each jail is its own file system in the main ZFS pool (<code class="language-plaintext highlighter-rouge">zroot</code>),
which allows me to snapshot each jail independently for backup purposes.</p>

<p>“Excuse me, I believe I was promised some <code class="language-plaintext highlighter-rouge">pkg(1)</code> related content?”</p>

<p>Yes yes, getting to that. Since FreeBSD jails are not well appreciated by the
broader systems engineering world, I wanted to take a moment to highlight some
of what we’ve been missing out the past couple years while we’ve been screwing
around with container orchestration engines.</p>

<p><code class="language-plaintext highlighter-rouge">pkg(1)</code> is a binary package management tool akin to <code class="language-plaintext highlighter-rouge">apt</code> or <code class="language-plaintext highlighter-rouge">yum</code>. On modern
FreeBSD installations compiling ports is no longer required, which is an
incredibly welcome change to FreeBSD in recent years.  Like its Linux
relatives, <code class="language-plaintext highlighter-rouge">pkg</code> retrieves package metadata and tarballs from a remote
repository by default, from the “offline jail” perspective this is a problem.</p>

<p>Jails however, are just running off slices of my host filesystem, e.g. <code class="language-plaintext highlighter-rouge">/jails/postgresql</code> which allows me to commands from the host in that file tree, for example:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>freebsd# ls /jails/postgressql
.cshrc          bin             entropy         libexec         net             root            tmp
.profile        boot            etc             media           proc            sbin            usr
COPYRIGHT       dev             lib             mnt             rescue          sys             var
freebsd#
</code></pre></div></div>

<p>You should note that this looks surprisingly identical to what a default base
install of FreeBSD, and that’s because it is!</p>

<p><a name="pkg"></a></p>
<h2 id="installing-packages">Installing packages</h2>

<p>The <code class="language-plaintext highlighter-rouge">pkg(1)</code> utility has a <em>very useful</em> flag <code class="language-plaintext highlighter-rouge">-c</code> which I can use for these jails:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-c &lt;chroot path&gt;, --chroot &lt;chroot path&gt;
    pkg will chroot in the &lt;chroot path&gt; environment.
</code></pre></div></div>

<p>From the jail host’s perspective, I can poke around the jail’s filesystem with ease, which makes installing packages <em>trivial</em> from the host’s perspective. For example:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>freebsd# pkg -c /jails/postgresql install postgresql13-server
</code></pre></div></div>

<p>The above command will install the PostgreSQL v13 package and all its dependencies within the jail’s filesystem path:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># postgres --version
postgres (PostgreSQL) 13.1
#
</code></pre></div></div>

<p>“Try this one weird trick and your jails will never have to know anything about
packages ever again!”</p>

<p><strong>Caveats</strong>:</p>

<ul>
  <li>My host distribution is identical to the distribution installed in the jail,
e.g. <code class="language-plaintext highlighter-rouge">12.2-RELEASE</code>. If there were drift I’m sure there would be problems
with using <code class="language-plaintext highlighter-rouge">pkg(1)</code> in this way.</li>
  <li>This approach can feel goofy with configuration management, since the jail
host is where all the configuration and package management happens.</li>
</ul>

<p>Nonetheless, I was incredibly excited to discover this feature which made
setting up and managing my heavily isolated vnet-based jails <em>much</em> easier!</p>

<hr />

<p><a name="update"></a>
<strong>2021-02-14 update:</strong> Here’s a tip passed along from a reader:</p>

<blockquote>
  <p>you might be interested in a tip for your jail post.</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pkg -o ABI=... \
--chroot /path/to/jail \
--config /some/package/repo/FreeBSD.conf \
install -y ...
</code></pre></div>  </div>

  <p>where ABI could be FreeBSD:14:aarch64 (FreeBSD current on armv8/aarch64) or a more prosaic FreeBSD:12:amd64 (amd64 architecture, FreeBSD 12).</p>

  <p>the config file is similar to <code class="language-plaintext highlighter-rouge">/etc/pkg/FreeBSD.conf</code> and is acquired by <code class="language-plaintext highlighter-rouge">pkg(8)</code> before dropping into the chroot.</p>

  <p>NB I usually need to mount_devfs inside the jail before &amp; after pkg, as it now requires /dev/null - see <a href="https://github.com/freebsd/pkg/issues/1763">#1763</a></p>

  <p>This allows us to install packages into a directory that is not for the same FreeBSD version (and possibly even architecture!), such as a FreeBSD 13.0 armv8 nfs mount, running on a FreeBSD 14.0-current amd64 server.</p>

  <p>There’s also pkg –rootdir … which is similar to chroot, but IIRC handles pre/post/user/group scripts differently.</p>
</blockquote>

<hr />

<p>In the future I hope to write more about the home lab FreeBSD set up that I
have been working on over the past couple weeks. FreeBSD 12.x is by far the
most exciting FreeBSD release I have used since the transition to full SMP in
the 4.x -&gt; 6.x timeframe. If you haven’t looked at FreeBSD lately, I highly
recommend giving it a spin!</p>]]></content><author><name>R. Tyler Croy</name></author><category term="freebsd" /><category term="jails" /><summary type="html"><![CDATA[In the modern era of highly connected software, I have been trying to “offline” as many of my personal services as I can. The ideal scenario being a service running in an environment where it cannot reach other nodes on the network, or in some cases even route back to the public internet. To accomplish this I have been working with FreeBSD jails a quite a bit, creating a service per-jail in hopes of achieving high levels of isolation between them. This approach has a pretty notable problem at first glance: if you need to install software from remote sources in the jail, how do you keep it “offline”?]]></summary></entry></feed>