<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Self-Host on Renne Rocha</title>
    <link>https://rennerocha.com/tags/self-host/</link>
    <description>Recent content in Self-Host 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>Thu, 14 Aug 2025 00:00:00 +0000</lastBuildDate>
    
      <atom:link href="https://rennerocha.com/tags/self-host/index.xml" rel="self" type="application/rss+xml" />
      <item>
        <title>Using rclone on Backblaze without spending all your money</title>
        <link>https://rennerocha.com/posts/using-rclone-on-backblaze-without-spending-all-your-money/</link>
        <pubDate>Thu, 14 Aug 2025 00:00:00 +0000</pubDate><author>blog@rocha.dev.br (Renne Rocha)</author>
        <guid>https://rennerocha.com/posts/using-rclone-on-backblaze-without-spending-all-your-money/</guid>
        <description>&lt;p&gt;&lt;a href=&#34;https://www.backblaze.com/&#34;&gt;Backblaze&lt;/a&gt; is an object storage company that offers a S3 compatible cloud object storage with very competitive prices. With prices starting at USD6 / TB / month (or less, as you pay proportionally to the amount of data stored), it was a perfect choice to store live data and backups of my projects and self-hosted services.&lt;/p&gt;&#xA;&lt;p&gt;One of the services that I use is &lt;a href=&#34;https://immich.app/&#34;&gt;Immich&lt;/a&gt;, a self-hosted photo and video management solution that allows me to have fully control on my photos (even in mobile). It doesn&amp;rsquo;t allows me to store my photos directly in a object storage as Backblaze, but I decided that it would be a good idea to keep a backup of the files of the server (photos, videos, and some other data that I need to keep safe).&lt;/p&gt;&#xA;&lt;p&gt;One tool that simplifies the process is &lt;a href=&#34;https://rclone.org/&#34;&gt;rclone&lt;/a&gt;, a tool that make it easier to sync data in cloud providers (their maintainers call it as &amp;ldquo;rsync for cloud storage&amp;rdquo;). I followed of the instructions they provide to &lt;a href=&#34;https://rclone.org/b2/&#34;&gt;configure Backblaze&lt;/a&gt; and then I was able to run the following command:&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;rclone sync /home/immich/library/ b2:my-immich-backup-bucket&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;This command syncs automatically only new and changed files (e.g. updated photos metadata), reducing the time needed to backup my photos and keeping them updated, uploading to my Backblaze bucket.&lt;/p&gt;&#xA;&lt;p&gt;There are many other options that I can use with rclone, and scenarios where this backup scheme doesn&amp;rsquo;t cover. However, as a starting point to give me a bit more of confidence that I will not lose my photos if my VPS provider suddenly decides to stop providing me services, it is good enough.&lt;/p&gt;&#xA;&lt;p&gt;I configured &lt;a href=&#34;https://www.man7.org/linux/man-pages/man5/crontab.5.html&#34;&gt;crontab&lt;/a&gt; to run it hourly, and then I start to get my files synchronized.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;So I got the first charge after enabling this scheme!&lt;/strong&gt; Usually I was paying less than USD2/month, but the first month I got a USD10 bill, then USD60, then USD70. I wasn´t storing terabytes of data. Looking at my billing report I noticed that now I have a not negligible amount of &lt;strong&gt;Class C (Charged)&lt;/strong&gt; transactions, that are responsible for me to pay that much.&lt;/p&gt;&#xA;&lt;p&gt;We interact with Backblaze using API calls to manage our storage, so we can upload and download files, get information about them and the buckets, and many other actions. Each call is grouped in a different class of transaction (A, B and C), and they are &lt;a href=&#34;https://www.backblaze.com/cloud-storage/transaction-pricing&#34;&gt;charged&lt;/a&gt; differently. Class A transactions are always free, but Class B and C transactions have a daily limit of 2,500 calls each and they charge for extra calls.&lt;/p&gt;&#xA;&lt;p&gt;When rclone executes, it gets information from the remote location about the files already there to decide if the local files need to be uploaded or not. This is done by the Class C API call &lt;a href=&#34;https://www.backblaze.com/apidocs/b2-list-file-names&#34;&gt;&lt;code&gt;b2_list_file_names&lt;/code&gt;&lt;/a&gt; that returns a list of filenames in chunks of 1.000 files each call.&lt;/p&gt;&#xA;&lt;p&gt;But when we have our files in nested directories, a call is made for each of them. Immich organizes the uploaded files in hundreds of nested directories, and because of that, every time my cron was executed, thousands of &lt;code&gt;b2_list_file_names&lt;/code&gt; calls were made. Given that I was running it hourly, I reached 17M calls in a month easily (around 500k a day). As I have only 2.5K free calls, I found the reason of the amount I was charged.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img loading=&#34;lazy&#34; &#xA;    src=&#34;https://rennerocha.com/immich-nested-directories.png&#34; &#xA;    alt=&#34;Immich nested directories&#34; &#xA;     &#xA;    width=924 &#xA;    height=&#34;215&#34;  /&gt;&lt;/p&gt;&#xA;&lt;p&gt;The solution is to add &lt;a href=&#34;https://rclone.org/docs/#fast-list&#34;&gt;&lt;code&gt;--fast-list&lt;/code&gt;&lt;/a&gt; parameter to the rclone command, that requires fewer transactions for highly recursive operations as we have in this scenario. This parameter &lt;a href=&#34;https://rclone.org/b2/&#34;&gt;is mentioned&lt;/a&gt; in rclone documentation that explains how to setup it with Backblaze, but I didn&amp;rsquo;t consider that this is basically a mandatory parameter based on how things are charged there!&lt;/p&gt;&#xA;&lt;p&gt;So I updated my rclone command to:&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;rclone sync /home/immich/library/ b2:my-immich-backup-bucket --fast-list&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;I reactivated cron again and after almost a day, instead of 500K calls, less than 1K calls were made (which is within the free amount I am entitled to). Probably when I have the double of the number of files I have right now, the daily quota I have will not be enough, but then I will know how to deal with it (possibly with a better backup strategy).&lt;/p&gt;&#xA;</description>
      </item>
      <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>
      <item>
        <title>Configuring a self-hosted calendar for your small community</title>
        <link>https://rennerocha.com/posts/configuring-self-hosted-calendar-for-small-community/</link>
        <pubDate>Thu, 08 Feb 2024 00:00:00 +0000</pubDate><author>blog@rocha.dev.br (Renne Rocha)</author>
        <guid>https://rennerocha.com/posts/configuring-self-hosted-calendar-for-small-community/</guid>
        <description>&lt;p&gt;I am one of the co-founders of &lt;a href=&#34;https://lhc.net.br&#34;&gt;Laboratório Hacker de Campinas&lt;/a&gt; (LHC), one of the first hackerspaces in Brazil and during more than a decade we always struggled how to publish and publicize our events.&lt;/p&gt;&#xA;&lt;p&gt;We started publishing them in our Wiki and crafting some custom scripts to convert certain special pages (following a very specific pattern) into entries of a ICS calendar (people usually didn&amp;rsquo;t follow the pattern, so many events were missing).&lt;/p&gt;&#xA;&lt;p&gt;For other years, we use meetup.com. It worked well and the net effect was good to make more people to know about the hackerspace. However they started to charge a not reasonable amount of money that we couldn&amp;rsquo;t afford to keep our community there.&lt;/p&gt;&#xA;&lt;p&gt;I was always looking for some kind of open source and (possibly) self-hosted solution. Then I found &lt;a href=&#34;https://gancio.org/&#34;&gt;Gancio&lt;/a&gt;, described as &lt;strong&gt;&amp;ldquo;A shared agenda for local communities.&amp;rdquo;&lt;/strong&gt;. Created in Italy by people from political hacking movements, it looked exactly the solution we are looking for. It is simple to use, (relatively) easy to maintain, privacy focused and federated.&lt;/p&gt;&#xA;&lt;p&gt;To deploy it, I decided to use &lt;a href=&#34;https://fly.io&#34;&gt;fly.io&lt;/a&gt;, a Platform-as-a-Service (PaaS) company that with one &lt;code&gt;Dockerfile&lt;/code&gt; and a few configuration files I was able to quickly deploy &lt;a href=&#34;https://gancio.org/&#34;&gt;Gancio&lt;/a&gt; there. They require a credit card to create an account, but if your application doesn&amp;rsquo;t use much CPU|memory|network|storage (which is our case with our calendar), it is very likely that you will never reach the minimum threshold to start paying. So it will be basically free to host it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;UPDATE (2025-03-04): fly.io did some changes in how they charge their users since this post was written (and to be honest, I still didn&amp;rsquo;t completely understand how it works), so perhaps following the steps that I shared here will not be totally free as before. But due to the ease of configuration and maintenance, I still believe it is a low-cost alternative to be considered.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt; I am not being sponsored by &lt;a href=&#34;https://fly.io&#34;&gt;fly.io&lt;/a&gt;. It is just a service that worked well for my needs.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img loading=&#34;lazy&#34; &#xA;    src=&#34;https://rennerocha.com/gancio-lhc.png&#34; &#xA;    alt=&#34;My hackerspace Gancio page&#34; &#xA;     &#xA;    width=956 &#xA;    height=&#34;712&#34;  /&gt;&#xA;&lt;em&gt;My &lt;a href=&#34;https://eventos.lhc.net.br&#34;&gt;hackerspace calendar&lt;/a&gt; running on fly.io&lt;/em&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;pre-requisites&#34;&gt;&#xA;    &lt;a href=&#34;#pre-requisites&#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;    Pre-requisites&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;To follow the next steps, you should have a basic knowledge with Linux and being comfortable to use command-line. Also I am assuming that you have a custom domain and know how to configure a DNS hosting to point it to a server.&lt;/p&gt;&#xA;&lt;h2 id=&#34;preparing-the-environment&#34;&gt;&#xA;    &lt;a href=&#34;#preparing-the-environment&#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;    Preparing the environment&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;We need three files that contains everything to deploy &lt;a href=&#34;https://gancio.org&#34;&gt;Gancio&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Dockerfile&lt;/code&gt; to build the application)&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;config.json&lt;/code&gt; to configure the application&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;fly.toml&lt;/code&gt; to deploy the application&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Start create a directory where you will place all these files. The first file you need is a &lt;code&gt;Dockerfile&lt;/code&gt;. I &lt;a href=&#34;https://framagit.org/les/gancio/-/blob/master/docs/Dockerfile&#34;&gt;copied it&lt;/a&gt; from the project documentation directory and did a few changes to give more control to the configuration file.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;FROM node:18-slim AS nodejs-base&#xA;RUN apt-get -q update &amp;amp;&amp;amp; \&#xA;    env DEBIAN_FRONTEND=noninteractive apt-get -y install git &amp;amp;&amp;amp; \&#xA;    apt-get clean &amp;amp;&amp;amp; rm -fr /var/lib/apt/lists/*&#xA;&#xA;FROM nodejs-base AS build&#xA;RUN yarnpkg global add --network-timeout 1000000000 --latest --production --silent https://gancio.org/latest.tgz &amp;amp;&amp;amp; \&#xA;    apt-get clean &amp;amp;&amp;amp; rm -fr /var/lib/apt/lists/* &amp;amp;&amp;amp; \&#xA;    yarnpkg cache clean&#xA;&#xA;FROM nodejs-base&#xA;COPY --from=build /usr/local/share/.config/yarn/ /usr/local/share/.config/yarn/&#xA;COPY config.json /config.json&#xA;RUN ln -s ../share/.config/yarn/global/node_modules/.bin/gancio /usr/local/bin/gancio&#xA;&#xA;ENTRYPOINT [&amp;#34;/usr/local/bin/gancio&amp;#34;]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next, create a &lt;code&gt;config.json&lt;/code&gt; file. The following is similar to the one that I am using, but you can check other &lt;a href=&#34;https://gancio.org/install/config&#34;&gt;configuration options&lt;/a&gt; information in Gancio&amp;rsquo;s docs.&lt;/p&gt;&#xA;&lt;p&gt;Given that I am not expecting that it will be a server with a high number of connections per second, I choose to keep every data stored in a SQLite file. This also make it easier for me to perform backups.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{&#xA;  &amp;#34;baseurl&amp;#34;: &amp;#34;https://your.domain.com&amp;#34;,&#xA;  &amp;#34;hostname&amp;#34;: &amp;#34;your.domain.com&amp;#34;,&#xA;  &amp;#34;server&amp;#34;: {&#xA;    &amp;#34;host&amp;#34;: &amp;#34;0.0.0.0&amp;#34;,&#xA;    &amp;#34;port&amp;#34;: 13120&#xA;  },&#xA;  &amp;#34;log_level&amp;#34;: &amp;#34;debug&amp;#34;,&#xA;  &amp;#34;log_path&amp;#34;: &amp;#34;/data/logs&amp;#34;,&#xA;  &amp;#34;db&amp;#34;: {&#xA;    &amp;#34;dialect&amp;#34;: &amp;#34;sqlite&amp;#34;,&#xA;    &amp;#34;storage&amp;#34;: &amp;#34;/data/gancio.sqlite&amp;#34;,&#xA;    &amp;#34;logging&amp;#34;: false,&#xA;    &amp;#34;dialectOptions&amp;#34;: {&#xA;      &amp;#34;autoJsonMap&amp;#34;: true&#xA;    },&#xA;    &amp;#34;retry&amp;#34;: {&#xA;      &amp;#34;match&amp;#34;: [&#xA;        null,&#xA;        null,&#xA;        null,&#xA;        {},&#xA;        {}&#xA;      ],&#xA;      &amp;#34;max&amp;#34;: 15&#xA;    }&#xA;  },&#xA;  &amp;#34;user_locale&amp;#34;: &amp;#34;/data/user_locale&amp;#34;,&#xA;  &amp;#34;upload_path&amp;#34;: &amp;#34;/data/uploads&amp;#34;,&#xA;  &amp;#34;proxy&amp;#34;: {&#xA;    &amp;#34;protocol&amp;#34;: &amp;#34;&amp;#34;,&#xA;    &amp;#34;hostname&amp;#34;: &amp;#34;&amp;#34;,&#xA;    &amp;#34;host&amp;#34;: &amp;#34;&amp;#34;,&#xA;    &amp;#34;port&amp;#34;: &amp;#34;&amp;#34;,&#xA;    &amp;#34;auth&amp;#34;: {&#xA;      &amp;#34;username&amp;#34;: &amp;#34;&amp;#34;,&#xA;      &amp;#34;password&amp;#34;: &amp;#34;&amp;#34;&#xA;    },&#xA;    &amp;#34;headers&amp;#34;: {}&#xA;  }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally we need to configure the application to deploy it to &lt;a href=&#34;https://fly.io&#34;&gt;fly.io&lt;/a&gt; using a &lt;code&gt;fly.toml&lt;/code&gt; file.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;app = &amp;#39;gancio-my-events&amp;#39;&#xA;primary_region = &amp;#39;gru&amp;#39;&#xA;&#xA;[build]&#xA;&#xA;[[mounts]]&#xA;  source = &amp;#39;gancio_data&amp;#39;&#xA;  destination = &amp;#39;/data&amp;#39;&#xA;&#xA;[http_service]&#xA;  internal_port = 13120&#xA;  force_https = true&#xA;  auto_stop_machines = true&#xA;  auto_start_machines = true&#xA;  min_machines_running = 0&#xA;  processes = [&amp;#39;app&amp;#39;]&#xA;&#xA;[[vm]]&#xA;  cpu_kind = &amp;#39;shared&amp;#39;&#xA;  cpus = 1&#xA;  memory_mb = 1024&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a minimal configuration that will allow you to deploy the application. But you can &lt;a href=&#34;https://fly.io/docs/reference/configuration/&#34;&gt;check fly.io docs&lt;/a&gt; to understand all available options.&lt;/p&gt;&#xA;&lt;p&gt;Important to know is that we are using &lt;a href=&#34;https://fly.io/docs/reference/volumes/&#34;&gt;Fly Volumes&lt;/a&gt; for persistent storage. In this volume we will have the configuration files, database and uploaded data (images) stored.&lt;/p&gt;&#xA;&lt;h2 id=&#34;launching-the-application&#34;&gt;&#xA;    &lt;a href=&#34;#launching-the-application&#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;    Launching the application&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;We are ready to launch our application. I am considering that you already have a &lt;a href=&#34;https://fly.io&#34;&gt;fly.io&lt;/a&gt; account created and installed &lt;a href=&#34;https://fly.io/docs/hands-on/install-flyctl/&#34;&gt;flyctl&lt;/a&gt; command-line utility that will be used in the next steps.&lt;/p&gt;&#xA;&lt;p&gt;After &lt;a href=&#34;https://fly.io/docs/hands-on/sign-in/&#34;&gt;sign-in&lt;/a&gt; to your account, you can launch your application using:&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 launch&#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;You will be asked a few questions. Answer them and wait. This may take a few minutes to finish. If no errors happen, you will see a message with an internal URL provided by fly.io:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Visit your newly deployed app at https://xxxxxxxxx.fly.dev/&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now you already have Gancio up and running! It is time to configure your domain and create your first admin user.&lt;/p&gt;&#xA;&lt;h2 id=&#34;domain-configuration&#34;&gt;&#xA;    &lt;a href=&#34;#domain-configuration&#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;    Domain configuration&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;To get the IPs your application server is using, use 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 ips list&#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;You will get a result like the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;configure DNS to point to these IPs with your domain&#xA;&#xA;v6      xxxx:xxxx:x::xx:xxxx  public (dedicated)  global  51s ago&#xA;v4      xx.xxx.xxx.xxx        public (shared)             Jan 1 0001 00:00&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Configure a &lt;code&gt;A&lt;/code&gt; record (v4) and a &lt;code&gt;AAAA&lt;/code&gt; record (v6) in your DNS hosting with your domain. After you change that, it may take minutes (or hours) to be able to access it.&lt;/p&gt;&#xA;&lt;p&gt;Now it is time to configure the SSL certificates (don&amp;rsquo;t forget to replace the command with your real domain):&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;flyctl certs create your.domain.com&#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;And we are done! Your domain is configured and you can securely access your application.&lt;/p&gt;&#xA;&lt;h2 id=&#34;admin-user&#34;&gt;&#xA;    &lt;a href=&#34;#admin-user&#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;    Admin user&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Now we need an admin user to manage our instance. Gancio provides a &lt;a href=&#34;https://gancio.org/usage/cli&#34;&gt;CLI&lt;/a&gt; that allows us to manage our calendar, approve events, etc.&lt;/p&gt;&#xA;&lt;p&gt;Open our application container console:&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 ssh console -C bash&#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;s&#xA;The CLI binary is located at &lt;code&gt;/usr/local/bin/gancio&lt;/code&gt;. Inside the container, create a new user using:&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;/usr/local/bin/gancio users create your@email.com yourpassword --admin&#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;Now you can login using &lt;code&gt;your@email.com&lt;/code&gt; as username and &lt;code&gt;yourpassword&lt;/code&gt; as password (change the values with the ones you want to use).&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Now you are ready to use Gancio!&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;maintenance&#34;&gt;&#xA;    &lt;a href=&#34;#maintenance&#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;    Maintenance&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;After deploying the application, follow their &lt;a href=&#34;https://mastodon.cisti.org/@gancio&#34;&gt;mastodon account&lt;/a&gt; so you can be notified about new versions of Gancio.&lt;/p&gt;&#xA;&lt;p&gt;To deploy a new version, you just need to use 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 deploy&#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;This command will rebuild your container and publish the latest version of Gancio.&lt;/p&gt;&#xA;&lt;p&gt;Before doing that, it is highly recommended to do a backup of the current state of the application. As we are keeping all the relevant files in a persistent volume from fly.io you can simply copy the files from there to your local computer.&lt;/p&gt;&#xA;&lt;p&gt;Unfortunately, there is not a simple command to copy an entire volume from a fly.io volume. The solution I am using now, is to connect into the container, create a tar file of the &lt;code&gt;/data/&lt;/code&gt; directory, and use &lt;a href=&#34;https://fly.io/docs/flyctl/sftp/&#34;&gt;SFTP&lt;/a&gt; to copy it locally.&lt;/p&gt;&#xA;&lt;p&gt;If I find a better solution to perform backups, I will update this post. If you find anything that doesn&amp;rsquo;t work anymore, please let me know and I will fix the post.&lt;/p&gt;&#xA;</description>
      </item>
  </channel>
</rss>