<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.3">Jekyll</generator><link href="https://www.mttf.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.mttf.io/" rel="alternate" type="text/html" /><updated>2023-06-30T16:19:25+00:00</updated><id>https://www.mttf.io/feed.xml</id><title type="html">Mean Time to Failure</title><subtitle>Mean Time To Failure is a blog about everything from research networking, automation, python, smart home tech, cycling, and anything else I feel is worthy of a post. Enjoy!</subtitle><author><name>Ryan Harden</name></author><entry><title type="html">Switch from FSTAB to Autofs for NFS mounts.</title><link href="https://www.mttf.io/blog/switch-to-autofs/" rel="alternate" type="text/html" title="Switch from FSTAB to Autofs for NFS mounts." /><published>2023-06-30T00:00:00+00:00</published><updated>2023-06-30T00:00:00+00:00</updated><id>https://www.mttf.io/blog/switch-to-autofs</id><content type="html" xml:base="https://www.mttf.io/blog/switch-to-autofs/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;This post will very briefly explain why you might want to switch from using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;autofs&lt;/code&gt; for your NFS mounts.&lt;/p&gt;

&lt;p&gt;Reason #1: NFS causing boot to hang.&lt;/p&gt;

&lt;p&gt;During a recent power outage, I took my NAS devices offline to save on UPS load.
But the servers were up and running and hung while trying to mount the NFS share.&lt;/p&gt;

&lt;p&gt;AutoFS lets you define mounts that don’t get mounted until you try to access them. Like when your docker containers start up.&lt;/p&gt;

&lt;h2 id=&quot;installation-and-config&quot;&gt;Installation and Config&lt;/h2&gt;

&lt;p&gt;Installing is pretty simple.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt install -y autofs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Configuration is also pretty easy once you figure it out.&lt;/p&gt;

&lt;p&gt;You’ll create two files. Replace the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;something&amp;gt;&lt;/code&gt; with a meaningful tag, like the name of your NAS.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/auto.master.d/&amp;lt;something&amp;gt;.autofs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/auto.&amp;lt;something&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;First we’ll set up the master file.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/auto.master.d/&amp;lt;something&amp;gt;.autofs&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&amp;lt;edit/paste line below&amp;gt;

/-   /etc/auto.&amp;lt;something&amp;gt; &lt;span class=&quot;nt&quot;&gt;--timeout&lt;/span&gt; 600 &lt;span class=&quot;nt&quot;&gt;--browse&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/-&lt;/code&gt;  indicates that the paths in the map file are non-relative.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/auto.&amp;lt;something&amp;gt;&lt;/code&gt; is the path to the map file.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--timeout 600&lt;/code&gt; how long to wait to auto-unmount the share after last access&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--browse&lt;/code&gt; if the NFS share is unavailable, create an empty directory so things don’t hang forver&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next we’ll set up the map file. (You might need to create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mnt/nfs&lt;/code&gt; first)&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/auto.&amp;lt;something&amp;gt;
&amp;lt;edit/paste line below&amp;gt;

/mnt/nfs/&amp;lt;share&amp;gt; &lt;span class=&quot;nt&quot;&gt;-rw&lt;/span&gt;,fstype&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nfs,soft,rsize&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8192,wsize&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8192 &amp;lt;nfs-server.example.com&amp;gt;:&amp;lt;/path/to/share&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mnt/nfs/&amp;lt;share&amp;gt;&lt;/code&gt; where you want the share mounted locally&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-rw,fstype=nfs,soft,rsize=8192,wsize=8192&lt;/code&gt; mounted it read-write, NFS, and some packet sizes for performance&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;nfs-server.example.com&amp;gt;:&amp;lt;/path/to/share&amp;gt;&lt;/code&gt; the FQDN to your NFS server and the path to the share.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;running&quot;&gt;Running&lt;/h2&gt;

&lt;p&gt;I’m running Ubuntu, so you’ll set it up just like any other service.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;systemctl &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;autofs
systemctl start autofs
systemctl status autofs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then you just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd&lt;/code&gt; to what you set in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mnt/nfs/&amp;lt;share&amp;gt;&lt;/code&gt; and after a second or two, your remote NFS data should be there.&lt;/p&gt;

&lt;p&gt;Make sure to remove or comment out the previous entry in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;p&gt;I kept running into issues when I was trying to use relative paths in the map file, which is supposed to be supported. But I couldn’t get it working, seeing the error(s) below.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;automount[68274]: key &quot;-&quot; not found in map source(s).
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Switch to that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/-&lt;/code&gt; in the master file and then using a full path in the map file was the key to success.&lt;/p&gt;</content><author><name>Ryan Harden</name></author><category term="blog" /><category term="Docker" /><category term="Ubuntu" /><category term="NFS" /><summary type="html">Introduction</summary></entry><entry><title type="html">Raspberry Pi 4 Docker Host/Home Server - From Scratch</title><link href="https://www.mttf.io/blog/raspberry-pi-4-docker-host-home-server-from-scratch/" rel="alternate" type="text/html" title="Raspberry Pi 4 Docker Host/Home Server - From Scratch" /><published>2021-01-12T00:00:00+00:00</published><updated>2021-01-12T00:00:00+00:00</updated><id>https://www.mttf.io/blog/raspberry-pi-4-docker-host-home-server-from-scratch</id><content type="html" xml:base="https://www.mttf.io/blog/raspberry-pi-4-docker-host-home-server-from-scratch/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;This post is mostly for my own notes, but others might find it helpful. Here I’ll document the process of buying, building, booting, and configuring a Raspberry Pi 4 (8GB) as a home server that runs various applications in Docker. Of course, you don’t necessarily &lt;strong&gt;need&lt;/strong&gt; to do all of the steps below to get a functional server, this is just what I did to get my Pis up and running how I wanted them.&lt;/p&gt;

&lt;h3 id=&quot;assumptions&quot;&gt;Assumptions&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;You already have a functioning home network.&lt;/li&gt;
  &lt;li&gt;You know the basics of linux, networking, docker, hardware, etc.&lt;/li&gt;
  &lt;li&gt;All of the commands below assume you are operating as root, or understand that you need to append &lt;strong&gt;sudo&lt;/strong&gt; if using an underprivileged user&lt;/li&gt;
  &lt;li&gt;You can work your way around basic applications, like the Raspberry Pi Imager app&lt;/li&gt;
  &lt;li&gt;other stuff I remember later&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;outline&quot;&gt;Outline&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Buying&lt;/li&gt;
  &lt;li&gt;Actual hardware you need to purchase&lt;/li&gt;
  &lt;li&gt;Building&lt;/li&gt;
  &lt;li&gt;Any gotchas around connecting any of the hardware itself&lt;/li&gt;
  &lt;li&gt;Booting&lt;/li&gt;
  &lt;li&gt;Creating a bootable SD card and editing it so it boots correctly&lt;/li&gt;
  &lt;li&gt;Configuring&lt;/li&gt;
  &lt;li&gt;Initial set up&lt;/li&gt;
  &lt;li&gt;Remove unnecessary packages&lt;/li&gt;
  &lt;li&gt;Set up the SSD&lt;/li&gt;
  &lt;li&gt;Set up Read-Only Mode&lt;/li&gt;
  &lt;li&gt;Disable Auto-Login&lt;/li&gt;
  &lt;li&gt;Install some packages&lt;/li&gt;
  &lt;li&gt;Set up some monitoring stuff&lt;/li&gt;
  &lt;li&gt;Docker&lt;/li&gt;
  &lt;li&gt;Pulling and running some containers with docker-compose&lt;/li&gt;
  &lt;li&gt;Backups&lt;/li&gt;
  &lt;li&gt;Setting up some backups scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;buying---open-your-wallet&quot;&gt;Buying - Open your wallet&lt;/h3&gt;

&lt;p&gt;First off, what do you need to buy to do even do this?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A Raspberry Pi 4B Kit (I went with the 8GB RAM version, because more is better)&lt;/li&gt;
  &lt;li&gt;A MicroSD Card (I went with 32GB because I had a few spares)&lt;/li&gt;
  &lt;li&gt;An SSD/mSATA/M.2 Add-on Card (For adding external storage)&lt;/li&gt;
  &lt;li&gt;An SSD/mSATA drive (Dedicated USB Storage)&lt;/li&gt;
  &lt;li&gt;RPi4 Heat Sinks (maybe not required, but really helps!)&lt;/li&gt;
  &lt;li&gt;RPi4 Active Cooling Fan (also not required, but really helps)&lt;/li&gt;
  &lt;li&gt;Short USB-A to USB-A Cable (don’t use the U shaped USB thing included with the add-on cards)&lt;/li&gt;
  &lt;li&gt;Power cables. USB-C cable/brick that can deliver up to 3 Amps at 5V-DC. And a second 5.5x2.5mm cable that can deliver the same specs.&lt;/li&gt;
  &lt;li&gt;USB Power Bank. Any power bank that can deliver 3 Amps per port will work.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;links-to-stuff&quot;&gt;Links to Stuff&lt;/h4&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ebay.com/itm/Vilros-Raspberry-Pi-4-with-USB-C-Micro-HDMI-Adapters/313125561738?ssPageName=STRK%3AMEBIDX%3AIT&amp;amp;var=612153551075&amp;amp;_trksid=p2057872.m2749.l2649&quot;&gt;RPi4 Kit - via eBay&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/SanDisk-Ultra-microSDXC-Memory-Adapter/dp/B073JWXGNT/ref=sxin_9?ascsubtag=amzn1.osa.e5e0b91d-64d7-4ef7-a6e5-3682102bf716.ATVPDKIKX0DER.en_US&amp;amp;creativeASIN=B073JWXGNT&amp;amp;cv_ct_cx=microsd&amp;amp;cv_ct_id=amzn1.osa.e5e0b91d-64d7-4ef7-a6e5-3682102bf716.ATVPDKIKX0DER.en_US&amp;amp;cv_ct_pg=search&amp;amp;cv_ct_we=asin&amp;amp;cv_ct_wn=osp-single-source-gl-ranking&amp;amp;dchild=1&amp;amp;keywords=microsd&amp;amp;linkCode=oas&amp;amp;pd_rd_i=B073JWXGNT&amp;amp;pd_rd_r=46fdaf5d-1fa2-44c3-bff3-38105add0cbc&amp;amp;pd_rd_w=K7SmA&amp;amp;pd_rd_wg=rzRHb&amp;amp;pf_rd_p=53f37bb1-bef6-4b9e-be3a-0696c5f5ad01&amp;amp;pf_rd_r=1CNX2C931HSXNR27KM9A&amp;amp;qid=1610469915&amp;amp;s=electronics&amp;amp;sr=1-1-d9dc7690-f7e1-44eb-ad06-aebbef559a37&amp;amp;tag=androidcentralosp-20&quot;&gt;32GB MicroSD Card&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/gp/product/B085HG7ZLJ/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;mSATA&lt;/a&gt; or &lt;a href=&quot;https://www.amazon.com/gp/product/B088HCY4TH/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;M.2&lt;/a&gt; Add-on Card&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/gp/product/B084Q137YJ/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;mSATA&lt;/a&gt; or &lt;a href=&quot;https://www.amazon.com/gp/product/B07V1KHPKK/ref=ppx_yo_dt_b_asin_title_o06_s01?ie=UTF8&amp;amp;psc=1&quot;&gt;M.2&lt;/a&gt; SSD Drive&lt;/li&gt;
  &lt;li&gt;Included in RPi4 Kit Linked above. There’s also a handy mini-HDMI to HDMI dongle.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/gp/product/B07Y9LFP1J/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;Active Cooling Fan&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/gp/product/B0891X229X/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;USB Cable&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/gp/product/B0765CFXBM/ref=ppx_yo_dt_b_asin_title_o04_s01?ie=UTF8&amp;amp;psc=1&quot;&gt;USB-C for Power&lt;/a&gt; and &lt;a href=&quot;https://www.amazon.com/gp/product/B00ZUE4WBE/ref=ppx_yo_dt_b_asin_title_o04_s01?ie=UTF8&amp;amp;psc=1&quot;&gt;USB-to-5.5x2.5mm for power&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/gp/product/B08HN6JK7N/ref=ppx_yo_dt_b_asin_title_o04_s02?ie=UTF8&amp;amp;psc=1&quot;&gt;USB Power Bank&lt;/a&gt; (Yeah-yeah, this is only 2.4A per port, but that’s probably going to be fine for my uses.)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;building---putting-it-all-together&quot;&gt;Building - Putting it all together&lt;/h3&gt;
&lt;p&gt;Assembling the various pieces should be fairly self-explanatory. Hopefully if you’re reading this guide, you can figure it out. Nevertheless, there’s some pics below that might be helpful.&lt;/p&gt;

&lt;h5 id=&quot;pics-and-stuff&quot;&gt;Pics and stuff&lt;/h5&gt;
&lt;p&gt;First, the Raspberry Pi4 and the heat sinks that came with the kit.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/pi_sinks.jpg&quot;&gt;&lt;img src=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/pi_sinks.jpg&quot; width=&quot;250&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/pi_sinks_on.jpg&quot;&gt;&lt;img src=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/pi_sinks_on.jpg&quot; width=&quot;250&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Second, all of the pieces. The Pi4, the fan hat, the mSATA (or M.2) SSD, and the SSD adapter.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/full_parts.jpg&quot;&gt;&lt;img src=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/full_parts.jpg&quot; width=&quot;250&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A gotcha. The Argon fan hat has a bolt that holds the fan on the board. This bolt interferes with one of the heat sinks. I removed it so there was adequate clearance. Three out of four screws to hold the fan in place should be adequate. Here’s a pic of the one to remove.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/fan_bolt.jpg&quot;&gt;&lt;img src=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/fan_bolt.jpg&quot; width=&quot;250&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last, fully assembled. Minus the 1 foot USB cable between the SSD adapter and the Pi4.
&lt;strong&gt;DO NOT, I REPEAT, DO NOT&lt;/strong&gt; use the little U shaped USB thingy that comes with the Geekworm SSD adapter. It is NOT electronically shielded and &lt;strong&gt;WILL&lt;/strong&gt; interfere with Wifi/bluetooth/anything nearby.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/assembled_side.jpg&quot;&gt;&lt;img src=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/assembled_side.jpg&quot; width=&quot;250&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/assembled_top.jpg&quot;&gt;&lt;img src=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pics/assembled_top.jpg&quot; width=&quot;250&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;booting---getting-it-running&quot;&gt;Booting - Getting it running&lt;/h3&gt;

&lt;h5 id=&quot;create-the-sd-card-using-the-latest-raspberry-pi-os&quot;&gt;Create the SD card using the latest Raspberry Pi OS&lt;/h5&gt;

&lt;p&gt;This step is pretty easy. Go &lt;a href=&quot;https://www.raspberrypi.org/software/&quot;&gt;here&lt;/a&gt; and download the imager for your operating system. Then insert an SD card. Then use the imager app to write the image.&lt;/p&gt;

&lt;p&gt;I didn’t use any of the images included by default in the app since I wanted to run a 64-bit OS. Running 64-bit is required to take advantage of the full 8GB of RAM in the RPi4-8GB. You can download it &lt;a href=&quot;https://downloads.raspberrypi.org/raspios_arm64/images/&quot;&gt;here&lt;/a&gt;. Pick the directory with the latest date. (I used 2020-08-24.)&lt;/p&gt;

&lt;h5 id=&quot;mount-the-sd-card-in-your-computer-to-enable-headlessssh&quot;&gt;Mount the SD card in your computer to enable headless/ssh&lt;/h5&gt;
&lt;p&gt;&lt;a href=&quot;https://www.shellhacks.com/raspberry-pi-enable-ssh-headless-without-monitor/&quot;&gt;Follow this guide&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;configuring---the-bulk-of-the-work-is-in-here&quot;&gt;Configuring - The bulk of the work is in here…&lt;/h3&gt;

&lt;h4 id=&quot;initial-stuff&quot;&gt;Initial Stuff&lt;/h4&gt;

&lt;h5 id=&quot;change-your-password&quot;&gt;Change your password&lt;/h5&gt;
&lt;p&gt;If you intend to use the default &lt;strong&gt;pi&lt;/strong&gt; user, change the password. If you don’t, either change it anyway or remove the user account.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;passwd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;remove-a-bunch-of-crap-you-dont-need&quot;&gt;Remove a bunch of crap you don’t need&lt;/h5&gt;
&lt;p&gt;NOTE: This can probably be avoided by selecting a more light weight OS or image, but I went with the Raspberry Pi (buster) OS that had 64bit support so I could use all 8GB of the RAM.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo apt remove &quot;x11-*&quot; triggerhappy logrotate dphys-swapfile rsyslog
sudo apt autoremove
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;do-an-os-update&quot;&gt;Do an OS Update&lt;/h5&gt;
&lt;p&gt;Just a good idea. The image you downloaded to your SD is likely outdated, get the latest versions of everything. This will also update you to the latest version of the RPi bootloader, if needed.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apt update
apt full-upgrade
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;disable-a-bunch-of-services-you-dont-need&quot;&gt;Disable a bunch of services you don’t need&lt;/h5&gt;
&lt;p&gt;Turn off some services that we won’t need as a headless home server.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;systemctl disable avahi-daemon
systemctl disable bluetooth
systemctl disable wpa_supplicant
systemctl disable apt-daily.timer           # More on this later
systemctl disable apt-daily.service         # More on this later
systemctl disable apt-daily-upgrade.timer   # More on this later
systemctl disable apt-daily-upgrade.service # More on this later
systemctl disable man-db.timer              # More on this later
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;partition-format-mount-your-fancy-ssd-drive&quot;&gt;Partition, Format, Mount your fancy SSD drive.&lt;/h5&gt;
&lt;p&gt;Typical Linux process here.
Run &lt;em&gt;dmesg&lt;/em&gt; to see what device id your SSD was given, then use fdisk to partition it, them mount it and add it to /etc/fstab.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dmesg | grep sd
[    2.111554] sd 0:0:0:0: [sda] 500118192 512-byte logical blocks: (256 GB/238 GiB)
[    2.111752] sd 0:0:0:0: [sda] Write Protect is off
[    2.111781] sd 0:0:0:0: [sda] Mode Sense: 43 00 00 00
[    2.112116] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[    2.112862] sd 0:0:0:0: [sda] Optimal transfer size 33553920 bytes
[    2.129604]  sda:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We see that it’s &lt;em&gt;/dev/sda&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;fdisk /dev/sda
Enter p         - To ensure you're on the right disk, check the reported size, etc...
Enter n         - To create a new partition on the disk
Enter p         - To specifiy a primary partition type
Enter 1         - Since this is the first (and only) partition we're creating
Enter &amp;lt;enter&amp;gt;   - To select the first sector as the start of your new partition
Enter &amp;lt;enter&amp;gt;   - To select the last sector as the end of your new partition (Your new partition is th full size of the disk)
Enter w         - To write the new changest to the disk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now let’s format it. I like &lt;strong&gt;ext4&lt;/strong&gt;. If you prefer something else, use it here.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkfs.ext4 /dev/sda1   - /dev/sda1 because sda1 refers to the new partition we created above
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we’ll mount it.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir /storage              - You can use whatever you want here, I like /storage
mount /dev/sda1 /storage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Add the following to &lt;strong&gt;/etc/fstab&lt;/strong&gt; to make sure the SSD gets mounted at boot.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Mount the SSD drive. The discard option turns on TRIM which should help extend the life of your SSD.
/dev/sda1	/storage	ext4	defaults,discard 	0	0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;adjust-tmpfs-sizes-add-some-mount-points&quot;&gt;Adjust tmpfs sizes, add some mount points&lt;/h5&gt;
&lt;p&gt;While we’re mucking with &lt;strong&gt;/etc/fstab&lt;/strong&gt;, we might as well make some adjustments here we can use later.
Add the following to &lt;strong&gt;/etc/fstab&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;### Mount a few paths as tmpfs so they exist in RAM instead of on disk (SD card)
tmpfs        /tmp            tmpfs   nosuid,nodev,size=256M         0       0
tmpfs        /var/log        tmpfs   nosuid,nodev,size=100M         0       0
tmpfs        /var/tmp        tmpfs   nosuid,nodev,size=100M         0       0

# And this so docker will work in Read-only mode
tmpfs        /var/lib/containerd tmpfs   nosuid,nodev,size=512M         0       0

### Make some default stuff smaller to save RAM
tmpfs      /dev/shm	tmpfs		nosuid,nodev,size=256M 		0	0
tmpfs      /run		tmpfs		nosuid,nodev,size=256M 		0	0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;set-your-pis-hostname&quot;&gt;Set your pi’s hostname&lt;/h5&gt;
&lt;p&gt;Edit &lt;strong&gt;/etc/hostname&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/hostname
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;set-your-pis-timezone&quot;&gt;Set your pi’s Timezone&lt;/h5&gt;
&lt;p&gt;You should be able to just set it via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/timezone&lt;/code&gt;, but that doesn’t work for some reason.
Instead, you’ll use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raspi-config&lt;/code&gt; tool. Follow &lt;a href=&quot;https://howchoo.com/pi/how-to-set-the-timezone-on-your-raspberry-pi&quot;&gt;this guide&lt;/a&gt; if you can’t figure it out. It’s under Localization Options.&lt;/p&gt;

&lt;h5 id=&quot;reboot&quot;&gt;Reboot&lt;/h5&gt;
&lt;p&gt;Reboot so you can take advantage of your newly cleaned and updated system before you do the rest of the work.&lt;/p&gt;

&lt;p&gt;We’ll reboot a few times throughout this guide. Luckily these things boot super quickly.&lt;/p&gt;

&lt;h4 id=&quot;make-your-sd-card-and-root-filesystem-read-only&quot;&gt;Make your SD Card and root filesystem read-only&lt;/h4&gt;
&lt;p&gt;Why? Because SD cards aren’t designed to be constantly written to. If you do, they’ll eventually (months) degrade and fail. And that’s no fun. They will still eventually fail, but this should let you run them for much much longer.&lt;/p&gt;

&lt;p&gt;I used &lt;a href=&quot;https://medium.com/swlh/make-your-raspberry-pi-file-system-read-only-raspbian-buster-c558694de79&quot;&gt;this guide&lt;/a&gt; as the basis for most of this. Credit to Andreas Schallwig for the excellent write up.&lt;/p&gt;

&lt;h5 id=&quot;remove-stuff-that-likes-to-write-files-constantly&quot;&gt;Remove stuff that likes to write files constantly&lt;/h5&gt;
&lt;p&gt;Oh wait, we already did this above. Check!&lt;/p&gt;

&lt;h5 id=&quot;adjust-your-kernel-parameters-to-turn-off-swap-disable-filesytem-checking-and-operate-in-read-only-mode&quot;&gt;Adjust your kernel parameters to turn off swap, disable filesytem checking, and operate in read-only mode&lt;/h5&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /boot/cmdline.txt
# Add the following three parameters to the only line that should be there.
fastboot noswap ro
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;make-your-filesystem-read-only&quot;&gt;Make your filesystem read-only&lt;/h5&gt;
&lt;p&gt;Your &lt;strong&gt;/boot&lt;/strong&gt; and &lt;strong&gt;/&lt;/strong&gt; filesystems need a flag added to make them read-only. You do this via &lt;strong&gt;/etc/fstab&lt;/strong&gt; again.
&lt;strong&gt;DO NOT&lt;/strong&gt; copy/paste this. Just add the &lt;strong&gt;ro&lt;/strong&gt; to each already existing line.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PARTUUID=fb0d460e-01  /boot     vfat    defaults,ro          0     2
PARTUUID=fb0d460e-02  /         ext4    defaults,noatime,ro  0     1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;move-some-paths-to-those-tmpfs-locations-you-created-above&quot;&gt;Move some paths to those tmpfs locations you created above&lt;/h5&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rm -rf /var/lib/dhcp /var/lib/dhcpcd5 /var/spool /etc/resolv.conf
ln -s /tmp /var/lib/dhcp
ln -s /tmp /var/lib/dhcpcd5
ln -s /tmp /var/spool
touch /tmp/dhcpcd.resolv.conf
ln -s /tmp/dhcpcd.resolv.conf /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;update-random-seed&quot;&gt;Update random-seed&lt;/h5&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rm /var/lib/systemd/random-seed
ln -s /tmp/random-seed /var/lib/systemd/random-seed
vi /lib/systemd/system/systemd-random-seed.service
# Add this line above ExecStart=
ExecStartPre=/bin/echo &quot;&quot; &amp;gt;/tmp/random-seed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;add-some-aliases-to-make-switching-between-read-write-and-read-only-easier&quot;&gt;Add some aliases to make switching between read-write and read-only easier&lt;/h5&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/bash.bashrc
# Paste the below at the end of the file.
set_bash_prompt() {
    fs_mode=$(mount | sed -n -e &quot;s/^\/dev\/.* on \/ .*(\(r[w|o]\).*/\1/p&quot;)
    PS1='\[\033[01;32m\]\u@\h${fs_mode:+($fs_mode)}\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
}
alias ro='sudo mount -o remount,ro / ; sudo mount -o remount,ro /boot'
alias rw='sudo mount -o remount,rw / ; sudo mount -o remount,rw /boot ; chmod 1777 /tmp'

PROMPT_COMMAND=set_bash_prompt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;create-a-bash_logout-file-to-go-back-into-ro-mode-when-you-log-out&quot;&gt;Create a bash_logout file to go back into ro mode when you log out.&lt;/h5&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/bash.bash_logout
# Paste the following, and save
mount -o remount,ro /
mount -o remount,ro /boot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;disable-a-bunch-of-services-that-try-to-write-to-disk-often&quot;&gt;Disable a bunch of services that try to write to disk often&lt;/h4&gt;
&lt;p&gt;Oh wait, we already did that above.
Remember those &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemctl disable&lt;/code&gt; commands?
We turned off &lt;strong&gt;apt-daily&lt;/strong&gt; and &lt;strong&gt;apt-daily-upgrade&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; This means your system is no longer keeping itself up to date automatically. You should do it manually on a regular basis. I’m a bit uneasy about having a device automatically updating packages.&lt;/p&gt;

&lt;h4 id=&quot;disable-auto-login&quot;&gt;Disable Auto-Login&lt;/h4&gt;
&lt;p&gt;The Raspberry Pi OS will automatically log in the user &lt;em&gt;pi&lt;/em&gt; at boot. This is bad. Here’s how you disable it. I haven’t found a non “GUI” way to do this, for whatever reason.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;raspi-config
(enter) 1 System Options -&amp;gt;
(enter) S5 Boot / Auto-Login -&amp;gt;
(enter) B1 Console Text console, requiring user to login -&amp;gt;
(enter) B3 Desktop Desktop GUI, requiring user to login -&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;reboot-1&quot;&gt;Reboot&lt;/h5&gt;
&lt;p&gt;Let’s reboot to make sure everything is working properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; From here on out, you might be presented with an error about the read-only filesystem. It will happen when installing packages, or editing any files that don’t live on your SSD. In most cases you just need to run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rw&lt;/code&gt; command to remount as read-write.&lt;/p&gt;

&lt;h4 id=&quot;install-some-packages&quot;&gt;Install some packages&lt;/h4&gt;
&lt;p&gt;Install a few handy packages that will make your life easier.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rw # Make you filesystem read-write temporarily.
apt update
apt install ntp dc telnet screen ntpdate busybox-syslogd docker-compose
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Yes, telnet. The telnet client, not the server, is useful for quickly checking to see if you can access open ports on another system, or locally. There’s probably a better tool, sue me.&lt;/p&gt;

&lt;p&gt;Busybox-syslogd replaces rsyslog that we removed earlier. There are two ways to read logs going forward.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;logread&lt;/strong&gt;      - ringlog that shows you a rolling list of the last N (I think it’s 128 bytes) worth of logs.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;journalctl&lt;/strong&gt;   - All of the system logs since the system booted.
NOTE: I need to understand a bit better about which logs go where and how to manipulate that. It’s on my TODO list and I’ll update here when I better understand it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You’ll also want to tweak the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;journalctl&lt;/code&gt; settings to only keep a certain amount of logs. I’ve got mine set to 64 MB. Otherwise it’ll eventually fill the tmpfs we created for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/run&lt;/code&gt;. And that’s a bad thing.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/systemd/journald.conf 
### Uncomment and edit the following line.
SystemMaxUse=64M
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;systemd-watchdog&quot;&gt;SystemD Watchdog&lt;/h5&gt;

&lt;p&gt;This is a process that will automatically safely reboot your Pi4 if it hangs for some reason.&lt;/p&gt;

&lt;p&gt;First turn it on in the kernel.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /boot/config.txt
### add the following line to the end of the file.
dtparam=watchdog=on
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Turn on the systemd watchdog service.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/systemd/system.conf
### uncomment (and edit) the following lines
RuntimeWatchdogSec=10s
ShutdownWatchdogSec=10min
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then reload systemd.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;systemctl daemon-reload
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After the next reboot, the systemd watchdog service will automatically reboot if the system hangs.&lt;/p&gt;

&lt;h5 id=&quot;telegraf&quot;&gt;Telegraf&lt;/h5&gt;
&lt;p&gt;Even if you plan to run Docker (like I am, and will explain later), it’s a good idea to run Telegraf as a system install. The main reason is that I want to gather system stats even if docker is broken somehow.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;echo &quot;deb https://repos.influxdata.com/debian buster stable&quot; | tee /etc/apt/sources.list.d/influxdb.list
apt update
apt install telegraf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s set it up to send some metrics to InfluxDB. You don’t have an InfluxDB running yet, but you will later. If you don’t want or plan to run InfluxDB, or use some other DB, I guess just skip this part.&lt;/p&gt;

&lt;p&gt;First we need to edit the main telegraf config file to enable an InfluxDB output and tell it to talk to the local Docker socket.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/telegraf/telegraf.conf
## Look for &quot;outputs.influxdb&quot;
## Uncomment the [[outputs.influxdb]] line, and edit/replace the urls field to something like the below.
urls = [&quot;http://influxdb.home.example.com:8086&quot;]
## Next enable the Docker section.
## Look for inputs.docker, and either uncomment the bits you need, or just paste this at the bottom:
# # Read metrics about docker containers
[[inputs.docker]]
  ## Docker Endpoint
  ## To use TCP, set endpoint = &quot;tcp://[ip]:[port]&quot;
  ## To use environment variables (ie, docker-machine), set endpoint = &quot;ENV&quot;
  endpoint = &quot;unix:///var/run/docker.sock&quot;
  ## Only collect metrics for these containers, collect all if empty
  container_names = []
  ## Timeout for docker list, info, and stats commands
  timeout = &quot;5s&quot;
  ## Whether to report for each container per-device blkio (8:0, 8:1...) and
  ## network (eth0, eth1, ...) stats or not perdevice = true
  perdevice = true
  ## Whether to report for each container total blkio and network stats or not
  total = false
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next we add the stuff to gather a bunch of stats from the RPi.
I am using a version you can find &lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/telegraf/rpi-to-influx.conf&quot;&gt;here&lt;/a&gt;. You might need to edit it.
I got most of it from &lt;a href=&quot;http://oostens.me/projects/raspberrypiserver/system-monitoring/&quot;&gt;this guide&lt;/a&gt;, so it might be helpful to follow that guide. I of course, skipped the InfluxDB/Telegraf/etc stuff since I already did it above.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/telegraf/telegraf.d
### Paste the file from the github repo above, and save it.
### Add the telegraf user to the video group for various stat collection
usermod -aG video telegraf
### Then restart telegraf
systemctl restart telegraf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;docker&quot;&gt;Docker&lt;/h5&gt;
&lt;p&gt;Finding a guide to install docker is easy. I’ll include my steps and the couple tweaks I made here.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl -sSL https://get.docker.com | sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Edit /etc/docker/daemon.json to place the Docker root directory on your SSD instead of the default.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/docker/daemon.json
### add
{
  &quot;data-root&quot;: &quot;/storage/docker-root&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Turn on TCP access to the Docker socket for monitoring purposes.
This is only required if you want a remote telegraf instance to be able to monitor the docker info from this system. I don’t use this, but listed it for posterity. Most people won’t need this.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /lib/systemd/system/docker-tcp.socket
### Paste the following:
[Unit]
Description=Docker Socket for the API
PartOf=docker.service

[Socket]
ListenStream=2375

BindIPv6Only=both
Service=docker.service

[Install]
WantedBy=sockets.target
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Enable the new docker-tcp.socket and restart docker.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;systemctl daemon-reload
systemctl stop docker.service
# systemctl enable docker-tcp.socket # Only do this if you actually need it.
# systemctl start docker-tcp.socket # Only do this if you actually need it.
systemctl start docker.service
# add telegraf user to docker group for monitoring
usermod -aG docker telegraf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you’re ready to start running containers with docker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; Now might be a good time to skip ahead to the Backups section (at the end) and do a quick backup of the SD card. Backing up now gives you a nice snapshot in time before you started adding containers, and the edits and changes to the SD card are done.&lt;/p&gt;

&lt;h4 id=&quot;containers&quot;&gt;Containers&lt;/h4&gt;
&lt;p&gt;A few of the containers I run, and how I set them up. From here on out, you can pretty much mix and match the things you want to set up or not. So skip sections for things you don’t want.&lt;/p&gt;

&lt;h5 id=&quot;docker-secrets&quot;&gt;Docker Secrets&lt;/h5&gt;

&lt;p&gt;Docker allows you to store credentials and other secrets in a file, then reference them in your docker-compose files. Here’s how you set it up, using AWS credentials as an example.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir /storage/secrets
vi /storage/secrets/aws.creds
###
[default]
aws_access_key_id = &amp;lt;key here&amp;gt;
aws_secret_access_key = &amp;lt;key here&amp;gt;
###
chmod 600 /storage/secrets/aws.creds
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;traefik&quot;&gt;Traefik&lt;/h5&gt;
&lt;p&gt;Traefik is a reverse proxy for docker. It’s a lot more than I use it for. I’m using it as a fancy way to automate running containers that expose port 80/443 (web) and generate Let’s Encrypt certificates for them. If none of this interest you, or you already know how to do all of this, skip ahead.&lt;/p&gt;

&lt;p&gt;Create your docker-compose.yml file. &lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/traefik/docker-compose.yml&quot;&gt;This is what I use&lt;/a&gt;, I won’t explain what everything means or all of the options are. You can use this as a starting point, or find another guide that explains it.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir /storage/traefik
vi /storage/traefik/docker-compose.yml
### paste and edit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create your config files. You need both &lt;strong&gt;&lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/traefik/api.toml&quot;&gt;api.toml&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/traefik/traefik.toml&quot;&gt;traefik.toml&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The docker-compose.yml file sets up the container to mount &lt;strong&gt;/storage/traefik/conf&lt;/strong&gt; as &lt;strong&gt;/etc/traefik&lt;/strong&gt; inside the container, so make sure you place them in the right place on your system. Also, create a directory for traefik to store the certificate file.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir /storage/traefik/conf
vi /storage/traefik/conf/api.toml
### paste stuff
vi /storage/traefik/conf/traefik.toml
### paste stuff
mkdir /storage/letsencrypt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: There’s a very important part of this I’m not covering in great detail. I’m using AWS Route53 to host the zone (And do DNS-01 Challenges) where I want to create Let’s Encrypt certificates. You’ll need to set that up, or something similar with another service. There are lots of guides on how to set that up.&lt;/p&gt;

&lt;p&gt;Now that you’re ready to go (and edited those files to match your environment), let’s start it up.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd /storage/traefik
docker network create traefik-ext
docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once that is up and running, and you wait a few minutes. You should be able to browse to whatever container + domainname you configured in your docker-compose.yml file. So from the example it is: &lt;strong&gt;traefik-docker1.home.example.com&lt;/strong&gt;. You should be presented with the traefik dashboard, and it should have a valid Let’s Encrypt certificate. Hurray!&lt;/p&gt;

&lt;h5 id=&quot;influxdb&quot;&gt;InfluxDB&lt;/h5&gt;
&lt;p&gt;You may want to skip this section (and the following one for Grafana) if you aren’t interested in setting up dashboards for various apps and services you run on your network. But I do, and I wanted to document how I do it.&lt;/p&gt;

&lt;p&gt;Create your docker-compose.yml file. Again, &lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/influxdb/docker-compose.yml&quot;&gt;here’s an example of mine&lt;/a&gt;. Same as above, you should be able to figure out what the options mean. :)&lt;/p&gt;

&lt;p&gt;A few things you want to tweak:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;The influxdb admin username and password. (You’ll need it later for Grafana)&lt;/li&gt;
  &lt;li&gt;The hostname in the Traefik config, so it generates the correct certificate. (You’ll note that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certresolver=le&lt;/code&gt; line is commented out in the example. I’m not using SSL, but you might want to for your applications.)&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir /storage/influxdb
vi /storage/influxdb/docker-compose.yml
### paste and edit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next you just need to bring it up.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd /storage/influxdb
docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Most applications (like Telegraf) that can use InfluxDB, will automatically create the databases they need the first time you run them. So running InfluxDB is really as simple as just running the container.&lt;/p&gt;

&lt;h5 id=&quot;grafana&quot;&gt;Grafana&lt;/h5&gt;
&lt;p&gt;Same as above, this section can be skipped if you want plan to build dashboards. I have dashboards for everything I can think of.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;General Service Health&lt;/li&gt;
  &lt;li&gt;Docker Stats for each Server&lt;/li&gt;
  &lt;li&gt;Traffic/Health of my Mikrotik Router (it’s also my wireless controller for 3 Mikrotik APs)&lt;/li&gt;
  &lt;li&gt;Cable Modem Health and Stats&lt;/li&gt;
  &lt;li&gt;Zoneminder Event Stats&lt;/li&gt;
  &lt;li&gt;Hubitat Information (Temperatures, doors open/close status, Thermostat settings, etc)&lt;/li&gt;
  &lt;li&gt;Synology NAS Health and Stats&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can find dashboard JSON files for some of these dashboards &lt;a href=&quot;https://github.com/ancker010/rpi-home-server/tree/main/grafana/dashboards&quot;&gt;here&lt;/a&gt;. Most are tweaked versions I found on the Grafana Dashboard site. So YMMV if you try to run them in your environment.&lt;/p&gt;

&lt;p&gt;Anyway, let’s get it running.&lt;/p&gt;

&lt;p&gt;Create your docker-compose.yml file. &lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/grafana/docker-compose.yml&quot;&gt;Here’s mine&lt;/a&gt;. You’ll need to tweak the hostname stuff again, and set the admin user password. You’ll need it to log into the interface.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir /storage/grafana
vi /storage/grafana/docker-compose.yml
### paste and edit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And run it.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd /storage/grafana
docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you wait a few minutes, you should be able to browse to the hostname you configured. Like the traefik dashboard above, you should have a valid Let’s Encrypt certificate. Log in with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin&lt;/code&gt; and the password you set the docker-compose file.&lt;/p&gt;

&lt;p&gt;Next we need to add InfluxDB as a datasource. Rather than me take a bunch of screenshots, I’ll just &lt;a href=&quot;https://grafana.com/docs/grafana/latest/datasources/influxdb/&quot;&gt;link to the official guide from Grafana&lt;/a&gt;. You’ll enter something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://influxdb.home.example.com:8086&quot;&lt;/code&gt; as the URL, and use the username and password you set in the InfluxDB docker-compose file. &lt;strong&gt;NOTE&lt;/strong&gt; Best practice is to create an influxdb user just for grafana rather than use an admin account. You should totally do this. Don’t say I didn’t warn you. Your risk is probably not that high if you aren’t exposing InfluxDB or Grafana outside of your home network, but still.&lt;/p&gt;

&lt;p&gt;I won’t get into how to create Dashboards. It’s fairly easy to find a guide that will help you with that. But since I provided some dashboards in my github repo, we can at least import the basic Server Stats and Docker Stats ones.&lt;/p&gt;

&lt;p&gt;To import, &lt;a href=&quot;https://grafana.com/docs/grafana/latest/dashboards/export-import/#importing-a-dashboard&quot;&gt;follow this guide&lt;/a&gt;, copy/paste or upload the json files, select the Datasource you created above, and you should be set.&lt;/p&gt;

&lt;p&gt;Because InfluxDB has been running for a bit, and telegraf has been running for a bit, you should almost immediately see metrics in both of the Dashboards. If you don’t, there might be some fun detective work to be done.&lt;/p&gt;

&lt;h5 id=&quot;pihole&quot;&gt;PiHole&lt;/h5&gt;
&lt;p&gt;If you haven’t heard of PiHole, you should &lt;a href=&quot;https://pi-hole.net/&quot;&gt;look it up&lt;/a&gt;. It’s a local DNS server that will use meticulously curated lists of AD, tracking, and other malicious (or not) domains and block them on your network. It can also provide DHCP services, but my router does that.&lt;/p&gt;

&lt;p&gt;It is designed to operate on a standalone Raspberry Pi, but I choose to run mine in docker so it’s a bit more portable. Here’s how I set it up.&lt;/p&gt;

&lt;p&gt;Create your docker-compose.yml file. &lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pihole/docker-compose.yml&quot;&gt;Example here&lt;/a&gt;. Tweak the file to your environment, make sure to edit the hostname for the certificate, the IP/IPv6 address, and your web admin password.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir /storage/pihole
vi /storage/pihole/docker-compose.yml
### paste and edit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Set up DNSMASQ. This is necessary if you are running a private local zone. I have my router configured with a bunch of local-only DNS entries for all of my home network devices.
Here’s an &lt;a href=&quot;https://github.com/ancker010/rpi-home-server/raw/main/pihole/01-pihole.conf&quot;&gt;example config file&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir /storage/pihole/dnsmasq
vi /storage/pihole/dnsmasq/01-pihole.conf
### paste and edit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create the log file, it complains if it doesn’t already exist for some reason.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touch /storage/pihole/logs/pihole.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And run it.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd /storage/pihole
docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;backups---in-case-something-goes-wrong&quot;&gt;Backups - In case something goes wrong&lt;/h4&gt;
&lt;p&gt;I’m not going to cover this in great detail. You should probably already know how to back up important files. The bulk of your critical config is on the SSD drive. It’s less likely to fail than the SD card, but you should probably set something up to zip/tar and compress it on a regular basis. Just don’t forget to exclude the docker-root directory, you don’t need to backup local versions if your docker containers.&lt;/p&gt;

&lt;p&gt;Your command will look something like this. It will tar (and bzip2 compress) everything under &lt;strong&gt;/storage&lt;/strong&gt; but exclude the &lt;strong&gt;docker-root&lt;/strong&gt; directory, any &lt;strong&gt;.log&lt;/strong&gt; files, and your backup directory. You may also want to exclude the InfluxDB database files. They can get pretty big, and unless you really really need it, it’s not a big deal to lose historical data about your cable modem or interface stats. If you want to exclude them, just add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--exclude=&quot;/storage/dockerinfluxdb/data&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The command will write the backup file to the SSD, but be sure to remember to copy it off to a USB thumb drive, or another system frequently. Storing your backups locally doesn’t help much if the drive fails, does it…&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tar -cjvf /storage/backups/home-server-backup-ssh-`date +%m-%d-%Y`.bz2 --exclude=&quot;/storage/docker-root&quot; --exclude=&quot;*.log&quot; --exclude=&quot;storage/backups&quot; /storage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The easiest, but downtime causing, backup method for the SD card is to just use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dd&lt;/code&gt; or an app to copy the whole SD card to an image file. This point in the guide is a good time to do it since pretty much anything else you’ll need to change will be through docker.&lt;/p&gt;

&lt;p&gt;I was going to type up a guide for this, but realized there are a ton out there that do a better job and have screenshots. So just use something &lt;a href=&quot;https://medium.com/@ccarnino/backup-raspberry-pi-sd-card-on-macos-the-2019-simple-way-to-clone-1517af972ca5&quot;&gt;like this&lt;/a&gt;. Or &lt;a href=&quot;https://pimylifeup.com/backup-raspberry-pi/&quot;&gt;this&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;conlusion&quot;&gt;Conlusion&lt;/h3&gt;
&lt;p&gt;There you have it. You should have a fully functioning home server on your fancy new Raspberry Pi4. This post is mainly for my own purposes, documenting almost everything I did to set up my RPis. I hope it’s helpful to you. I will probably update this post as I figure out new ways to do things, so hopefully it’ll be consistently accurate over the years. Famous last words, I know, but hey, at least I documented this much. It’s a lot more than I usually do for home projects…&lt;/p&gt;

&lt;p&gt;I don’t enable comments on my posts, and odds are I don’t really have time to help through problems. If you do want to reach out, use the Twitter link in the sidebar. My DMs are closed, but just tag me in a tweet and I’ll see it.&lt;/p&gt;</content><author><name>Ryan Harden</name></author><category term="blog" /><category term="Raspberry Pi" /><category term="Docker" /><category term="SSD" /><category term="PiHole" /><category term="InfluxDB" /><category term="Grafana" /><category term="Telegraf" /><category term="Python" /><category term="Traefik" /><category term="ZoneMinder" /><summary type="html">Introduction</summary></entry><entry><title type="html">Conditional ISP(Cellular) Failover with Mikrotik/RouterOS</title><link href="https://www.mttf.io/blog/conditional-isp-failover-with-mikrotik-routeros/" rel="alternate" type="text/html" title="Conditional ISP(Cellular) Failover with Mikrotik/RouterOS" /><published>2020-07-16T00:00:00+00:00</published><updated>2020-07-16T00:00:00+00:00</updated><id>https://www.mttf.io/blog/conditional-isp-failover-with-mikrotik-routeros</id><content type="html" xml:base="https://www.mttf.io/blog/conditional-isp-failover-with-mikrotik-routeros/">&lt;h3 id=&quot;preface&quot;&gt;Preface&lt;/h3&gt;
&lt;p&gt;I’ve been long-time subscriber to home automation. It started with the original Nest thermostat. I loved being able to control it via an app on my phone. The ‘learning’ part wasn’t as interesting since shortly after installing it, I switched to 100% remote work.&lt;/p&gt;

&lt;p&gt;Not too long after the Nest, I was introduced to the Staples Connect hub. It had Z-Wave and Zigbee radios and also an app for my phone. I quickly installed a handful of z-wave door sensors and got a z-wave garage door controller. Getting alerts on opened doors and being able to control the garage door from afar hooked me. Everything must be automated.&lt;/p&gt;

&lt;p&gt;Staples Connect was eventually sunset so I moved to SmartThings. SmartThings started getting unreliable (too much reliance on Cloud for what should be local rules), and the subsequent purchase by Samsung. The delayed alerts and actions (sometimes 30+ minutes) were enough to push me to find other options. The stand-out option was Hubitat Elevation. I looked at home-assistant and a few more, but Hubitat had the greatest amount of community supported apps and devices combined with not having to spend too much time in code. I’ve now moved to 100% Hubitat, which means all of the home automation actions are processes and executed locally. This is huge. Everything works (and quickly) even if our ISP is down.&lt;/p&gt;

&lt;p&gt;So how did all of this lead to this blog post? &lt;strong&gt;Alerts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While our ISP is generally pretty stable, I didn’t like the idea of missing an alert or being unable to check the status of the house while away from home due to an ISP outage. I wanted a way to switch over to a secondary ISP (Cellular in this case) only when the main ISP has an outage.&lt;/p&gt;

&lt;p&gt;Let’s get started!&lt;/p&gt;

&lt;h3 id=&quot;assumptions&quot;&gt;Assumptions&lt;/h3&gt;
&lt;p&gt;In order for this to work, a handful of things need to be in place.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Your main home router needs to be a recent Mikrotik capable of running 6.x. (Tested on 6.47)
    &lt;ul&gt;
      &lt;li&gt;I’m using a Mikrotik hEX.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;No special routing config, VLANs, or existing policies.
    &lt;ul&gt;
      &lt;li&gt;You can likely make it work, but these won’t work without modifications.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;The secondary ISP modem operates in a “&lt;strong&gt;Router&lt;/strong&gt;” mode, and has a “&lt;strong&gt;DMZ&lt;/strong&gt;” or “&lt;strong&gt;Forward All&lt;/strong&gt;” mode to a specific client.
    &lt;ul&gt;
      &lt;li&gt;My Cellular/LTE modem provides a subnet 192.168.5.0/24 for clients. I’ve statically assigned 192.168.5.10 to the “lte” interface on my Mikrotik, and set this IP in the modem DMZ settings.&lt;/li&gt;
      &lt;li&gt;Some Cellular modems provide a “&lt;strong&gt;Passthrough/Bridge&lt;/strong&gt;” option where the cellular IP gets assigned directly to the client. I couldn’t get that to work reliably, so I chose to leave the modem in “&lt;strong&gt;Router&lt;/strong&gt;” mode. If I decide to work more on that, I’ll come back and add an addendum.&lt;/li&gt;
      &lt;li&gt;For reference: I’m using a Netgear LB1120 LTE Modem.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;ispcellular-setup&quot;&gt;ISP/Cellular Setup&lt;/h3&gt;

&lt;p&gt;The first thing you need to do is get a secondary ISP or figure out your cellular plan. While researching cellular options for another project, I came across a &lt;a href=&quot;https://www.embeddedworks.net/wsim4827/&quot;&gt;pre-paid SIM card&lt;/a&gt; that offers unlimited data at 64kbps on T-Mobile, AND provides a static IP option. Static IP isn’t required, but it means I can add it to my smokeping config pretty easily. Of course, you need to do some research to ensure that whatever cellular plan you decide to go with is supported by whatever Cellular Modem you plan to purchase. The Netgear LB1120 seems to support most of the common bands in the US/Canada. You’ll need to verify for your region and area.&lt;/p&gt;

&lt;p&gt;Once you have your SIM and modem in hand, obviously you’ll need to verify everything works. I won’t go into how you should do that, but I essentially connected it to my laptop and made sure I could browse the internet via cellular. It worked surprisingly well for a 64kbps connection speed.&lt;/p&gt;

&lt;p&gt;Once you’ve verified it works and passes traffic. Plug the client part into your Mikrotik. I chose ether5.&lt;/p&gt;

&lt;h3 id=&quot;mikrotik-set-up&quot;&gt;Mikrotik Set Up&lt;/h3&gt;

&lt;p&gt;First, you’ll need to set up/name the interface something useful. I chose ‘&lt;strong&gt;lte&lt;/strong&gt;’, not to be confused with ‘&lt;strong&gt;lteN&lt;/strong&gt;’ interfaces that might get created if you plug an LTE modem into the USB port on some Mikrotik devices.&lt;/p&gt;

&lt;p&gt;NOTE: You can do 100% of this via the Winbox/Webfig interface. It’s just WAY easier to provide CLI commands instead of million screenshots. You can probably figure out where to look in the GUI tools by reading the commands…&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/interface ethernet
set [ find default-name=ether5 ] l2mtu=1598 mac-address=00:0D:B9:aa:bb:cc name=lte speed=100Mbps
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next you’ll need to set up a static default route towards the LTE modem. There are two important bits to pay attention to here.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Set the distance to something higher than your primary ISP. (I chose 5)&lt;/li&gt;
  &lt;li&gt;The routing-mark will be used later on. Make sure you set it to something that makes sense. (I chose use-lte).&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ip route
add comment=&quot;Default Route to LTE&quot; distance=5 gateway=192.168.5.1 routing-mark=use-lte
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, we’ll set up some firewall NAT and Mangle rules to massage the traffic to our will.&lt;/p&gt;

&lt;p&gt;To start, we’ll need to set up NAT for packets egressing the &lt;strong&gt;lte&lt;/strong&gt; interface.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ip firewall nat
add action=masquerade chain=srcnat out-interface=lte
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next a handful of Mange rules are necessary to mark connections and packets to ensure that when packets are received on the &lt;strong&gt;lte&lt;/strong&gt; interface, they egress back out the &lt;strong&gt;lte&lt;/strong&gt; interface.&lt;/p&gt;

&lt;p&gt;This was a little confusing me at first, so I’ll try to explain what they do in order.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Any packets received on the &lt;strong&gt;lte&lt;/strong&gt; interface, set a connection-mark of &lt;strong&gt;lte-packets&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Any packets that are forwarded by the router that have a connection-mark of &lt;strong&gt;lte-packets&lt;/strong&gt;, set the routing-mark &lt;strong&gt;use-lte&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Any packets originated by the router itself and sent out the &lt;strong&gt;lte&lt;/strong&gt; interface, set the routing-mark &lt;strong&gt;use-lte&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ip firewall mangle
add action=mark-connection chain=prerouting in-interface=lte new-connection-mark=lte-packets passthrough=no
add action=mark-routing chain=prerouting connection-mark=lte-packets new-routing-mark=use-lte passthrough=no
add action=mark-routing chain=output connection-mark=lte-packets new-routing-mark=use-lte passthrough=no
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Last, we need to set up a specific rule to set the &lt;strong&gt;use-lte&lt;/strong&gt; routing-mark on packets from my Hubitat hub. BUT, we’ll want to keep it disabled so it only gets used when the primary ISP is down.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;add action=mark-routing chain=prerouting comment=from-hubitat-rule disabled=yes new-routing-mark=use-lte passthrough=no src-address=10.100.100.82
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And last-last, we should probably add some firewall filters to prevent nefarious things from happening.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;We allow inbound &lt;strong&gt;ICMP&lt;/strong&gt; (so things like smokeping pointed at the cellular IP will work).&lt;/li&gt;
  &lt;li&gt;We allow only &lt;strong&gt;ESTABLISHED&lt;/strong&gt; and &lt;strong&gt;RELATED&lt;/strong&gt; packets to ingress the &lt;strong&gt;lte&lt;/strong&gt; interface.&lt;/li&gt;
  &lt;li&gt;And then we drop everything else.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ip firewall filter
add action=accept chain=input connection-state=established,related in-interface=lte protocol=icmp
add action=accept chain=forward connection-state=established,related in-interface=lte
add action=drop chain=input in-interface=lte
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;testing-time&quot;&gt;Testing time!&lt;/h3&gt;

&lt;p&gt;Everything we’ve done so far is all you really need to allow your chosen device to use the cellular modem. You can manually enable that last rule and see if your device can ping/talk via cellular. Go ahead and try it!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you are trying to trigger a push notification from a Hubitat hub, you’ll likely find that it doesn’t work. The reason is that the Hubitat hub maintains a constant TCP session with a host in AWS for push notifications.&lt;/p&gt;

&lt;p&gt;Okay..what’s that mean. Well, Mikrotik/RouterOS does connection tracking for NAT. By default the timeout for &lt;strong&gt;TCP Established&lt;/strong&gt; is set to 1 day. WAY longer than I want to wait for things to fail over in an outage (and frankly longer than I’ve ever had an ISP outage). You can change this to something lower with the following. There may be rammifications for setting this too low, but likely nothing too worrisome.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ip firewall connection tracking
set tcp-established-timeout=2m
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Or if you don’t want to wait…&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ip firewall connection print
... find all of the connections for your chosen device ...
/ip firewall connection remove &amp;lt;numbers&amp;gt;
... &amp;lt;numbers&amp;gt; represents the list of connections you found.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;so-how-do-we-make-it-happen-automatically&quot;&gt;So how do we make it happen automatically?&lt;/h3&gt;

&lt;p&gt;Mikrotik has a built-in function called a &lt;strong&gt;netwatch&lt;/strong&gt;. It’s not very eloquent, but it allows you to run commands (or scripts) based on whether a given IP is reachable via ping. We’ll set up two netwatch rules below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; There are likely better ways to do this, like with scripts or some other method. This worked for me and has proved to be pretty simple to get up and running.&lt;/p&gt;

&lt;p&gt;First you need to pick an IP on the general internet that should pretty much always be reachable. I chose Google’s public resolver &lt;strong&gt;8.8.8.8&lt;/strong&gt;. (This IP probably gets Gbps of ICMP traffic…)&lt;/p&gt;

&lt;p&gt;Then we create a netwatch rule. There a few interesting bits here, so I’ll try to explain.
The rule has three components.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Target host (and how own to test, I chose &lt;strong&gt;8.8.8.8&lt;/strong&gt; and every &lt;strong&gt;30s&lt;/strong&gt;).&lt;/li&gt;
  &lt;li&gt;A &lt;strong&gt;down-script&lt;/strong&gt;. (A list of commands to run when 8.8.8.8 is unreachable. Primary ISP Down)&lt;/li&gt;
  &lt;li&gt;An &lt;strong&gt;up-script&lt;/strong&gt;. (A list of commands to run when 8.8.8.8 is back. Primary ISP Up)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Down-script, unpacked.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Enable the rule for packets from the Hubitat hub we set up (but disabled) earlier.
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:set [/ip firewall mangle set [ find comment=\&quot;from-hubitat-rule\&quot; ] disabled=no];&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Up-script, unpacked.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Re-Disable the rule for packets from the Hubitat hub. (Remember, we only want it enabled when the primary ISP is down.)
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:set [/ip firewall mangle set [ find comment=\&quot;from-hubitat-rule\&quot; ] disabled=yes];&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Clear/Remove all connections that are currently marked with the lte-packets connection-mark. (We do this to make the Hubitat hub immediately establish a new connection with the notification server back on the Primary ISP.)
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ip firewall connection remove [ find connection-mark=lte-packets ]&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/tool netwatch
add comment=&quot;Check for primary ISP function (ping 8.8.8.8). Disable/Enable Hubitat table/rules based on result.&quot; down-script=\
    &quot;:set [/ip firewall mangle set [ find comment=\&quot;from-hubitat-rule\&quot; ] disabled=no];&quot; host=8.8.8.8 interval=30s up-script=\
    &quot;:set [/ip firewall mangle set [ find comment=\&quot;from-hubitat-rule\&quot; ] disabled=yes];\
    \n/ip firewall connection remove [ find connection-mark=lte-packets ]&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The clever among you might say “But Ryan, since we picked 8.8.8.8, wouldn’t that be reachable via Cellular as well?” Yes, it would. So we create a firewall filter to block it on the &lt;strong&gt;lte&lt;/strong&gt; interface.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ip firewall filter
add action=drop chain=input comment=&quot;Drop inbound from 8.8.8.8 on lte for netwatch script&quot; in-interface=lte src-address=8.8.8.8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And if you want, (this part isn’t required), I set up a second netwatch rule to check the status of the cellular modem itself. It can definitely be improved as I’m just checking whether the modem itself responds, NOT whether the cellular service is working. If it’s down for whatever reason, there’s no reason for the first netwatch rule to try and alter anything. I set it up as follows.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/tool netwatch
add comment=&quot;Disable the 8.8.8.8 check if LTE is dead.&quot; down-script=&quot;:set [/tool netwatch set [ find host=8.8.8.8 ] disabled=yes]];&quot; host=192.168.5.1 interval=15s up-script=\
    &quot;:set [/tool netwatch set [ find host=8.8.8.8 ] disabled=no]];&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;testing-time-2&quot;&gt;Testing Time 2!&lt;/h3&gt;

&lt;p&gt;Everything is in place for automatic failover (and back) if your primary ISP fails. But how do we test it without unplugging primary ISP?&lt;/p&gt;

&lt;p&gt;Simple. You add a static route to point your chosen test host (8.8.8.8 in my case) to the lte interface, where we have it blocked. And since we have a netwatch rule for 8.8.8.8, it will appear down and trigger our failover. Here’s how I built it. It’s disabled by default.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ip route
add disabled=yes distance=1 dst-address=8.8.8.8/32 gateway=192.168.5.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Any time you want to test your failover, you can toggle this static route and traffic from your chosen host (my Hubitat) switch to the cellular connection and back.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;There you have it. A functional automatic failover system. Is it perfect? No. But it will get the job done 90%+ of the time.&lt;/p&gt;

&lt;p&gt;Feel free to drop me a line on twitter if you have any questions.&lt;/p&gt;</content><author><name>Ryan Harden</name></author><category term="blog" /><category term="networking" /><category term="Home-Automation" /><category term="Hubitat" /><category term="Cellular" /><category term="Mikrotik" /><summary type="html">Preface I’ve been long-time subscriber to home automation. It started with the original Nest thermostat. I loved being able to control it via an app on my phone. The ‘learning’ part wasn’t as interesting since shortly after installing it, I switched to 100% remote work.</summary></entry><entry><title type="html">Second Post</title><link href="https://www.mttf.io/blog/second-post/" rel="alternate" type="text/html" title="Second Post" /><published>2019-08-01T15:45:00+00:00</published><updated>2019-08-01T15:45:00+00:00</updated><id>https://www.mttf.io/blog/second-post</id><content type="html" xml:base="https://www.mttf.io/blog/second-post/">&lt;p&gt;Adding a second page as a test. I know this is boring so far, bear with me.&lt;/p&gt;</content><author><name>Ryan Harden</name></author><category term="blog" /><summary type="html">Adding a second page as a test. I know this is boring so far, bear with me.</summary></entry><entry><title type="html">Hello, World.</title><link href="https://www.mttf.io/blog/hello-world/" rel="alternate" type="text/html" title="Hello, World." /><published>2019-08-01T15:00:00+00:00</published><updated>2019-08-01T15:00:00+00:00</updated><id>https://www.mttf.io/blog/hello-world</id><content type="html" xml:base="https://www.mttf.io/blog/hello-world/">&lt;p&gt;Consider this my “Hello, World!” post. It’s going to take some time learning Jekyll, so there might be a handful of test posts and gibberish for the next few weeks. Then expect some semi-useful content.&lt;/p&gt;

&lt;p&gt;Working on this from the back row at PEARC19, plenary session with NSF Directors. Good stuff.&lt;/p&gt;</content><author><name>Ryan Harden</name></author><category term="blog" /><summary type="html">Consider this my “Hello, World!” post. It’s going to take some time learning Jekyll, so there might be a handful of test posts and gibberish for the next few weeks. Then expect some semi-useful content.</summary></entry></feed>