<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Fly.io on Renne Rocha</title>
    <link>https://rennerocha.com/tags/fly.io/</link>
    <description>Recent content in Fly.io on Renne Rocha</description>
    <generator>Hugo</generator>
    <language>en</language>
    
      <managingEditor>blog@rocha.dev.br (Renne Rocha)</managingEditor>
    
    
      <webMaster>blog@rocha.dev.br (Renne Rocha)</webMaster>
    
    
    
      <lastBuildDate>Tue, 06 May 2025 00:00:00 +0000</lastBuildDate>
    
      <atom:link href="https://rennerocha.com/tags/fly.io/index.xml" rel="self" type="application/rss+xml" />
      <item>
        <title>Creating backups for fly.io Volumes</title>
        <link>https://rennerocha.com/posts/creating-backups-for-fly-io-volumes/</link>
        <pubDate>Wed, 30 Apr 2025 00:00:00 +0000</pubDate><author>blog@rocha.dev.br (Renne Rocha)</author>
        <guid>https://rennerocha.com/posts/creating-backups-for-fly-io-volumes/</guid>
        <description>&lt;p&gt;I have a few applications running on &lt;a href=&#34;https://fly.io&#34;&gt;fly.io&lt;/a&gt;, and some of them need to&#xA;keep data in the file system persistently (more precisely, an SQLite database file and&#xA;user-submitted data) so that it is not lost after a redeploy or when the Fly Machine running my application is&#xA;restarted.&lt;/p&gt;&#xA;&lt;p&gt;To achieve that, I use &lt;a href=&#34;https://fly.io/docs/volumes/overview/&#34;&gt;Fly Volumes&lt;/a&gt; which are local&#xA;persistent storage for Fly Machines, mounted in my server just like a regular directory. This setup works fine,&#xA;but I began considering how to back up the data stored there.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://fly.io/docs/volumes/snapshots/&#34;&gt;Volume snapshots&lt;/a&gt; are created automatically on a daily basis and&#xA;retained for 5 days by default. However, there doesn&amp;rsquo;t seem to be an easy (or well-documented) way to implement&#xA;a custom backup policy. I wanted the ability to copy the entire directory&amp;rsquo;s content using tools like &lt;code&gt;rsync&lt;/code&gt; or upload&#xA;it to an S3 bucket on my own schedule.&lt;/p&gt;&#xA;&lt;p&gt;I explored solutions involving &lt;code&gt;cron&lt;/code&gt; jobs running inside my Fly Machine, but they became overly complicated.&#xA;These approaches required modifying my &lt;code&gt;Dockerfile&lt;/code&gt; to install additional applications, and I wasn&amp;rsquo;t sure&#xA;how to manage the schedule effectively, especially since I configured my machines to auto-stop to save resources.&lt;/p&gt;&#xA;&lt;p&gt;Direct SSH connections requires me to use &lt;code&gt;flyctl&lt;/code&gt; CLI and it wasn&amp;rsquo;t clear to me how to handle authentication&#xA;in this case. After some research, I found that I can use &lt;a href=&#34;https://fly.io/docs/security/tokens/&#34;&gt;access tokens&lt;/a&gt;&#xA;to connect to the machines using SSH allowing me to send commands there in an automated way.&lt;/p&gt;&#xA;&lt;h2 id=&#34;generating-your-access-token&#34;&gt;&#xA;    &lt;a href=&#34;#generating-your-access-token&#34; class=&#34;anchor&#34;&gt;&#xA;        &lt;svg class=&#34;icon&#34; aria-hidden=&#34;true&#34; focusable=&#34;false&#34; height=&#34;16&#34; version=&#34;1.1&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34;&gt;&#xA;            &lt;path fill-rule=&#34;evenodd&#34;&#xA;                d=&#34;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/a&gt;&#xA;    Generating your access token&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;First step is to create an access token that allows me to send commands to my machine without requiring any&#xA;manual form of authentication. This can be done using the following command:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&#xA;&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fly tokens create ssh -n my-token-name&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;Check the &lt;a href=&#34;https://fly.io/docs/flyctl/tokens-create-ssh/&#34;&gt;command documentation&lt;/a&gt; for more options. The output of&#xA;this command will be as the following, where &lt;code&gt;&amp;lt;TOKEN_CONTENT_STRING&amp;gt;&lt;/code&gt; will be a very long string that&#xA;you need to store and don&amp;rsquo;t share it publicly.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&#xA;&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FlyV1 &amp;lt;TOKEN_CONTENT_STRING&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;Add the token to an environment var in the machine you will run the backup script:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&#xA;&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export FLY_SSH_TOKEN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&amp;lt;TOKEN_CONTENT_STRING&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;h2 id=&#34;data-location&#34;&gt;&#xA;    &lt;a href=&#34;#data-location&#34; class=&#34;anchor&#34;&gt;&#xA;        &lt;svg class=&#34;icon&#34; aria-hidden=&#34;true&#34; focusable=&#34;false&#34; height=&#34;16&#34; version=&#34;1.1&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34;&gt;&#xA;            &lt;path fill-rule=&#34;evenodd&#34;&#xA;                d=&#34;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/a&gt;&#xA;    Data location&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;The volume is mounted in &lt;code&gt;/data&lt;/code&gt; directory, defined in our application &lt;code&gt;fly.toml&lt;/code&gt; file:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[[mounts]]&#xA;  source = &amp;#39;app_data&amp;#39;&#xA;  destination = &amp;#39;/data&amp;#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;creating-a-backup-script&#34;&gt;&#xA;    &lt;a href=&#34;#creating-a-backup-script&#34; class=&#34;anchor&#34;&gt;&#xA;        &lt;svg class=&#34;icon&#34; aria-hidden=&#34;true&#34; focusable=&#34;false&#34; height=&#34;16&#34; version=&#34;1.1&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34;&gt;&#xA;            &lt;path fill-rule=&#34;evenodd&#34;&#xA;                d=&#34;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/a&gt;&#xA;    Creating a backup script&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Given that we have a token, we are now able to execute SSH commands remotely on our Fly Machine. In&#xA;our scenario, I am compacting the whole content of &lt;code&gt;/data/&lt;/code&gt; directory (where all the data that I want&#xA;to backup is located) generating a tarball, then I download it locally.&lt;/p&gt;&#xA;&lt;p&gt;I could create a custom script and copy it to the remote machine if I want to perform more complex&#xA;tasks, or you can extend/modify this script to perform other tasks (e.g. download the tarball&#xA;and upload to a S3 bucket).&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#!/bin/bash&#xA;# backup.sh&#xA;&#xA;# Need to start container in fly.io if it was stopped by inactivity&#xA;curl -s -o /dev/null https://your-app.fly.dev/&#xA;&#xA;filename=&amp;#34;data_backup_$(date +%F).tar.gz&amp;#34;&#xA;fly ssh console -C &amp;#39;tar cvz /data&amp;#39; -t $FLY_SSH_TOKEN &amp;gt; $filename&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;run-it-periodically&#34;&gt;&#xA;    &lt;a href=&#34;#run-it-periodically&#34; class=&#34;anchor&#34;&gt;&#xA;        &lt;svg class=&#34;icon&#34; aria-hidden=&#34;true&#34; focusable=&#34;false&#34; height=&#34;16&#34; version=&#34;1.1&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34;&gt;&#xA;            &lt;path fill-rule=&#34;evenodd&#34;&#xA;                d=&#34;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/a&gt;&#xA;    Run it periodically&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Now you can add &lt;code&gt;backup.sh&lt;/code&gt; to your &lt;code&gt;crontab&lt;/code&gt; schedule, or even adapt the procedure described here&#xA;to be executed in other environments, like defining a GitHub Action or another way to schedule jobs.&lt;/p&gt;&#xA;&lt;p&gt;I know this is not the most complete way to implement a backup policy, but it is working for my current projects.&#xA;In the future, as I improve my scripts, I will possibly update this post to make it more complete.&lt;/p&gt;&#xA;</description>
      </item>
  </channel>
</rss>