<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Chris LaPointe</title>
    <description>Another site of Code
</description>
    <link>https://www.zdyn.net/</link>
    <atom:link href="https://www.zdyn.net/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Fri, 05 May 2023 01:30:10 +0000</pubDate>
    <lastBuildDate>Fri, 05 May 2023 01:30:10 +0000</lastBuildDate>
    <generator>Jekyll v2.5.3</generator>
    
      <item>
        <title>Virtual PDF Network Printer</title>
        <description>&lt;p&gt;For my &lt;a href=&quot;https://github.com/paperless-ngx/paperless-ngx&quot;&gt;paperless-ngx&lt;/a&gt; install, I wanted to be able to easily &amp;quot;print&amp;quot;
to it from anywhere in my network.  I find this is slightly easier than logging in to the interface or dragging/dropping
to the &lt;code&gt;consume&lt;/code&gt; folder for some docs.&lt;/p&gt;

&lt;p&gt;One of the hardest parts of this setup was making the printer available on the network and visible accepting postscript.&lt;/p&gt;

&lt;h2&gt;Quick Install&lt;/h2&gt;

&lt;p&gt;The fastest way to get this running is to check out the repo &lt;a href=&quot;https://github.com/zix99/virtual-cups-printer&quot;&gt;cups-virtual-printer&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Explanation&lt;/h3&gt;

&lt;p&gt;This system is composed of two parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cupsd printer with &lt;code&gt;printer-driver-cups-pdf&lt;/code&gt; configured to output to &lt;code&gt;/mnt/output&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;avahi-daemon&lt;/code&gt;, configured to use a custom &lt;code&gt;service&lt;/code&gt; file and with dbus disabled (it&amp;#39;d work with dbus, but one less dependency!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, the docker container needed to be configured with &lt;code&gt;macvlan&lt;/code&gt; so that the container had a &amp;quot;real&amp;quot; IP and
was able to expose avahi discovery on the network.&lt;/p&gt;

&lt;h3&gt;Compose file&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/zix99/virtual-cups-printer&quot;&gt;cups-virtual-printer&lt;/a&gt; docker image&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;3.4&amp;quot;&lt;/span&gt;
&lt;span class=&quot;l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;printserver&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;cups-vlan&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;/tmp/output:/mnt/output&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;631:631&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Expose HTTP server&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;cups-vlan&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;macvlan&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;driver_opts&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;eth0&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Update as necessary&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;ipam&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;subnet&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;192.168.0.0/24&amp;quot;&lt;/span&gt;
          &lt;span class=&quot;l-Scalar-Plain&quot;&gt;ip_range&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;192.168.0.12/32&amp;quot;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#static IP&lt;/span&gt;
          &lt;span class=&quot;l-Scalar-Plain&quot;&gt;gateway&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;192.168.0.1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The hardest part of this setup was figuring out all the configuration to make the system work as expected. After that a lot
of trial and error, the service now works reliably. I use it to write a pdf to the consume-directory of my
paperless-ngx installation, which then ingests the file.&lt;/p&gt;
</description>
        <pubDate>Thu, 04 May 2023 00:00:00 +0000</pubDate>
        <link>https://www.zdyn.net/docker/2023/05/04/virtual-printer.html</link>
        <guid isPermaLink="true">https://www.zdyn.net/docker/2023/05/04/virtual-printer.html</guid>
        
        <category>docker</category>
        
        <category>cookbooks</category>
        
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Home-Assistant Doorbell</title>
        <description>&lt;p&gt;The end of this year I wanted to finally get a video doorbell that I could hook up to home-assistant.&lt;/p&gt;

&lt;p&gt;I had a few requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The doorbell would be able to operate completely offline, with no cloud services. This is partially because the big companies have started handing over your videos without a warrent or your permission if asked, which is ripe for both official and non-official abuse&lt;/li&gt;
&lt;li&gt;There was home-assistant integration, with video stream and doorbell button integration&lt;/li&gt;
&lt;li&gt;Didn&amp;#39;t break the bank&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;The Options&lt;/h2&gt;

&lt;p&gt;Because of the requirements, that quickly ruled out a lot of the mainstream doorbells.  What was left, was two options:&lt;/p&gt;

&lt;h3&gt;The Eufy Doorbell with Home Base&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://www.amazon.com/eufy-Security-Battery-Powered-Detection-Recognition/dp/B099RX62SC&quot;&gt;Amazon Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Eufy was a contender because of its features, but spoiler alert -- I ultimately went with the Amcrest.&lt;/p&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Locally hosted, with storage in base station&lt;/li&gt;
&lt;li&gt;Decent app, got good reviews&lt;/li&gt;
&lt;li&gt;Home assistant integration (Though lacking some features)&lt;/li&gt;
&lt;li&gt;Base station can act as chime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Base station storage is encrypted in a way that only the app can access&lt;/li&gt;
&lt;li&gt;Video streaming to HA seemed hacky at best, and a lot of forum posts seemed to suggest it didn&amp;#39;t work (at time of writing)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Amcrest AD410 (or AD110)&lt;/h3&gt;

&lt;p&gt;Ultimately I landed on the &lt;a href=&quot;https://a.co/d/cTsmBkc&quot;&gt;Amcrest AD410&lt;/a&gt;.  Though it had its own drawbacks, the pros outweighted the cons for me.&lt;/p&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RTSP stream and working home-assistant integration (Though more on that later)&lt;/li&gt;
&lt;li&gt;Decent app that&amp;#39;s easy to access, as long as you&amp;#39;re okay with it having internet access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Could only wire up to an existing chime, which I didn&amp;#39;t have.

&lt;ul&gt;
&lt;li&gt;Work-around: I opted for using home-assistant to send a text and chime with my google home&amp;#39;s&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Storage was in the doorbell itself (SD Card), so if stolen, storage gone too.

&lt;ul&gt;
&lt;li&gt;Work-around: At least it&amp;#39;s encrypted, and I worked around that by using home-assistant to store images elsewhere&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;A Note on Hookup&lt;/h4&gt;

&lt;p&gt;One thing that made me nervous online was a lot of reviews claiming if you wired it up wrong, you&amp;#39;d end up shorting and breaking it.  A lot of this had to do with if you wired it directly to the doorbell transformer, and during the install process, set up a chime (either analog or digital).  This ultimately caused the button to create a short and it&amp;#39;d fry.&lt;/p&gt;

&lt;p&gt;When I installed it, they had made the app a lot clearer.  By default, it didn&amp;#39;t even have you set up a chime.  Just be careful, and don&amp;#39;t set up a chime if you don&amp;#39;t have one!&lt;/p&gt;

&lt;h2&gt;The Software&lt;/h2&gt;

&lt;h3&gt;First Try&lt;/h3&gt;

&lt;p&gt;When I started, I first used &lt;a href=&quot;https://github.com/dchesterton/amcrest2mqtt&quot;&gt;amcrest2mqtt&lt;/a&gt;.  This worked for a while, but I noticed it would have a weird bug where after a while it would disconnect some fetures (eg. the doorbell-button press) and then fail to reconnect.  This was obviously frustrating because, with my setup, it basically meant the doorbell had stopped functioning as a doorbell.&lt;/p&gt;

&lt;p&gt;I did dig into the code a bit, but I suspected that if the core async loop threw an exception it&amp;#39;d stop the loop but not the application, so it wouldn&amp;#39;t auto-restart.  I&amp;#39;m not super familiar with python&amp;#39;s &lt;code&gt;asyncio&lt;/code&gt;, so I wasn&amp;#39;t sure.&lt;/p&gt;

&lt;h3&gt;Write my Own&lt;/h3&gt;

&lt;p&gt;I took this as an opportunity to reverse engineer the above and write something in go, which I hoped was more stable.  This led to &lt;a href=&quot;https://github.com/zix99/ha-adapters&quot;&gt;ha-adapters&lt;/a&gt; to connect devices to MQTT, and ultimately home-assistant.&lt;/p&gt;

&lt;p&gt;After install and setup, there should be various sensors that show up on home-assistant immediately, with the exception of the RTSP camera which needs to be set up in the UI.&lt;/p&gt;

&lt;p&gt;At this point, it&amp;#39;s been running for several months with no issues.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;At this point, I&amp;#39;m stil happy with the AD410.  It&amp;#39;s weather about a year in the Northeast US (Cold), and with one exception when it dropped below 10F, has worked fine.  Human and motion detection works great, and I have it hooked up to my home-assistant instance in various ways.&lt;/p&gt;
</description>
        <pubDate>Wed, 05 Oct 2022 00:00:00 +0000</pubDate>
        <link>https://www.zdyn.net/hardware/home-automation/2022/10/05/video-doorbell.html</link>
        <guid isPermaLink="true">https://www.zdyn.net/hardware/home-automation/2022/10/05/video-doorbell.html</guid>
        
        
        <category>hardware</category>
        
        <category>home-automation</category>
        
      </item>
    
      <item>
        <title>Rare: 0.3.0</title>
        <description>&lt;h1&gt;Rare 0.3.0&lt;/h1&gt;

&lt;p&gt;Read 0.2.0 notes &lt;a href=&quot;/projects/2021/07/11/rare-0.2.0.html&quot;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/zix99/rare&quot;&gt;rare&lt;/a&gt; launched version &lt;code&gt;0.3.0&lt;/code&gt; this week which brings some bug fixes, significant performance improvements in key scenarios, as well as a new aggregator: heatmaps!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2022-10-01-rare-0.3.0/rare.gif&quot; alt=&quot;Rare 0.3&quot;&gt;&lt;/p&gt;

&lt;h2&gt;New Features&lt;/h2&gt;

&lt;p&gt;There are two major new features&lt;/p&gt;

&lt;h3&gt;New Aggregator: Heatmaps!&lt;/h3&gt;

&lt;p&gt;Heatmaps were added to allow displaying a dense visualization of strength of a value at a given 1D or 2D
key.  It&amp;#39;s similar to a table where each cell is the strength of the value at that value.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2022-10-01-rare-0.3.0/heatmap.gif&quot; alt=&quot;Rare Heatmap&quot;&gt;&lt;/p&gt;

&lt;h3&gt;Testing Expressions&lt;/h3&gt;

&lt;p&gt;Rare now has the ability to test, analyze, and benchmark expressions without running an aggregator with the &lt;code&gt;expression&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./rare expression -d &lt;span class=&quot;m&quot;&gt;15&lt;/span&gt; -d &lt;span class=&quot;m&quot;&gt;20&lt;/span&gt; -k &lt;span class=&quot;nv&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;30&lt;/span&gt; -sb &lt;span class=&quot;s2&quot;&gt;&amp;quot;The sum is {sumi {0} {1} {key}}&amp;quot;&lt;/span&gt;
Expression: The sum is &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;sumi &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;key&lt;span class=&quot;o&quot;&gt;}}&lt;/span&gt;
Result:     The sum is 65

Stats
  Stages:        2
  Match Lookups: 2
  Key   Lookups: 1

Benchmark: 163ns &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;6,400,000 iterations in 1.043727002s&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Improvements&lt;/h2&gt;

&lt;p&gt;In addition to the two major features above, there are some significant improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Significantly faster follow-reading files (10x read-rate from 50MB/s to 500MB/s)&lt;/li&gt;
&lt;li&gt;Allow tailing a file in addition to following&lt;/li&gt;
&lt;li&gt;Switch from buffered read-ahead to buffered read-thru allows better responsiveness with similar IO performance&lt;/li&gt;
&lt;li&gt;Better UTF8 read and render support&lt;/li&gt;
&lt;li&gt;Improved sorting arguments across all aggregators for more display control&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Misc Fixes/Bugs&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Functions: Add duration, time attribute function (eg. week number)&lt;/li&gt;
&lt;li&gt;Organize the --help documentation&lt;/li&gt;
&lt;li&gt;Allow single-row tables&lt;/li&gt;
&lt;li&gt;Fix some panics in edge-cases&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Try it out!&lt;/h2&gt;

&lt;p&gt;If you&amp;#39;re interested in trying out are, head over &lt;a href=&quot;https://github.com/zix99/rare&quot;&gt;github&lt;/a&gt; to grab it, or take a look at the &lt;a href=&quot;https://rare.zdyn.net/&quot;&gt;documentation&lt;/a&gt; for more screenshots and examples.&lt;/p&gt;
</description>
        <pubDate>Sat, 01 Oct 2022 00:00:00 +0000</pubDate>
        <link>https://www.zdyn.net/projects/2022/10/01/rare-0.3.0.html</link>
        <guid isPermaLink="true">https://www.zdyn.net/projects/2022/10/01/rare-0.3.0.html</guid>
        
        <category>rare</category>
        
        
        <category>projects</category>
        
      </item>
    
      <item>
        <title>Set up your own mailserver with Maddy</title>
        <description>&lt;p&gt;About a year ago I wanted to expand beyond namecheap&amp;#39;s simple &amp;quot;email forwarding&amp;quot; service and start
setting up my own mailboxes.  At the time, I was looking for a solution that I could host on my
docker swarm (obviously). And the defacto suggestion for a self-hosted solution was
&lt;a href=&quot;https://github.com/docker-mailserver/docker-mailserver&quot;&gt;docker-mailserver&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That solution worked for a while, but was relatively resource hungry.  It&amp;#39;s based a &amp;quot;recommended
email solution in a box&amp;quot; with all the bells and whistles.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s also worth noting that if you&amp;#39;re going down the road of setting up your own mailserver, that
&lt;a href=&quot;https://mxtoolbox.com/&quot;&gt;mxtoolbox&lt;/a&gt; is invaluable for testing your server and DNS configuration. I don&amp;#39;t
think I could&amp;#39;ve gotten this far without them.&lt;/p&gt;

&lt;h2&gt;The Road to Maddy&lt;/h2&gt;

&lt;p&gt;This month I did another search to see if anything else came up recently, and discovered &lt;a href=&quot;https://maddy.email/&quot;&gt;maddy&lt;/a&gt;. While
their solution targets smaller deployments, it was &lt;em&gt;significantly&lt;/em&gt; easier to setup. Their configuration is in a single volume,
and setup involves basically spinning up, creating TLS certs, and setting up DKIM (And other records) in your DNS. On top of that,
it seems to cap out around 15 MB of memory!&lt;/p&gt;

&lt;p&gt;Given that I already had experience setting up a mailserver before, this took me only a few hours to get fully working.&lt;/p&gt;

&lt;p&gt;I use &lt;a href=&quot;https://www.rainloop.net/&quot;&gt;rainloop&lt;/a&gt; as my webmail deployment.&lt;/p&gt;

&lt;h2&gt;Docker Compose&lt;/h2&gt;

&lt;p&gt;I use my mail setup on my same swarm that has &lt;a href=&quot;/docker/2021/03/08/traefikv2.html&quot;&gt;traefik&lt;/a&gt; setup on it, so I prefer to reuse
the certificates traefik is grabbing for me.  I do this by using my &lt;code&gt;jq&lt;/code&gt; snippet described &lt;a href=&quot;/docker/2022/02/04/acme-certificate.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;3.5&amp;quot;&lt;/span&gt;
&lt;span class=&quot;l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;maddy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;foxcpp/maddy:latest&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;25:25&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;143:143&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;587:587&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;993:993&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;maddydata:/data&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# REPLACE DOMAINS WITH YOURS&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;MADDY_HOSTNAME=mx.example.com&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;MADDY_DOMAIN=example.com&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;replicas&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;1&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;limits&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;32M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;reservations&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.05&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;16M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Hit /?admin for setup&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Webmail&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;rainloop&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;hardware/rainloop&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.docker.network=traefik-net&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.rainloop.rule=Host(`mail.example.com`)&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.services.rainloop.loadbalancer.server.port=8888&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.rainloop.entrypoints=websecure&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;limits&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;64M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;reservations&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.05&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;32M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;rainloop-data:/rainloop/data&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;default&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Synchronize certificates from traefik/acme.json to maddy every 24 hours&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;certsync&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;stedolan/jq&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;entrypoint&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;/bin/bash -c &amp;quot;&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;jq -r &amp;#39;.le.Certificates[] | select(.domain.main==\&amp;quot;&amp;#39;mx.example.com&amp;#39;\&amp;quot;) | .certificate&amp;#39; /data/acme.json | base64 -d &amp;gt; /out/tls_cert.pem;&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;jq -r &amp;#39;.le.Certificates[] | select(.domain.main==\&amp;quot;&amp;#39;mx.example.com&amp;#39;\&amp;quot;) | .key&amp;#39; /data/acme.json | base64 -d &amp;gt; /out/tls_key.pem;&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;common_letsencrypt:/data:ro&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;maddydata:/out&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;global&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;placement&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;constraints&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;node.role==manager&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;restart_policy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;24h&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;limits&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;32M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;reservations&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.025&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;16M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# The network that can talk to traefik&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;maddydata&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;rainloop-data&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;common_letsencrypt&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Wherever you store your acme.json file from traefik&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        <pubDate>Thu, 10 Feb 2022 00:00:00 +0000</pubDate>
        <link>https://www.zdyn.net/docker/2022/02/10/maddy-mailserver.html</link>
        <guid isPermaLink="true">https://www.zdyn.net/docker/2022/02/10/maddy-mailserver.html</guid>
        
        <category>docker</category>
        
        <category>cookbooks</category>
        
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Extracting a Certificate from Traefik/acme.json</title>
        <description>&lt;p&gt;It&amp;#39;s a fairly common need to extract a certificate and key
from traefik to use it for other reasons. In my case, I needed to grab
a certificate for an existing domain and use it for my mail-server.&lt;/p&gt;

&lt;p&gt;There&amp;#39;s a bunch of very complex examples to dump all certificates,
and semi-official &lt;a href=&quot;https://github.com/ldez/traefik-certs-dumper&quot;&gt;traefik-cert-dumper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My method only uses &lt;code&gt;jq&lt;/code&gt; (&lt;a href=&quot;https://stedolan.github.io/jq/&quot;&gt;jq&lt;/a&gt;) in a one-liner.&lt;/p&gt;

&lt;h2&gt;The Snippet&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;jq -r &lt;span class=&quot;s1&quot;&gt;&amp;#39;.le.Certificates[] | select(.domain.main==\&amp;quot;&amp;#39;&lt;/span&gt;example.com&lt;span class=&quot;s1&quot;&gt;&amp;#39;\&amp;quot;) | .certificate&amp;#39;&lt;/span&gt; /data/acme.json &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; base64 -d &amp;gt; /out/tls_cert.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This should be fairly self-explanatory, but it extracts the certificate of &lt;code&gt;example.com&lt;/code&gt; and decodes the base64.&lt;/p&gt;

&lt;p&gt;To extract the key, simply change the last &lt;em&gt;jq&lt;/em&gt; expression &lt;code&gt;.certificate&lt;/code&gt; to &lt;code&gt;.key&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;As a scheduled docker service&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;3.5&amp;quot;&lt;/span&gt;
&lt;span class=&quot;l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;certsync&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;stedolan/jq&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Dumps both certificate and key for &amp;quot;example.com&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;entrypoint&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;/bin/bash -c &amp;quot;&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;jq -r &amp;#39;.le.Certificates[] | select(.domain.main==\&amp;quot;&amp;#39;example.com&amp;#39;\&amp;quot;) | .certificate&amp;#39; /data/acme.json | base64 -d &amp;gt; /out/tls_cert.pem;&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;jq -r &amp;#39;.le.Certificates[] | select(.domain.main==\&amp;quot;&amp;#39;example.com&amp;#39;\&amp;quot;) | .key&amp;#39; /data/acme.json | base64 -d &amp;gt; /out/tls_key.pem;&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;common_letsencrypt:/data:ro&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Mount traefik volume as read-only&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;out:/out&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# And whichever volume you want to output on&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;global&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;placement&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;constraints&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;node.role==manager&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Only run on the manager node (Where traefik and its volume exists)&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;restart_policy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;24h&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Re-run every 24 hours&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;limits&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;32M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;reservations&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.025&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;16M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        <pubDate>Fri, 04 Feb 2022 00:00:00 +0000</pubDate>
        <link>https://www.zdyn.net/docker/2022/02/04/acme-certificate.html</link>
        <guid isPermaLink="true">https://www.zdyn.net/docker/2022/02/04/acme-certificate.html</guid>
        
        <category>docker</category>
        
        <category>cookbooks</category>
        
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Docker Samba / CIFS Volume (Photoview)</title>
        <description>&lt;p&gt;Recently I had a need to mount a CIFS volume as a docker volume: The summary is that I wanted
to use &lt;a href=&quot;https://github.com/photoview/photoview&quot;&gt;photoview&lt;/a&gt; to index photos on my NAS.  This led
to a lot of google searching, which ultimately told me it was perfectly possible, but not a lot
of detail on the how.&lt;/p&gt;

&lt;h2&gt;Requirements&lt;/h2&gt;

&lt;p&gt;If you&amp;#39;re on linux, make sure to: &lt;code&gt;sudo apt-get install cifs-utils&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;Word of Warning&lt;/h2&gt;

&lt;p&gt;The biggest difference between doing this in docker and using a simple &lt;code&gt;mount -t cifs&lt;/code&gt; is that
the docker mount point &lt;strong&gt;must be the IP address&lt;/strong&gt; and can&amp;#39;t be the hostname.  Some googling
eventually told me that this may be due to restrictions in the kernel, but I haven&amp;#39;t verified myself.&lt;/p&gt;

&lt;h2&gt;Example&lt;/h2&gt;

&lt;h3&gt;Command&lt;/h3&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;docker volume create &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  --driver &lt;span class=&quot;nb&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  --opt &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;cifs
  --opt &lt;span class=&quot;nv&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;//192.168.8.103/public &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# IMPORTANT: This must be an IP, can&amp;#39;t be a hostname&lt;/span&gt;
  --opt &lt;span class=&quot;s2&quot;&gt;&amp;quot;o=username=guest,password=guest&amp;quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  cifstest

docker run -it --rm -v cifstest:/mnt busybox
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;docker-compose&lt;/h3&gt;

&lt;p&gt;And bonus photoview docker-compose stack behind traefik!&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;3.5&amp;#39;&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;photoview&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;viktorstrate/photoview:2&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;always&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-bridge&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;db:/app/db&lt;/span&gt;
            &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;cache:/app/cache&lt;/span&gt;
            &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;photos:/photos&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;PHOTOVIEW_DATABASE_DRIVER=sqlite&lt;/span&gt;
            &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;PHOTOVIEW_SQLITE_PATH=/app/db/photoview.db&lt;/span&gt;
            &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;PHOTOVIEW_LISTEN_PORT=80&lt;/span&gt;
            &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;PHOTOVIEW_MEDIA_CACHE=/app/cache&lt;/span&gt;
            &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;MAPBOX_TOKEN=xxx&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.photoview.rule=Host(`photoview`)&amp;quot;&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{}&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{}&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;photos&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;local&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;driver_opts&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;l-Scalar-Plain&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;cifs&lt;/span&gt;
            &lt;span class=&quot;l-Scalar-Plain&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;//192.168.8.131/public&lt;/span&gt;
            &lt;span class=&quot;l-Scalar-Plain&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;username=guest,password=guest,ro&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-bridge&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;See Also&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;https://forums.docker.com/t/docker-volume-create-with-local-cifs-driver/41226&lt;/li&gt;
&lt;li&gt;https://github.com/moby/moby/pull/39250&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 12 Jul 2021 00:00:00 +0000</pubDate>
        <link>https://www.zdyn.net/docker/2021/07/12/docker-cifs.html</link>
        <guid isPermaLink="true">https://www.zdyn.net/docker/2021/07/12/docker-cifs.html</guid>
        
        <category>docker</category>
        
        <category>cookbooks</category>
        
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Rare: 0.2.0</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://rare.zdyn.net&quot;&gt;rare&lt;/a&gt; &lt;code&gt;0.2.0&lt;/code&gt; launches today, which brings numerous features, significantly better documentation, and some performance improvements.&lt;/p&gt;

&lt;h2&gt;Key Changes&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;New documentation site at &lt;a href=&quot;https://rare.zdyn.net&quot;&gt;rare.zdyn.net&lt;/a&gt; hosted by netlify, and generated via &lt;a href=&quot;https://www.mkdocs.org/&quot;&gt;mkdocs&lt;/a&gt;, using same markdown that&amp;#39;s embedded in rare&lt;/li&gt;
&lt;li&gt;Output match-data as json&lt;/li&gt;
&lt;li&gt;Numerous new expressions, including color-coding and custom rendering&lt;/li&gt;
&lt;li&gt;Arm64 support&lt;/li&gt;
&lt;li&gt;Numerous bug-fixes and ease-of-use fixes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Changelog&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;448b0ec Add ability to do some simple coloring/drawing with expressions. Support escaping (#52)
2f5ebaa Add ignore-case modifier flag for ease of use
2397fa4 Allow outputing matched data as json (#51)
eaeb6bb Batcher cleanup (#54)
26c424a Break out bytesize to humanize, add some features, expand to expression lib
3654616 Create mkdocs site, and reorganize some of the doc files (#53)
da708e6 Display read bytes and read-rate (#55)
79b154e Doc fixes (#49)
0bd7f6d Doc tweaks
cbcd424 Faster string-select lookup and null-rune recognition
380764c Fix PCRE panic when filter has no expression
5c70a29 Fix bytesize test
ba59e52 Fix embedded docs on windows
97d690f If fail to read input as gzip, rewind to get entire file as plain text
0eb2b09 Not google analytics (On mkdocs site)
545f909 Performance bump (#56)
afe912c Readme tweaks
b2b463b Strconv is much faster than printer
bed0fb4 Update README.md (#47)
e5b48cb Use default pager when outputting docs
2000129 Useability 3 (#50)
8213b35 Build arm64 version
dc90df1 Filter delim (#42)
f9a464e Fix manpage path
a444c98 Implement exit codes to signal exit states (#43)
22b0a34 Introduce some better code for term size (#44)
ce59a7e Manpage generation and packaging (#45)
efaee25 Docs website
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        <pubDate>Sun, 11 Jul 2021 00:00:00 +0000</pubDate>
        <link>https://www.zdyn.net/projects/2021/07/11/rare-0.2.0.html</link>
        <guid isPermaLink="true">https://www.zdyn.net/projects/2021/07/11/rare-0.2.0.html</guid>
        
        <category>rare</category>
        
        
        <category>projects</category>
        
      </item>
    
      <item>
        <title>Self-Hosted Analytics: Docker &amp; Privacy-First</title>
        <description>&lt;p&gt;I have a lot of little sites. Probably too many.  Includes various personal sites, sites for friends and family, and random projects I&amp;#39;m doing.  They&amp;#39;re scattered across the internet: Some are hosted here on my swarm, some on netlify, some on surge.sh.. and the list goes on.  Google analytics is &amp;quot;fine&amp;quot;. It works, and provides the basic features I need (along with a bajillion I usually don&amp;#39;t).  Frankly, I&amp;#39;ll probably keep using google-analytics for my more professional things, but I needed something super simple that was easy to spin up and down for each little site to give me a glimpse into if anyone was looking at them.  There&amp;#39;s also the whole google privacy concern.&lt;/p&gt;

&lt;p&gt;I looked at &lt;a href=&quot;https://goaccess.io/&quot;&gt;goaccess&lt;/a&gt; a bit, but now that I have things on these CDN-focused services (eg netlify), I really needed something that allowed js-snippet style analytics.  Yes, I know there are tricks to getting goaccess to work with pixels, but it&amp;#39;s not really what it was meant for, and isn&amp;#39;t able to slice and dice quite in an analytics-focused way (eg, break down by virtual host).&lt;/p&gt;

&lt;p&gt;So, the search began...&lt;/p&gt;

&lt;h2&gt;Goals&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lightweight and fast. I don&amp;#39;t have that much traffic, and don&amp;#39;t want a giant service running&lt;/li&gt;
&lt;li&gt;Open source / self-hostable&lt;/li&gt;
&lt;li&gt;Respects privacy. Doesn&amp;#39;t collect overly obtrusive details on users&lt;/li&gt;
&lt;li&gt;Dockerized / Swarmable&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Resources&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s be frank, this was about 80% googling, but I did find two lists that were super helpful.&lt;/p&gt;

&lt;p&gt;Florens Verschelde has a good article on his own experiences: https://fvsch.com/small-analytics&lt;/p&gt;

&lt;p&gt;A complete and unopinionated list of stats software: https://github.com/0xnr/awesome-analytics&lt;/p&gt;

&lt;h2&gt;Options I Evaluated&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Many of the options below contain example swarm-compatible compose files.  Many of these were used for testing purposes, but are not fully built out (Meaning they often don&amp;#39;t have volumes or any sort of persistence).  Feel free to use them as a baseline, but please see their website setup docs.&lt;/p&gt;

&lt;h3&gt;Plausible&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Site:&lt;/strong&gt; https://github.com/plausible/analytics&lt;br&gt;
&lt;strong&gt;Stars:&lt;/strong&gt; 8.1k&lt;br&gt;
&lt;strong&gt;Language:&lt;/strong&gt; Elixir&lt;br&gt;
&lt;strong&gt;DB:&lt;/strong&gt; Postgres and clickhouse&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overall, it seems to use 3-5 containers to run, and so is a little too heavy weight.&lt;/li&gt;
&lt;li&gt;After spending much more time to setup that I wanted, I moved on to the next...&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Fathom&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Site:&lt;/strong&gt; https://github.com/usefathom/fathom&lt;br&gt;
&lt;strong&gt;Stars:&lt;/strong&gt; 6.9k&lt;br&gt;
&lt;strong&gt;Language:&lt;/strong&gt; GO&lt;br&gt;
&lt;strong&gt;DB:&lt;/strong&gt; Sqlite or Postgres&lt;br&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; ~20MB&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nice and light, sqllite DB by default or can upgrade.&lt;/li&gt;
&lt;li&gt;Very basic metrics (Visitors/uniques over time).&lt;/li&gt;
&lt;li&gt;Can&amp;#39;t see other info like geography/language.&lt;/li&gt;
&lt;li&gt;No commit since Feb 2020, and even longer since a commit with substance&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Docker Compose&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;3.5&amp;quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Note, if this is a new image, must run fathom&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# as an instance and run ./fathom user add ...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# see their docs&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;fathom&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;usefathom/fathom:latest&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;fathom:/var/fathom&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;FATHOM_DATABASE_NAME&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;/var/fathom/fathom.db&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.docker.network=traefik-net&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.fathom.rule=Host(`fathom.${HOST}`)&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.services.fathom.loadbalancer.server.port=8080&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.fathom.entrypoints=websecure&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;limits&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;64M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;reservations&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.05&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;64M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;fathom&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Umami&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Github:&lt;/strong&gt; https://github.com/mikecao/umami&lt;br&gt;
&lt;strong&gt;Site:&lt;/strong&gt; https://umami.is/&lt;br&gt;
&lt;strong&gt;DB:&lt;/strong&gt; Postgres or MySQL&lt;br&gt;
&lt;strong&gt;Lang:&lt;/strong&gt; Nodejs 10.3+&lt;br&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; 100-150 MB + DB (20-80MB)&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A little bit heavier on the memory&lt;/li&gt;
&lt;li&gt;Has all the features I&amp;#39;m looking for&lt;/li&gt;
&lt;li&gt;I like the style of the UI, easy to integrate with&lt;/li&gt;
&lt;li&gt;Active developers&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Docker Compose&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;3.5&amp;quot;&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;umami&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;ghcr.io/mikecao/umami:postgresql-latest&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;default&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;db&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;postgresql://umami:replace-me@db:5432/umami&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;DATABASE_TYPE&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;postgresql&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;HASH_SALT&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;replace-me&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.docker.network=traefik-net&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.umami.rule=Host(`stats.${HOST}`)&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.services.umami.loadbalancer.server.port=3000&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.umami.entrypoints=websecure&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;limits&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;128M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;reservations&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.05&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;128M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;postgres:12-alpine&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;POSTGRES_DB&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;umami&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;POSTGRES_USER&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;umami&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;replace-me&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;default&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;configs&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;umami-schema&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;/docker-entrypoint-initdb.d/schema.postgresql.sql&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;umami-db:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;limits&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;64M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;reservations&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.05&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;64M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;configs&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;umami-schema&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;umami-schema-${NOW}&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;config/umami.schema.sql&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;umami-db&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Shynet&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Github:&lt;/strong&gt; https://github.com/milesmcc/shynet&lt;br&gt;
&lt;strong&gt;Stars:&lt;/strong&gt; 1.4k&lt;br&gt;
&lt;strong&gt;DB:&lt;/strong&gt; Postgres&lt;br&gt;
&lt;strong&gt;Language:&lt;/strong&gt; Python&lt;br&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; ~60-80 MB + DB&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mid-memory usage&lt;/li&gt;
&lt;li&gt;UI is okay, but not my favorite&lt;/li&gt;
&lt;li&gt;Development on it is semi-active&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Docker Compose&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;3.5&amp;#39;&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;shynet&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;milesmcc/shynet:latest&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;env_file&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;shynet.env&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Config from their site&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;DB_HOST=db&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;default&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;db&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.docker.network=traefik-net&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.shynet.rule=Host(`stats.${HOST}`)&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.services.shynet.loadbalancer.server.port=8080&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.shynet.entrypoints=websecure&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;postgres:alpine&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;always&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;POSTGRES_USER=shynet&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;POSTGRES_PASSWORD=shynet&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;POSTGRES_DB=shynet&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#volumes:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#  - shynet_db:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;default&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;#volumes:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#  shynet_db:&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Ackee&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Github:&lt;/strong&gt; https://github.com/electerious/Ackee&lt;br&gt;
&lt;strong&gt;Site:&lt;/strong&gt; https://ackee.electerious.com/&lt;br&gt;
&lt;strong&gt;Stars:&lt;/strong&gt; 2.6k&lt;br&gt;
&lt;strong&gt;Language:&lt;/strong&gt; Nodejs&lt;br&gt;
&lt;strong&gt;DB:&lt;/strong&gt; Mongo&lt;br&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; 125-175MB (Ackee) + 60-80 MB (Mongo)&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Has the features I like&lt;/li&gt;
&lt;li&gt;UI looks nice&lt;/li&gt;
&lt;li&gt;Heaviest of the group on memory usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Docker Compose&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;3.5&amp;quot;&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;ackee&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;electerious/ackee&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;WAIT_HOSTS=mongo:27017&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;ACKEE_MONGODB=mongodb://mongo:27017/ackee&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;ACKEE_USERNAME=username&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;ACKEE_PASSWORD=password&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;mongo&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;default&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.docker.network=traefik-net&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.shynet.rule=Host(`stats.${HOST}`)&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.services.shynet.loadbalancer.server.port=3000&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.shynet.entrypoints=websecure&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;mongo&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;mongo&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#volumes:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#  - ./data:/data/db&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Goatcounter&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Github:&lt;/strong&gt; https://github.com/zgoat/goatcounter&lt;br&gt;
&lt;strong&gt;Site:&lt;/strong&gt; https://www.goatcounter.com/&lt;br&gt;
&lt;strong&gt;Stars:&lt;/strong&gt; 2.1k&lt;br&gt;
&lt;strong&gt;Language:&lt;/strong&gt; Go&lt;br&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; ~25 MB&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No official docker container (And an okay community contributed one)&lt;/li&gt;
&lt;li&gt;Doesn&amp;#39;t handle multiple domains well (At best, it&amp;#39;s a hack that puts the domain in the paths)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Docker Compose&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;3.5&amp;#39;&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;goatcounter&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;baethon/goatcounter:1.4&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 2.0 (latest) is broken right now&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;GOATCOUNTER_DOMAIN&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;stats.s0.zdyn.net&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;GOATCOUNTER_EMAIL&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;test@example.com&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;GOATCOUNTER_PASSWORD&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;testtest&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Would need volume for: sqlite:///goatcounter/db/goatconter.sqlite3&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.docker.network=traefik-net&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.shynet.rule=Host(`stats.${HOST}`)&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.services.shynet.loadbalancer.server.port=8080&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.shynet.entrypoints=websecure&amp;quot;&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;What I Picked&lt;/h2&gt;

&lt;p&gt;Initially I picked Fathom, because it was super light weight (Only used 20 MB in testing), supported SQLite, which is great in low-volume situations, and was super easy to spin up and use in docker.  That said, it missed some really key features such as device, country, and browser.  It&amp;#39;s also woefully out of date and shows no signs of being updated ever again.&lt;/p&gt;

&lt;p&gt;Right now, &lt;strong&gt;I&amp;#39;m using Umami&lt;/strong&gt;, and I&amp;#39;m pretty happy with it.  It&amp;#39;s a little hefty compared to fathom on the resource front (~150 MB total, compared to fathom&amp;#39;s 20MB of memory), but at the end of the day that&amp;#39;s not that excessive, and it has all the features I was looking for.  I&amp;#39;ll keep testing both of them out a bit, and update if I have any further thoughts.&lt;/p&gt;
</description>
        <pubDate>Fri, 02 Jul 2021 00:00:00 +0000</pubDate>
        <link>https://www.zdyn.net/docker/2021/07/02/simple-analytics.html</link>
        <guid isPermaLink="true">https://www.zdyn.net/docker/2021/07/02/simple-analytics.html</guid>
        
        <category>docker</category>
        
        <category>cookbooks</category>
        
        
        <category>docker</category>
        
      </item>
    
      <item>
        <title>Rare: Introducing PCRE2 support</title>
        <description>&lt;p&gt;Following up from my original post &lt;a href=&quot;/projects/2019/11/17/rare.html&quot;&gt;introducing rare&lt;/a&gt;, I paused development for a bit as it suited my need for a while, but recently restarted as I felt like its biggest flaw was resolvable.&lt;/p&gt;

&lt;h1&gt;What is rare?&lt;/h1&gt;

&lt;p&gt;As a quick recap of the previous post, &lt;code&gt;rare&lt;/code&gt; is a realtime regex extractor and evaluator.  This allows you to visualize data from a mass of text files (eg. log files) quickly and while the scan is in-progress. It includes visualizations like bargraphs, histograms, tables, and simple filter (grep-like).&lt;/p&gt;

&lt;p&gt;You can find the source and binary downloads on &lt;a href=&quot;https://github.com/zix99/rare&quot;&gt;github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2021-05-23-rare-pcre/rare.gif&quot; alt=&quot;rare&quot;&gt;&lt;/p&gt;

&lt;h1&gt;The Problem&lt;/h1&gt;

&lt;p&gt;Golang&amp;#39;s implements regex using &lt;a href=&quot;https://en.wikipedia.org/wiki/RE2_(software)&quot;&gt;re2&lt;/a&gt;, which comes with the guarantee that runtime increases linearly with the size of input (as opposed to other algorithms that may increase exponetially).  Exponential algorithms introduces the application to &lt;a href=&quot;https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS&quot;&gt;ReDoS attacks&lt;/a&gt; (Regular Expression Denial of Service Attack), so when the input might be uncontrolled, it&amp;#39;s best to use re2.&lt;/p&gt;

&lt;p&gt;For rare the input is often log files or other data.  And even if the input is uncontrolled, when used as a tool, the user is in control of the execution (And you can always ctrl+c of course).  This means that in most cases this issue should be manageable.&lt;/p&gt;

&lt;h2&gt;Benchmarking re2&lt;/h2&gt;

&lt;p&gt;For a while I worked on optimizing other parts of &lt;em&gt;rare&lt;/em&gt; that I had direct control over. This included optimizing expressions, batching the data going through the channels, and decreasing file io using an optimized read-ahead.&lt;/p&gt;

&lt;p&gt;After all that work, there was really only one thing I could reasonably increasee the performance of (and it was pretty obvious): the regex implementation.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;du -sh testdata/
84M     testdata/ &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;~ 1.5 GB decompressed&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Version ~ 0.2.0-rc.2&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go run . --profile&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;re2 table -z -m &lt;span class=&quot;s2&quot;&gt;&amp;quot;\[(.+?)\].*\&amp;quot; (\d+)&amp;quot;&lt;/span&gt; -e &lt;span class=&quot;s2&quot;&gt;&amp;quot;{buckettime {1} year nginx}&amp;quot;&lt;/span&gt; -e &lt;span class=&quot;s2&quot;&gt;&amp;quot;{bucket {2} 100}&amp;quot;&lt;/span&gt; testdata/*

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go tool pprof -http&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;:8080 re2.cpu.prof
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;/assets/article_images/2021-05-23-rare-pcre/re2.png&quot; alt=&quot;RE2 Flame Chart&quot;&gt;&lt;/p&gt;

&lt;h3&gt;Why?&lt;/h3&gt;

&lt;p&gt;There is of course the question of &amp;quot;why do this at all?&amp;quot;  Let&amp;#39;s be honest, half of this was for fun, and because I could.  The other half is that I always felt that rare lacked performance in certain situations compared to other tools, and being able to improve that was critical to its main use, which is to speed up seeing results of large text queries.&lt;/p&gt;

&lt;h1&gt;PCRE2&lt;/h1&gt;

&lt;p&gt;PCRE2 (libpcre2) is significantly faster for non-trivial regexs.  A simple benchmark shows it can be both faster and use less CPU time by a factor of 4-5x.  It&amp;#39;s also common and popular enough that adoption wouldn&amp;#39;t be an issue.  That led to the next step, which was a proof-of-concept.&lt;/p&gt;

&lt;h2&gt;Implementing PCRE2 in CGO&lt;/h2&gt;

&lt;p&gt;Besides reading up on cgo, much of the port to go is based on the &lt;a href=&quot;https://www.pcre.org/current/doc/html/pcre2demo.html&quot;&gt;pcre2 demo&lt;/a&gt; from the &lt;a href=&quot;https://www.pcre.org/current/doc/html/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Because PCRE2 requires per-instant memory (Stack if JITd, the &lt;code&gt;ovec&lt;/code&gt; result vector, etc), I changed the interface implementation slightly, but try to stick close to &lt;code&gt;re2&lt;/code&gt;&amp;#39;s interface as closely as possible (Matter of fact, re2 can easily implement the interface).  Each goroutine will hold its own instance, but reference the static data (The compiled regex) only once.  To free any created memory, we leverage go&amp;#39;s &lt;code&gt;runtime.SetFinalizer&lt;/code&gt; to cleanup after ourselves.&lt;/p&gt;

&lt;p&gt;You can see the full implementation on &lt;a href=&quot;https://github.com/zix99/rare/blob/a444c98c4194936966c8f3861fe9c5ba0f3f3152/pkg/fastregex/pcre2.go&quot;&gt;github&lt;/a&gt;, but execution effecetively boils down to:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pcre2Regexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FindSubmatchIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;bPtr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;rc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pcre2_match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bPtr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;matchData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;groupCount&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;goOvec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ulong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ovec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ovec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;goOvec&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Benchmarks&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2021-05-23-rare-pcre/pcre.png&quot; alt=&quot;PCRE Flame Chart&quot;&gt;&lt;/p&gt;

&lt;p&gt;As you can see, despite cgo&amp;#39;s overhead, pcre is significantly faster than re2.  With the same test data, pcre computes all the regex&amp;#39;s in 4.14s, and re2 does it in 68.31s.  This evens out the load between the major parts of the program fairly evenly (Aggregation, regex extraction, key-building, and file IO).&lt;/p&gt;

&lt;h2&gt;Shortcomings&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;As mentioned above, PCRE is non-linear, meaning that in some very complex cases that this regex might be slower than re2.  Given what people are usually looking for in log-files, I consider this unlikely.&lt;/li&gt;
&lt;li&gt;PCRE is written as a CGO dependency, meaning that &lt;em&gt;rare&lt;/em&gt; now incurs the &lt;a href=&quot;https://www.cockroachlabs.com/blog/the-cost-and-complexity-of-cgo/&quot;&gt;overhead associated with cgo&lt;/a&gt; because of various &lt;a href=&quot;https://golang.org/cmd/cgo/&quot;&gt;safety and security measures&lt;/a&gt;.  This can be significant per-call, so work has been done to insure that only one C-call happens per regex evaluation by frontloading anything that can be, and delegating this to a new &amp;quot;regex instance&amp;quot; (since we&amp;#39;re often processing text in many go-routines).&lt;/li&gt;
&lt;li&gt;This also means that the binary is now dynamically linked, since it depends on &lt;code&gt;libpcre2-8&lt;/code&gt;, which some consumers might not be used to.  For this reason, we include both pcre and non-pcre versions.&lt;/li&gt;
&lt;li&gt;And lastly, because PCRE is easiest to obtain on linux, we only compile PCRE on linux and continue to maintain a backwards-compatibility layer to go&amp;#39;s RE2 &lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;Bonus: Expression Analysis&lt;/h1&gt;

&lt;p&gt;Albeit smaller, another shortcoming could occur if the user used the expression helper-logic to assist in computing static expressions.  For instance, let&amp;#39;s examine the expression &lt;code&gt;{multi 10 10}&lt;/code&gt;.  This effectively generates a &lt;code&gt;multi&lt;/code&gt; function that takes in 2 static-functions (each with the string-value of &lt;code&gt;10&lt;/code&gt;). So that means each time an expression is evaluated, we have to parse 2 integers, multiple them together, and stringify.&lt;/p&gt;

&lt;p&gt;It obviously doesn&amp;#39;t make sense to do this every time.  Instead, what I did, is when the expression is compiled I pass the expression tree a dummy-context to see if it needs to query the context in order to evaluate an expression.  The context contains the ability to lookup a key by name or value (usually the results of your regex).  Failure to use context implies that the expression is constant (Thare are some exceptions to this reasoning, but none currently exist in rare).&lt;/p&gt;

&lt;p&gt;If the expression does seem to be constant based on the above definition, then it is evaluated during compilation, and the result is treated as a literal rather than a tree.  I was able to see significant improvements in performance relative to the expression complexity.  In no case would the performance become worse (Except for one additional expression evaluation at the beginning to figure this out).&lt;/p&gt;
</description>
        <pubDate>Tue, 25 May 2021 00:00:00 +0000</pubDate>
        <link>https://www.zdyn.net/projects/2021/05/25/rare-pcre.html</link>
        <guid isPermaLink="true">https://www.zdyn.net/projects/2021/05/25/rare-pcre.html</guid>
        
        <category>rare</category>
        
        
        <category>projects</category>
        
      </item>
    
      <item>
        <title>Docker Swarm Registry and Auto Garbage Collection on NFS</title>
        <description>&lt;p&gt;After moving Traefik to v2, I also updated the common registry infrastructure. Namely, this stack has a UI infront of the registry,
hosts the registry volume on an NFS store, and has an auto-garbage-collection image that runs once every 24 hours (With nothing fancier
than some swarm config!)&lt;/p&gt;

&lt;h2&gt;Docker Swarm Stack&lt;/h2&gt;

&lt;p&gt;Please note that there are several variables in the below config I use to abstract secrets/hosts/etc.  You&amp;#39;ll need to fill in these
before they can work.&lt;/p&gt;

&lt;p&gt;Also note that you can replace the NFS volume with a normal volume, but if you do, make sure to pin the two containers that use the volume
to the node that contains the volume.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;3.3&amp;quot;&lt;/span&gt;
&lt;span class=&quot;l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# This registry is ONLY on the local net&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# and will be fronted by the registryui&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;registry&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;registry:2&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;REGISTRY_HTTP_SECRET&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;some-secret-to-be-used-here&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;registry-data:/var/lib/registry&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;REGISTRY_STORAGE_DELETE_ENABLED&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;true&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;replicas&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;1&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;restart_policy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;on-failure&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;limits&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;48M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;reservations&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.05&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;32M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;registry-cleanup&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;registry:2&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;garbage-collect /etc/docker/registry/config.yml&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;registry-data:/var/lib/registry&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;replicas&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;1&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;restart_policy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;24h&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;limits&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;32M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;reservations&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.025&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;16M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;registryui&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;joxit/docker-registry-ui:static&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;default&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;REGISTRY_TITLE&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Registry&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;DELETE_IMAGES&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;true&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;REGISTRY_URL&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;http://registry:5000&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;registry&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.enable=true&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.docker.network=traefik-net&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.registry.rule=Host(`registry.${HOST}`)&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.services.registry.loadbalancer.server.port=80&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.registry.entrypoints=websecure&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.routers.registry.middlewares=registry-auth&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;traefik.http.middlewares.registry-auth.basicauth.users=${GLOBAL_HTPASSWD}&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;limits&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;32M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;l-Scalar-Plain&quot;&gt;reservations&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;0.05&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;16M&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;traefik-net&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;traefik-net&amp;#39;&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;registry-data&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;driver_opts&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;nfs&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;addr=${NFS},nolock,soft,rw&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;l-Scalar-Plain&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;${NFS_BASE}/registry&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        <pubDate>Mon, 15 Mar 2021 00:00:00 +0000</pubDate>
        <link>https://www.zdyn.net/docker/2021/03/15/registry-v2.html</link>
        <guid isPermaLink="true">https://www.zdyn.net/docker/2021/03/15/registry-v2.html</guid>
        
        <category>docker</category>
        
        <category>cookbooks</category>
        
        
        <category>docker</category>
        
      </item>
    
  </channel>
</rss>
