<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>S3 on inetshell</title><link>https://inet.sh/en/tags/s3/</link><description>Recent content in S3 on inetshell</description><generator>Hugo</generator><language>en</language><lastBuildDate>Wed, 19 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://inet.sh/en/tags/s3/index.xml" rel="self" type="application/rss+xml"/><item><title>Send ZFS snapshots to another host (and on to S3)</title><link>https://inet.sh/en/posts/zfs/backups-to-s3/</link><pubDate>Wed, 19 Aug 2026 00:00:00 +0000</pubDate><guid>https://inet.sh/en/posts/zfs/backups-to-s3/</guid><description>zfs send -w -R -i over SSH into zfs recv -s, and how to land the same stream in S3. Incremental, raw, resumable.</description><content:encoded><![CDATA[<h2 id="tldr">TL;DR</h2>
<p><code>zfs send -w -R -i</code> over SSH to <code>zfs recv -s</code>. The stream is not a tarball; S3 is an extra hop if needed.</p>
<p><code>zfs send</code> emits a <strong>replicable stream</strong>, not a directory. The natural sink is another pool (<code>zfs recv</code>). S3 is a second hop: store the stream as an object, or use something like <a href="https://github.com/pressly/z3">z3</a>.</p>
<h2 id="incremental-to-another-host-the-command-i-actually-run">Incremental to another host (the command I actually run)</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">zfs send -w -R -v -i vol1/secure/backups@initial vol1/secure/backups@new <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="p">|</span> ssh root@10.0.0.1 zfs recv -s vol1/secure/backups
</span></span></code></pre></td></tr></table>
</div>
</div><table>
  <thead>
      <tr>
          <th>Flag</th>
          <th>Meaning</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>-w</code></td>
          <td>raw: send the dataset <strong>encrypted as-is</strong>. The receiver does not need the key to <code>recv</code>.</td>
      </tr>
      <tr>
          <td><code>-R</code></td>
          <td>replicate properties and child snapshots</td>
      </tr>
      <tr>
          <td><code>-i @initial @new</code></td>
          <td>incremental from <code>@initial</code> (must exist on <strong>both</strong> sides)</td>
      </tr>
      <tr>
          <td><code>-v</code></td>
          <td>progress</td>
      </tr>
      <tr>
          <td><code>recv -s</code></td>
          <td><strong>resumable</strong> if SSH drops (<code>recv -s</code> again)</td>
      </tr>
  </tbody>
</table>
<p><a href="/en/posts/zfs/hold-protect-snapshot/">Hold</a> <code>@initial</code> and <code>@new</code> while the send runs, or prune will break the chain.</p>
<p>The first full (no <code>-i</code>) is mandatory once:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">zfs send -w -R -v vol1/secure/backups@initial <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="p">|</span> ssh root@10.0.0.1 zfs recv -s vol1/secure/backups
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="land-it-in-s3">Land it in S3</h2>
<p>Same stream, other side of the pipe:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">zfs send -w -R vol1/secure/backups@new <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="p">|</span> gzip -1 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="p">|</span> aws s3 cp - s3://my-bucket/zfs/backups@new.zfs.gz
</span></span></code></pre></td></tr></table>
</div>
</div><p>Restore:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">aws s3 cp s3://my-bucket/zfs/backups@new.zfs.gz - <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="p">|</span> gunzip <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="p">|</span> zfs recv -s vol1/secure/backups
</span></span></code></pre></td></tr></table>
</div>
</div><p>This is <strong>not</strong> a file sync. It is an opaque blob: you restore the whole stream (or the incremental on top of the full), or you restore nothing. Name <code>@initial</code> / <code>@new</code> and do not delete the full.</p>
<p>For incrementals in S3, tools like z3 keep a catalog of what already landed. A raw <code>aws s3 cp -</code> does not.</p>
<p><code>-w</code> into S3 is correct if the dataset is already encrypted: AWS never sees plaintext. If the source is <strong>not</strong> encrypted, either encrypt on recv (<a href="/en/posts/zfs/send-unencrypted-to-encrypted/">post</a>) or encrypt the object (KMS / client) — a cleartext stream in a bucket is a cleartext backup.</p>
<p>See also: <a href="/en/posts/zfs/encryption/">native encryption</a>.</p>
]]></content:encoded></item></channel></rss>