<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>unixdude.net</title><link href="https://www.unixdude.net/" rel="alternate"></link><link href="https://www.unixdude.net/feeds/all.atom.xml" rel="self"></link><id>https://www.unixdude.net/</id><updated>2026-02-10T00:00:00-05:00</updated><entry><title>PSR-100 satellite rotor</title><link href="https://www.unixdude.net/posts/2026/Feb/10/psr-100-satellite-rotor/" rel="alternate"></link><published>2026-02-10T00:00:00-05:00</published><updated>2026-02-10T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2026-02-10:/posts/2026/Feb/10/psr-100-satellite-rotor/</id><summary type="html">&lt;p&gt;I have long been fascinated by ham radio satelites, but once you get past
the most basic setup of an &lt;a href="https://arrowantennas.com"&gt;Arrow II&lt;/a&gt; or &lt;a href="https://elkantennas.com/product/dual-band-2m440l5-log-periodic-antenna/"&gt;Elk&lt;/a&gt; antenna and an HT, the
required equipment can become prohibitive in both size and expense.&lt;/p&gt;
&lt;p&gt;Enter the &lt;a href="https://wa4mcmkits.com/psr-100/"&gt;PSR-100&lt;/a&gt;, a small rotor kit
that is designed to &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2026/Feb/10/psr-100-satellite-rotor/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have long been fascinated by ham radio satelites, but once you get past
the most basic setup of an &lt;a href="https://arrowantennas.com"&gt;Arrow II&lt;/a&gt; or &lt;a href="https://elkantennas.com/product/dual-band-2m440l5-log-periodic-antenna/"&gt;Elk&lt;/a&gt; antenna and an HT, the
required equipment can become prohibitive in both size and expense.&lt;/p&gt;
&lt;p&gt;Enter the &lt;a href="https://wa4mcmkits.com/psr-100/"&gt;PSR-100&lt;/a&gt;, a small rotor kit
that is designed to hold those handheld Arrow II and Elk antennas.
This is both cheaper and smaller than the amazing
&lt;a href="https://www.yaesu.com/product-detail.aspx?Model=G-5500DC&amp;amp;CatName=Rotators"&gt;Yaesu G-5500&lt;/a&gt;/&lt;a href="https://www.m2inc.com/FGLEOPACK"&gt;M2 LEO Satellite antenna&lt;/a&gt; setup.  I am
sure it will be less performant, but right now for me size and cost
are top concerns.&lt;/p&gt;
&lt;p&gt;I really like the Yaesu G-5500 setup with the M2 LEO Satellite antennas,
but I live in an HOA where that type of setup is not allowed, so I started looking
for something that would effectively be the little brother of the awesome 5500/M2 setup.
This PSR-100 + an Elk or Arrow II antenna seems to be just that.&lt;/p&gt;
&lt;p&gt;I got my kit last week and soldered the board over the weekend.  I should
finish my build this week, then I will be able to try it out.&lt;/p&gt;
&lt;p&gt;This kit requires a Windows laptop to control the rotor.  It has an interesting
design where the link between the computer and the rotor is not wired but is
instead a private wifi network between the kit's two ESP32 devices.  One ESP32
is installed on the rotor control board and the other is found in a USB dongle
that plugs into the computer.  The companion Windows software uses the private wifi
connection to control the rotor.&lt;/p&gt;
&lt;p&gt;The Windows software can also act as a go-between to allow the rotor to
be controlled by a &lt;a href="http://www.csntechnologies.net/sat"&gt;CSN SAT controller&lt;/a&gt;,
with the CSN SAT configured to control a PST Rotator, using the laptop's
IP address as the rotator IP address.&lt;/p&gt;
&lt;p&gt;My plan is to use this rotor with an Elk antenna, a CSN SAT controller,
and an &lt;a href="https://www.icomamerica.com/lineup/products/IC-9700/"&gt;Icom IC-9700&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I chose the Elk over an Arrow mainly because I wanted a faster and simpler
setup. Since I cannot have a permanent satellite station at home, I will
be using this in portable/temporary setups, both in my driveway and in parks,
so setup time and complexity must be considered.  There are trade-offs with
this setup: Instead of having 2 cables, I will instead need a duplexer, but
I already have a &lt;a href="https://www.cometantenna.com/product/comet-cf-416b/"&gt;Comet CF-416B&lt;/a&gt;,
so I will be using that.  I have ordered a coax cable from &lt;a href="https://abrind.com/product/amateur-radio-coax-builder/"&gt;ABR Industries&lt;/a&gt;,
and that should arrive soon.&lt;/p&gt;
&lt;p&gt;Based on what I have seen so far, this kit is top shelf.  This kit came
extremely well-packed and ready to build.  I didn't take a picture of it when
I opened the box, but I took pictures of the box and then all the components.
Don has done a great job with this kit, as you can see.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Box" src="/images/psr100/box.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Components" src="/images/psr100/components.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Don has a comprehensive pre-assembly test guide, and I took this pic while
I was running those tests.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Board" src="/images/psr100/board.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I look forward to finishing this project and then using this setup to make satellite contacts.
I might even try to work satellites during a POTA activation.&lt;/p&gt;</content><category term="Ham radio"></category><category term="satellite"></category></entry><entry><title>Comics</title><link href="https://www.unixdude.net/posts/2025/Oct/26/comics/" rel="alternate"></link><published>2025-10-26T00:00:00-04:00</published><updated>2025-10-26T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2025-10-26:/posts/2025/Oct/26/comics/</id><summary type="html">&lt;p&gt;For 15-20 years, I have run a script that gathers daily images for several comic strips.
Recently, this script stopped working, and rather than fix it (it is Perl code that at
this point has become unmaintainable) I decided to look for an OSS solution.&lt;/p&gt;
&lt;p&gt;Web searches quickly led me &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2025/Oct/26/comics/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;For 15-20 years, I have run a script that gathers daily images for several comic strips.
Recently, this script stopped working, and rather than fix it (it is Perl code that at
this point has become unmaintainable) I decided to look for an OSS solution.&lt;/p&gt;
&lt;p&gt;Web searches quickly led me to &lt;a href="https://dosage.rocks"&gt;dosage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dosage can output HTML files, and it seems that, generally, people have Dosage output
saved to a directory accessible on a web server.  I wanted to do this too, but I also
wanted to have this fully deployed via Ansible, and I wanted it to integrate with my
Traefik server, with everything running in Docker images.&lt;/p&gt;
&lt;p&gt;Also, there is &lt;a href="https://github.com/webcomics/dosage/issues/346"&gt;an issue&lt;/a&gt; affecting Dosage's
ability to download from GoComics, but there is also a workaround (posted in that thread)
that is not yet available in the main Dosage code, so I wanted my Docker container to
incorporate that fix.&lt;/p&gt;
&lt;p&gt;I ended up with a very simple Docker container, a volume to store the images, and a cron job
to run load the strips each day.&lt;/p&gt;
&lt;p&gt;Credit for the download.sh script goes to Simon Szustkowski, in his &lt;a href="https://github.com/simonszu/dosage-docker"&gt;dosage-docker&lt;/a&gt;
repository.&lt;/p&gt;
&lt;p&gt;I tried out Simon's image, but found that it was not suitable for my needs, due to the GoComics
issue mentioned above.  And, my solution is not a fork of his, but rather a similar solution.&lt;/p&gt;
&lt;p&gt;The code to build my Dosage docker image is found &lt;a href="https://github.com/ataridude/dosage-docker"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm using this as a one-shot container -- I do not leave it running.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The other side of this is having it on the web.  Since I am already running Traefik, and
since I only need to present a few files on the web, I decided to add this as another
web server container connected to Traefik.  Among other benefits, this means I easily get SSL
using my existing configuration.&lt;/p&gt;
&lt;p&gt;All I had to do on this side was to add another DNS entry (comics.unixdude.net), another
call to my &lt;a href="https://github.com/ataridude/ansible/tree/master/roles/traefik-website"&gt;traefik-website&lt;/a&gt;
role, and a little bit of configuration of that new role.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The only remaining pieces were to add a directory in which to store the images, and a cron job
to run the dosage-docker container once daily.&lt;/p&gt;</content><category term="General"></category><category term="docker"></category></entry><entry><title>New NAS</title><link href="https://www.unixdude.net/posts/2025/Aug/24/new-nas/" rel="alternate"></link><published>2025-08-24T00:00:00-04:00</published><updated>2025-08-24T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2025-08-24:/posts/2025/Aug/24/new-nas/</id><summary type="html">&lt;p&gt;I recently discovered that my offsite backup NAS, a Synology DS118 with a 12TB drive in it,
had filled up.  I considered several solutions to this problem, eventually deciding to replace
the DS118 with a DS225+.  Since &lt;a href="https://www.tomshardware.com/pc-components/nas/synology-requires-self-branded-drives-for-some-consumer-nas-systems-drops-full-functionality-and-support-for-third-party-hdds"&gt;Synology now requires Synology-branded drives&lt;/a&gt;,
I had to either buy two new drives &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2025/Aug/24/new-nas/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently discovered that my offsite backup NAS, a Synology DS118 with a 12TB drive in it,
had filled up.  I considered several solutions to this problem, eventually deciding to replace
the DS118 with a DS225+.  Since &lt;a href="https://www.tomshardware.com/pc-components/nas/synology-requires-self-branded-drives-for-some-consumer-nas-systems-drops-full-functionality-and-support-for-third-party-hdds"&gt;Synology now requires Synology-branded drives&lt;/a&gt;,
I had to either buy two new drives or I had to shift some drives around.&lt;/p&gt;
&lt;p&gt;To save some money, I decided to shift drives around rather than buy two new drives for the DS225+,
because the 12TB drive would work nicely in my local backup NAS, and I recently purchased two 6TB
Synology HDDs to replace dead drives in my local NAS units.  I decided to buy a single 16TB
Synology drive in conjuntion with using one of my recently purchased 6TB drives; as a result, I
have about 22TB in the DS225+.&lt;/p&gt;
&lt;p&gt;I decided to configure these drives as two basic volumes, rather than as a single volume, because I
don't care about redundancy for this unit, and because I do not want a single failed drive to
destroy all of my remote backup data, which is what would happen in a JBOD setup.&lt;/p&gt;
&lt;p&gt;After I installed the 16TB drive, I started priming the backup.  For my remote backup solution,
I use Synology's Hyper Backup because it works well, works fine over WireGuard, and is easy to use.
A short while after starting to prime the new backup, I noticed that the operation was taking
forever... I traced this down to a bad switch port on my desktop switch: The backup was running
at only 100Mbps!  Simply relocating the cable fixed the issue.&lt;/p&gt;
&lt;p&gt;Once the backup is primed, I will take it back to my friend's house, and I will reconfigure Hyper
Backup to point to the new location.&lt;/p&gt;
&lt;p&gt;Access to the unit will be over WireGuard -- the DS225+ will connect to one of my DigitalOcean VMs, and
OSPF will allow me to easily route to it.  For WireGuard on the Synology, I used
&lt;a href="https://www.youtube.com/watch?v=uPjAirU4occ"&gt;this guide&lt;/a&gt; to find the installation SPK, then
I followed the standard WireGuard setup.  I generated the key by running something like this: &lt;code&gt;wg genkey | tee private.key | wg pubkey &amp;gt; public.key&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then I configured the WireGuard client on the DS225+ by creating &lt;code&gt;/etc/wireguard/wg0.conf&lt;/code&gt; with these contents:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[Interface]&lt;/span&gt;
&lt;span class="na"&gt;Address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;192.168.x.x/30&lt;/span&gt;
&lt;span class="na"&gt;SaveConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;Table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;off&lt;/span&gt;
&lt;span class="na"&gt;PrivateKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;GENERATED_PRIVATE_KEY&lt;/span&gt;

&lt;span class="k"&gt;[Peer]&lt;/span&gt;
&lt;span class="na"&gt;PublicKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PEER_PUBLIC_KEY&lt;/span&gt;
&lt;span class="na"&gt;AllowedIPs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;0.0.0.0/0, ::/0&lt;/span&gt;
&lt;span class="na"&gt;Endpoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;hostname:port&lt;/span&gt;
&lt;span class="na"&gt;PersistentKeepalive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once the peer was configured as well, a simple &lt;code&gt;wg-quick up wg0&lt;/code&gt; on the DS225+ was all I needed to establish
the connection.&lt;/p&gt;
&lt;p&gt;In order to ensure that this connection is started when the NAS boots, I also ran &lt;code&gt;wg-autostart enable wg0&lt;/code&gt;
on the DS225+.&lt;/p&gt;
&lt;p&gt;WireGuard + FRR really is a great solution for remote systems like this offsite backup NAS.&lt;/p&gt;</content><category term="General"></category><category term="hardware"></category><category term="synology"></category><category term="frr"></category><category term="backup"></category></entry><entry><title>Ultimate Hacking Keyboard</title><link href="https://www.unixdude.net/posts/2025/May/11/ultimate-hacking-keyboard/" rel="alternate"></link><published>2025-05-11T00:00:00-04:00</published><updated>2025-05-11T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2025-05-11:/posts/2025/May/11/ultimate-hacking-keyboard/</id><summary type="html">&lt;p&gt;I recently received some advice that I should set up a more ergonomic
workstation at home: a split keyboard, an ergonomic mouse, and an
adjustable sitting/standing desk.&lt;/p&gt;
&lt;p&gt;I did a lot of research about keyboards and decided that an ortholinear
or column staggered unit was not for me.  I &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2025/May/11/ultimate-hacking-keyboard/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently received some advice that I should set up a more ergonomic
workstation at home: a split keyboard, an ergonomic mouse, and an
adjustable sitting/standing desk.&lt;/p&gt;
&lt;p&gt;I did a lot of research about keyboards and decided that an ortholinear
or column staggered unit was not for me.  I wanted something that would
work in both split and one-piece configurations, and something somewhat
close to what I already knew because I do frequently use the onboard
keyboards on my laptops.  In my research, I eventually
discovered the
&lt;a href="https://ultimatehackingkeyboard.com/"&gt;Ultimate Hacking Keyboard&lt;/a&gt;.
This is a fully programmable unit, with layers and macro support.&lt;/p&gt;
&lt;p&gt;Right around the time I was looking for a new keyboard, a fellow
employee in California listed his spare
&lt;a href="https://ultimatehackingkeyboard.com/uhk60"&gt;UHK60 v2&lt;/a&gt; for sale,
including a carry case and both the 3-key cluster and trackpoint
modules, and I bought it.&lt;/p&gt;
&lt;p&gt;I received it on Monday of this week, and I immediately plugged it in
and started using it.  I had never used a programmable keyboard before,
and I had never used a split keyboard, and it has been 20 years or more
since I last used a mechanical keyboard.&lt;/p&gt;
&lt;p&gt;My previous keyboard was the Apple one -- I have a 2025 MacBook Air, a
2024 MacBook Pro, and an &lt;a href="https://en.wikipedia.org/wiki/Apple_Wireless_Keyboard"&gt;A1314&lt;/a&gt;
-- all have the same basic Apple layout (the newer ones have fingerprint
sensors in the location where the old one had an eject key; this is the main
difference).  The UHK60 is a 60% keyboard, so when compared to the Apple
keyboards I have used for decades, the UHK is missing the function keys,
escape key, and arrow keys.  All of these are accessed through layers on
the UHK, a layer meaning that you press a modifier key (such as the UHK's
Fn or Mod key) to access that key.&lt;/p&gt;
&lt;p&gt;My first day was very rough -- I kept my A1314 close at hand, just behind
the UHK, and I kept using the A1314 to do things that I had not sorted out
how to do on the UHK.  It was easy to get used to the split keyboard; it
was difficult to get used to accessing keys through layers.&lt;/p&gt;
&lt;p&gt;On Tuesday, the A1314 was a little farther away to
the side, but I still used it quite frequently.  By this point I had started
reconfiguring the UHK to have it do what I wanted it to do... somewhat like
how I decide where to put things in my house: Where will I look for that
thing? When I found myself doing a particular key sequence for a function,
I made that shortcut do that function, rather than always forcing myself to
learn the default UHK shortcut for that function.  This is, after all, the
point of the UHK: you program it how you want it to operate.&lt;/p&gt;
&lt;p&gt;The default UHK layout for the modifier keys matches that of a PC keyboard,
not a Mac keyboard, so one other thing I did early on was to pull all of
the modifier keycaps and reorder them to be more like the Apple keyboard,
but I swapped the left function and left control keys, because the order
of those two keys has always annoyed me on the Apple keyboard.  Doing all
that resulted in a much higher positive hit rate, and on Wednesday my old
A1314 keyboard was at the edge of my desk, still powered on and available
if I needed it, but I hardly used it.  On Thursday the Apple keyboard was
in the drawer, powered off.&lt;/p&gt;
&lt;p&gt;There is much to learn here, and I am almost certainly going to change out
the silent pink switches in this keyboard for something with at least tactile
feedback, but most likely I will go with a clicky key.  I am going to test
out a few switches and then buy replacements.&lt;/p&gt;
&lt;p&gt;At this point I greatly prefer the UHK over the Apple keyboard, and look
forward to learning everything that it can do, and further tweaking it to
best fit my usage.&lt;/p&gt;
&lt;p&gt;As you can see in the first picture, I have also replaced my Apple Magic Mouse
with a more ergonomic Logitech MX Master 3S.  So far so good with that one.&lt;/p&gt;
&lt;p&gt;&lt;img alt="UHK60 v2 split" src="/images/uhk/IMG_3231.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="UHK60 v2 joined" src="/images/uhk/IMG_3238.jpg"&gt;&lt;/p&gt;</content><category term="General"></category><category term="hardware"></category></entry><entry><title>Bye bye Time Machine</title><link href="https://www.unixdude.net/posts/2024/Aug/24/bye-bye-time-machine/" rel="alternate"></link><published>2024-08-24T00:00:00-04:00</published><updated>2024-08-24T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2024-08-24:/posts/2024/Aug/24/bye-bye-time-machine/</id><summary type="html">&lt;p&gt;In my family, we have a half-dozen Mac laptops -- one for each
of us, and one provided by my employer.  For the personal laptops,
I have been using Time Machine, backing up to my primary Synology
unit.  Unfortunately, Time Machine has proven unreliable, requiring
frequent resets of the backup.  For &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2024/Aug/24/bye-bye-time-machine/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;In my family, we have a half-dozen Mac laptops -- one for each
of us, and one provided by my employer.  For the personal laptops,
I have been using Time Machine, backing up to my primary Synology
unit.  Unfortunately, Time Machine has proven unreliable, requiring
frequent resets of the backup.  For every system, I have had to
reset the backups multiple times -- that is, I have had to completely
erase the backup on the Synology, and have Time Machine do another
full backup.  This happened to my laptop backup so many times that
a few months back, I migrated my laptop's backup to rsync,
using an NFS automount on my Synology as the destination.  I run
this in a cron job, and I use &lt;a href="https://healthchecks.io/"&gt;healthchecks.io&lt;/a&gt;
to watch the status of the cron jobs.&lt;/p&gt;
&lt;p&gt;The cron job is simple, just something to run the script every 2 hours:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*/&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rsync_mba&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For the health check, I use a simple check type, with a 1-day period
and a 2-day grace time.  I use the 2-day grace time because I do not
want to get notified of a failed backup just because I unplugged my
laptop for the weekend.&lt;/p&gt;
&lt;p&gt;Today, I configured this style of backup for all of my family laptops.
I chose to do it now because my younger son's laptop refuses to restart
Time Machine: it repeatedly warns that the TM hard drive was replaced,
and forces me to confirm that I want to use the drive -- but then it
never starts the backup.  So, his system has been without a backup,
until today when I configured this rsync style backup.&lt;/p&gt;
&lt;p&gt;The script itself is also simple, basically just an rsync, but with a
bunch of excludes for things that need to be excluded on macOS.  Also,
the script maintains status files and it has a variable holding the
healthchecks.io ping URL.&lt;/p&gt;
&lt;p&gt;The script checks the exit code from rsync, and does various things
based on the exit code.  For example, rsync exit code 23 means the
transfer was partially successful, and I log this as a success, but
I also note that it happened.  rsync exit code 24 means that some
source files disappeared.  I log this as a success without qualification.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;One thing I maintain is a travel router; this is new in my toolkit, and
I should post about it.  Anyway, a short summary is that my travel
router has an always-on WireGuard VPN to my home network via one of my
Digital Ocean VMs.  I do not want backups to occur while I am connected
this way, so my NAS sets the export to be read/write only for my home 
network's IP subnet.  This way, I do not eat up lots of bandwidth while
I am not at home -- such as when I am using Starlink or wifi at a condo
or resort.&lt;/p&gt;</content><category term="General"></category><category term="macos"></category><category term="backup"></category><category term="rsync"></category></entry><entry><title>F150 radio install update</title><link href="https://www.unixdude.net/posts/2024/May/26/f150-radio-install-update/" rel="alternate"></link><published>2024-05-26T00:00:00-04:00</published><updated>2024-05-26T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2024-05-26:/posts/2024/May/26/f150-radio-install-update/</id><summary type="html">&lt;p&gt;A while back, I moved my FT-7800R to my hamshack, and bought an FTM-400XDM to replace
it in the truck, so I thought an update was in order.  I never fully mounted the FT-7800R
control head, but after switching to the FTM-400, I finished the permanent install by
mounting the &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2024/May/26/f150-radio-install-update/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;A while back, I moved my FT-7800R to my hamshack, and bought an FTM-400XDM to replace
it in the truck, so I thought an update was in order.  I never fully mounted the FT-7800R
control head, but after switching to the FTM-400, I finished the permanent install by
mounting the control head.&lt;/p&gt;
&lt;p&gt;I bought a Bulletpoint Mounting Solutions RubiGrid
for my F150, and some RAM Mount balls and arms to mount the control head.&lt;/p&gt;
&lt;p&gt;Because the FTM-400 microphone only connects to the main radio unit, I needed
to get an extension cable for that.  I also needed a longer cable for the
control head, which I built myself since it only needed flat 4-conductor cable and
RJ 4P4C connectors, which I already had on hand.&lt;/p&gt;
&lt;p&gt;I'm pretty impressed with the results of this install.&lt;/p&gt;
&lt;p&gt;&lt;img alt="image 1" src="/images/2024/ftm-400/image1.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="image 2" src="/images/2024/ftm-400/image2.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="image 3" src="/images/2024/ftm-400/image3.jpg"&gt;&lt;/p&gt;</content><category term="Ham radio"></category><category term="ftm400"></category><category term="ft7800r"></category><category term="f150"></category></entry><entry><title>Home lab</title><link href="https://www.unixdude.net/posts/2024/May/26/home-lab/" rel="alternate"></link><published>2024-05-26T00:00:00-04:00</published><updated>2024-05-26T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2024-05-26:/posts/2024/May/26/home-lab/</id><summary type="html">&lt;p&gt;I was recently asked about how to get started with a home lab.
As with most things, the answer depends on what you want to do
with it.  But, the core components are probably pretty similar.&lt;/p&gt;
&lt;p&gt;Every home lab is going to require some sort of storage system.
For mine &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2024/May/26/home-lab/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I was recently asked about how to get started with a home lab.
As with most things, the answer depends on what you want to do
with it.  But, the core components are probably pretty similar.&lt;/p&gt;
&lt;p&gt;Every home lab is going to require some sort of storage system.
For mine, I use Synology units running Btrfs.  I currently run
a DS1821+ as my primary storage unit, with 7 disks in an SHR-2
configuration, and one SSD cache disk.  I chose SHR-2 for its
RAID6-like double disk redundancy.  My disks are so large that
the likelihood of a second failure during a rebuild was high
enough that I wanted to protect against that.&lt;/p&gt;
&lt;p&gt;I have a second Synology at home, a DS1618+, for backup purposes.
My first Synology sends Btrfs snapshots to the second.  This
backup unit uses SHR-2 like the primary, but with only 5 disks
in the array.&lt;/p&gt;
&lt;p&gt;Most home labs will implement some sort of virtualization. For my
needs, free VMware ESXi on an i7-powered Lenovo M900 with 32GB RAM
works well.  I have tried Proxmox, and I greatly prefer ESXi.  I
know there are other solutions, and I will need to evaluate those
since Broadcom has done away with the free license, meaning home
lab users are out of luck with that one now.  When I had a Dell
R610 with 192GB RAM and was a member of VMUG, I ran vSphere, but
that takes too many resources on my M900.&lt;/p&gt;
&lt;p&gt;I chose the M900 because at the time of my purchase, they were
readily available used on eBay for a couple hundred dollars, and
the i7 model supports 8 vCPUs and 32GB RAM.  Any of this type of
tiny server (there are many) should work.  My main recommendation
is to get an i7 and something that supports at least 32GB RAM.&lt;/p&gt;
&lt;p&gt;For my network, I exclusively use Ubiquiti products.  I have
multiple sites and multiple VLANs.  I run OSPF and WireGuard to
connect those sites.  This is more than a beginner will need to do.&lt;/p&gt;
&lt;p&gt;Other considerations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Backup power; I use a CyberPower 1500AVR.&lt;/li&gt;
&lt;li&gt;Monitoring; I run &lt;a href="https://kuma.unixdude.net/status"&gt;Kuma&lt;/a&gt; for basic
monitoring&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For additional reading, I recommend &lt;a href="https://linuxblog.io/home-lab-beginners-guide-hardware/"&gt;Hayden James's excellent guide&lt;/a&gt;.&lt;/p&gt;</content><category term="Homelab"></category><category term="homelab"></category><category term="esxi"></category><category term="synology"></category><category term="ubiquiti"></category><category term="raspberry pi"></category><category term="cisco"></category></entry><entry><title>Home network upgrade</title><link href="https://www.unixdude.net/posts/2024/Apr/21/home-network-upgrade/" rel="alternate"></link><published>2024-04-21T00:00:00-04:00</published><updated>2024-04-21T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2024-04-21:/posts/2024/Apr/21/home-network-upgrade/</id><summary type="html">&lt;p&gt;Over the weekend, I upgraded my network:  I replaced my Ubiquiti USG with a
UDM-SE.  I debated between the UDMP and UDM-SE, and decided on the UDM-SE
because of its added features.  As part of this upgrade, I retired my
self-hosted UniFi Controller in favor of the one on the &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2024/Apr/21/home-network-upgrade/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Over the weekend, I upgraded my network:  I replaced my Ubiquiti USG with a
UDM-SE.  I debated between the UDMP and UDM-SE, and decided on the UDM-SE
because of its added features.  As part of this upgrade, I retired my
self-hosted UniFi Controller in favor of the one on the UDM-SE.&lt;/p&gt;
&lt;p&gt;I have never done a UniFi network upgrade before, so I really wasn't sure what
to expect.  It was actually surprisingly easy, but my custom setup required a
slightly modified process and configuration after the upgrade.&lt;/p&gt;
&lt;p&gt;My biggest questions were: How does one actually replace a UniFi router?  How
does one replace the router and controller with a single unit, as I was doing?
I did some research but was never truly clear about the answers to these
questions.&lt;/p&gt;
&lt;p&gt;Replacing a controller seems to be a pretty well-known process: Take a backup,
then forget all devices in the old controller, and import the backup into the
new controller.  My concern was that I was also replacing the router, and I did
not know what the controller in the UDM-SE would do with the USG in the backup.
It did exactly what I wanted it to do: It detected the USG in the backup, and
it replaced the USG with itself.&lt;/p&gt;
&lt;p&gt;I thought I was going to have to adopt the UDM-SE and somehow figure out how to
replace the USG with it, because I thought I would need to configure the UDM-SE
with an IP address to add it to the network, then replace that address with the
one in the USG, but I was completely wrong.&lt;/p&gt;
&lt;p&gt;I had to use a slightly different process because of the configuration I had on
the USG: I used a &lt;code&gt;config.gateway.json&lt;/code&gt; file to configure WireGuard and
OSFP, and I had to remove that before taking my backup.  After the migration, I
had to add my WireGuard links and configure OSPF on the UDM-SE.&lt;/p&gt;
&lt;p&gt;In the end, this worked great except for one thing: The web UI does not seem to
allow me to configure OSPF on the WireGuard links.  OSPF on the UDM-SE peered with
my local routers, but not with my remote ones, so my routes were not optimal.
There are multiple ways to get to my remote sites, so the routes were there,
they just added another hop or 2.  This kind of defeats the purpose of WireGuard
for me.&lt;/p&gt;
&lt;p&gt;I did a lot of searches, and found &lt;a href="https://community.ui.com/questions/FRR-questions-on-UDM-Pro-SE-3-1-x/b6d128c2-5b32-49a1-b0cf-e6441e781575"&gt;this 7-month-old post&lt;/a&gt;,
and wondered if it would still work in the current version of the OS.  Turns out
it works great: After starting the FRR service, I was able to use &lt;code&gt;vtysh&lt;/code&gt; to
add the WireGuard links to my OSPF area, and to add the neighbors.  It required
one more thing to work.  I had to configure the interfaces with &lt;code&gt;ip ospf network
non-broadcast&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;wgclt1&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ospf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ospf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dead&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;interval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ospf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;network&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;broadcast&lt;/span&gt;
&lt;span class="k"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These entries mirror the other ones created on the UDM-SE, and the &lt;code&gt;ip ospf
network non-broadcast&lt;/code&gt; mirrors what I had on the USG.&lt;/p&gt;
&lt;p&gt;After I did all that, OSPF peered to the routers at the remote sites, and the
correct entries were in the routing table.  The config persists across reboots,
and it works perfectly.&lt;/p&gt;</content><category term="Network"></category><category term="ubiquiti"></category><category term="udm-se"></category><category term="usg"></category><category term="ospf"></category><category term="wireguard"></category></entry><entry><title>Solenoid installs</title><link href="https://www.unixdude.net/posts/2024/Jan/28/solenoid-installs/" rel="alternate"></link><published>2024-01-28T00:00:00-05:00</published><updated>2024-01-28T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2024-01-28:/posts/2024/Jan/28/solenoid-installs/</id><summary type="html">&lt;p&gt;A few weeks ago, I installed a solenoid in my truck, to control my ham
radio's power based on the ignition key position: I want the radio to
power on and off with the engine.&lt;/p&gt;
&lt;p&gt;As with most mobile ham radios, my radio has an auto-power-down function,
but I want &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2024/Jan/28/solenoid-installs/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;A few weeks ago, I installed a solenoid in my truck, to control my ham
radio's power based on the ignition key position: I want the radio to
power on and off with the engine.&lt;/p&gt;
&lt;p&gt;As with most mobile ham radios, my radio has an auto-power-down function,
but I want it to power on as well.  At the suggestion of a friend, I
purchased &lt;a href="https://www.amazon.com/dp/B0BJ9RQFWX"&gt;these solenoids&lt;/a&gt;.
I don't know if all ham radios do this, but mine power up when they
regain power, if they were powered on when they lost power.  So, the
solenoid will power my radio up and down.&lt;/p&gt;
&lt;p&gt;This solenoid is easy to use, as can be seen by the wiring diagram:&lt;/p&gt;
&lt;p&gt;&lt;img alt="wiring diagram" src="/images/2024/solenoids/wiring_diagram.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The hardest part of this type of job is getting through the firewall.
Fortunately, I had already done that when I &lt;a href="/posts/2022/Sep/25/ft-7800r-install/"&gt;wired up my FT-7800R in
my truck&lt;/a&gt;.  Installing this
solenoid involved only some rewiring, and placement of the solenoid.&lt;/p&gt;
&lt;p&gt;First, we had to find a switched trigger source.  We searched the
fuse box and found an unused pin that was powered only when the ignition
was switched on, so we used that, wiring it to the "positive trigger source"
pin on the solenoid.&lt;/p&gt;
&lt;p&gt;&lt;img alt="trigger source" src="/images/2024/solenoids/IMG_1119.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="installed solenoid" src="/images/2024/solenoids/IMG_1121.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;The radio ground was unchanged.  The radio power source was changed from
battery to solenoid, and the solenoid is powered directly from the battery.
It's a pretty simple install, as you can see.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Yesterday I added a solenoid to my wife's 2010 Lincoln Navigator.  I did this
because we now have a third driver in the family, and I wanted a dashcam to
have some video in case we need it.&lt;/p&gt;
&lt;p&gt;At a friend's suggestion, we bought &lt;a href="https://www.amazon.com/dp/B07VCHVTCM"&gt;this dashcam&lt;/a&gt;.
I'm not yet going to recommend this camera, but it seems okay so far.  In any case,
yesterday I finished the install, with the same professional-grade install that
I did for the radio.&lt;/p&gt;
&lt;p&gt;First, we had to find a switched trigger source.  We were able to locate an
unused (and powered!) fuse slot in the fuse box, so we used this adapter to make our own
circuit.  This goes to the solenoid positive trigger pin.  Note that we also
get the positive power line from the fuse box too.&lt;/p&gt;
&lt;p&gt;&lt;img alt="fuse box" src="/images/2024/solenoids/IMG_1117.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;We located the solenoid on the firewall at the top of the engine compartment,
similar in location to where we did it on the F-150.&lt;/p&gt;
&lt;p&gt;&lt;img alt="solenoid" src="/images/2024/solenoids/IMG_1113.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;As with the F-150, the hardest part of this job was pulling cables through
the firewall.  (The next hardest part was pulling them behind the A-pillar
trim.)&lt;/p&gt;
&lt;p&gt;&lt;img alt="firewall" src="/images/2024/solenoids/IMG_1114.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;This camera came with a 12v power plug, and I didn't want to cut that off,
so I bought a &lt;a href="https://www.amazon.com/dp/B07H1MGWFN"&gt;12v socket&lt;/a&gt;.  I then
soldered that to the wires we passed through the firewall, and I plugged
the camera into this.  Then I zip-tied this to a U-shaped beam under the
dash.&lt;/p&gt;
&lt;p&gt;&lt;img alt="12v socket" src="/images/2024/solenoids/IMG_1111.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="beam" src="/images/2024/solenoids/IMG_1108.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;All of the wires are hidden behind trim of course.  Camera is suction-cup
mounted to the windshield, and now it powers on with the ignition key.&lt;/p&gt;
&lt;p&gt;&lt;img alt="camera" src="/images/2024/solenoids/IMG_1118.jpeg"&gt;&lt;/p&gt;</content><category term="General"></category><category term="diy"></category><category term="solenoid"></category><category term="ham radio"></category><category term="dashcam"></category></entry><entry><title>ESPHome home control</title><link href="https://www.unixdude.net/posts/2024/Jan/15/esphome-home-control/" rel="alternate"></link><published>2024-01-15T00:00:00-05:00</published><updated>2024-01-15T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2024-01-15:/posts/2024/Jan/15/esphome-home-control/</id><summary type="html">&lt;p&gt;I have continued playing with my M5stack.  I now have it programmed to show
3 types of data:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The local weather forecast for the next several days; either the 5-day
forecast, or a single day at a time.&lt;/li&gt;
&lt;li&gt;The temperature and humidity readings in my home office and garage,
or &amp;#8230;&lt;/li&gt;&lt;a class="label label-primary read-more" href="/posts/2024/Jan/15/esphome-home-control/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/ol&gt;</summary><content type="html">&lt;p&gt;I have continued playing with my M5stack.  I now have it programmed to show
3 types of data:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The local weather forecast for the next several days; either the 5-day
forecast, or a single day at a time.&lt;/li&gt;
&lt;li&gt;The temperature and humidity readings in my home office and garage,
or the reading from a single location.&lt;/li&gt;
&lt;li&gt;The status of my Kasa Smart outlets.  This view also controls some of the
outlets.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I already posted about the weather forecast. This post is about the
other 2 items.&lt;/p&gt;
&lt;p&gt;My ESP32 in the garage has a PIR sensor as well as a DHT11.  The PIR sensor
is used to detect motion, which then initiates an automation to turn on the
garage light. This has been super helpful, because we do not have to leave
the garage light on: it always turns on when we enter
the garage.  The DHT11 provides temperature and humidity readings in the garage.&lt;/p&gt;
&lt;p&gt;One of the reasons I wanted the M5stack was to be able to use it as a remote
control for the house, and I have now achieved that.  The code for this is
a mess, but it can be found &lt;a href="https://github.com/ataridude/ESPHome/blob/main/m5stack_home_control.yml"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I would prefer to use arrays for things like the names of the
switches (both my "friendly name" and the Home Assistant name), and I would prefer
to use array length to know when the last item is being viewed.  I assume it is
possible to do this in ESPHome, but I don't know how to do it yet.&lt;/p&gt;
&lt;p&gt;In any case, I can now cycle through the lights, and I can control all but the
garage light (because there's no need to control this one manually).  This functionality was suprisingly easy
to add tonight, and it is super cool: Now I can carry my M5stack, and push a few
buttons to control the lights around the house.&lt;/p&gt;</content><category term="Home Assistant"></category><category term="diy"></category><category term="home assistant"></category><category term="m5stack"></category><category term="esphome"></category></entry><entry><title>ESPHome weather display on an m5stack</title><link href="https://www.unixdude.net/posts/2023/Dec/10/esphome-weather-display-on-an-m5stack/" rel="alternate"></link><published>2023-12-10T00:00:00-05:00</published><updated>2023-12-10T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2023-12-10:/posts/2023/Dec/10/esphome-weather-display-on-an-m5stack/</id><summary type="html">&lt;p&gt;After using a couple of ESP32s and doing some things with them, I
decided I wanted to get an M5stack.  I bought a &lt;a href="https://shop.m5stack.com/products/esp32-basic-core-lot-development-kit-v2-7"&gt;first generation
core&lt;/a&gt;,
and am working to use that as a display for various things around
the house.&lt;/p&gt;
&lt;p&gt;As I started using the m5stack and trying to &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2023/Dec/10/esphome-weather-display-on-an-m5stack/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;After using a couple of ESP32s and doing some things with them, I
decided I wanted to get an M5stack.  I bought a &lt;a href="https://shop.m5stack.com/products/esp32-basic-core-lot-development-kit-v2-7"&gt;first generation
core&lt;/a&gt;,
and am working to use that as a display for various things around
the house.&lt;/p&gt;
&lt;p&gt;As I started using the m5stack and trying to do this project,
I did not find a complete ESPHome m5stack "hello world" type program, or a
complete ESPHome weather "hello world" type program, so in this
project and posting, I create both of those.  I uploaded the ESPHome code
to &lt;a href="https://github.com/ataridude/ESPHome"&gt;my github repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Note from my code that I am using font Roboto-Medium.ttf.  You can use any font
you like, just make sure it is uploaded to your device.&lt;/p&gt;
&lt;p&gt;Also, hopefully others find this as useful as I intend it to be, and as useful as I
would have found something like this, when I started on this project.&lt;/p&gt;
&lt;p&gt;I decided my first project would be a weather forecast display.  This
is a project that many people have done, and tonight I was able to
get the data to my M5stack.&lt;/p&gt;
&lt;p&gt;As I said, I consider this a "Hello World" type program, and I post it here
because it took me a while to piece this all together.  I found lots of
writeups from people who had done this project, but they seemed to be
assuming knowledge that I didn't have; hopefully this post includes
everything a new user needs to get this done.&lt;/p&gt;
&lt;p&gt;First, you need to create a sensor in Home Assistant.  To do this, edit
your &lt;code&gt;/homeassistant/configuration.yaml&lt;/code&gt; file.  I added the following code to mine,
using the Home Assistant File editor.  If you do not have the File editor installed,
you can add it as an Add-on.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="x"&gt;sensor:&lt;/span&gt;
&lt;span class="x"&gt;  - platform: template&lt;/span&gt;
&lt;span class="x"&gt;    sensors:&lt;/span&gt;
&lt;span class="x"&gt;      wx_forecast:&lt;/span&gt;
&lt;span class="x"&gt;        friendly_name: &amp;quot;Local forecast&amp;quot;&lt;/span&gt;
&lt;span class="x"&gt;        value_template: &amp;gt;-&lt;/span&gt;
&lt;span class="x"&gt;            &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;weather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
               &lt;span class="s2"&gt;&amp;quot;sunny&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;sunny&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
               &lt;span class="s2"&gt;&amp;quot;clear-day&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;clear-day&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
               &lt;span class="s2"&gt;&amp;quot;clear-night&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;clear-night&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
               &lt;span class="s2"&gt;&amp;quot;cloudy&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;cloudy&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
               &lt;span class="s2"&gt;&amp;quot;rainy&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;rainy&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
               &lt;span class="s2"&gt;&amp;quot;sleet&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;sleet&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
               &lt;span class="s2"&gt;&amp;quot;snow&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;snow&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
               &lt;span class="s2"&gt;&amp;quot;wind&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;wind&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
               &lt;span class="s2"&gt;&amp;quot;fog&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;fog&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
               &lt;span class="s2"&gt;&amp;quot;partlycloudy&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;partlycloudy&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
             &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;span class="x"&gt;             &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;states.weather.forecast_home.attributes.forecast&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; -&lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;span class="x"&gt;             &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;as_timestamp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;state.datetime&lt;/span&gt;&lt;span class="o"&gt;)|&lt;/span&gt; &lt;span class="nf"&gt;timestamp_custom&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%a&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="x"&gt;;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;state.templow&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="x"&gt;;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.temperature&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="x"&gt;;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.precipitation&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="x"&gt;in;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;weather&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;state.condition&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="x"&gt;#&lt;/span&gt;

&lt;span class="x"&gt;             &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt;- &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code is basically copied from &lt;a href="https://community.home-assistant.io/t/selected-forecast-items-to-esp32-epaper-display/307976/9"&gt;this post&lt;/a&gt;, but I removed the day name translation.  I could also remove the weather hash, but I kept that for now.
I also changed the format slightly - I separate the low and high temperatures into separate fields.&lt;/p&gt;
&lt;p&gt;After I edited the &lt;code&gt;configuration.yaml&lt;/code&gt; file, I checked and then reloaded the configuration on the Developer Tools page, YAML tab.
After the reload, I confirmed the existence of my state, by going to the States tab on the Developer Tools page, and
filtering states for &lt;code&gt;wx_forecast&lt;/code&gt;.  This completes and confirms the HA side.&lt;/p&gt;
&lt;p&gt;Then, in ESPHome, I added the sensor to my m5stack configuration:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;text_sensor:
  &lt;span class="k"&gt;-&lt;/span&gt; platform: homeassistant
    id: w_forecast
    entity_id: sensor.wx_forecast
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;My display code is basically copied from the same post as above.  Here is my display lambda code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fivedays&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w_forecast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;five&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;ESP_LOGD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;fivedays [&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fivedays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;five&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;strtok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;const_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fivedays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;splits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;believe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;found&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;five&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;strtok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;here&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;we&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fiv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;five&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;adds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;around&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;day&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wy&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;126&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fiv&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;ESP_LOGD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;test: &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;String to Vector: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;strtok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;strtok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;day&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Day&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Mon&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Tue&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;font_roboto_medium22&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_red&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TextAlign&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TOP_LEFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Temperature&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;font_roboto_medium22&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_red&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TextAlign&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TOP_LEFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Precipitation&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;font_roboto_medium22&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_red&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TextAlign&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TOP_LEFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;135&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;font_roboto_medium22&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_red&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TextAlign&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TOP_LEFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;210&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;font_roboto_medium22&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_red&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TextAlign&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TOP_LEFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ESP_LOGD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;test: &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;String to Vector: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;wy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;down&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pixels&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The result of all this work is a weather forecast on my m5stack:&lt;/p&gt;
&lt;p&gt;&lt;img alt="m5stack" src="/images/m5stack/first_weather.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Now that I have the data in my m5stack, I will set out to get the display how I want it.&lt;/p&gt;</content><category term="Home Assistant"></category><category term="diy"></category><category term="home assistant"></category><category term="m5stack"></category><category term="esphome"></category></entry><entry><title>Home Automation using Home Assistant</title><link href="https://www.unixdude.net/posts/2023/Nov/28/home-automation-using-home-assistant/" rel="alternate"></link><published>2023-11-28T00:00:00-05:00</published><updated>2023-11-28T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2023-11-28:/posts/2023/Nov/28/home-automation-using-home-assistant/</id><summary type="html">&lt;p&gt;A few weeks back I mentioned Home Assistant.  After I set that up, I
bought some Kasa smart outlets.  Two have replaced timers, so I no longer
have to change the start times as the time of sunset changes throughout
the year.  A third is set up in my home &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2023/Nov/28/home-automation-using-home-assistant/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;A few weeks back I mentioned Home Assistant.  After I set that up, I
bought some Kasa smart outlets.  Two have replaced timers, so I no longer
have to change the start times as the time of sunset changes throughout
the year.  A third is set up in my home office, and is set to come on an
hour before sunset.  I installed this plug because I often find myself
in a dark office at the end of my work day.  I don't even notice it
getting dark outside because I'm staring at lighted screens, so this
keeps me out of the darkness when I shut down.&lt;/p&gt;
&lt;p&gt;A couple days ago, I installed the 4th plug.  This one is in the garage, and it now
switches one of the two LED shop lights that I installed on Saturday.  The
other LED shop light is switched inside the house.  Originally, both
of those LED shop lights were switched inside the house, but that is
two 5,000 lumen shop lights -- and those replaced two 825-lumen compact
fluorescent bulbs -- so it was extremely bright, much brighter than we
were used to.  I moved one of the
shop lights to the Kasa switched outlet, which cuts down on the brightness,
but means that I would have to manually power the second light, from the app on
my phone.&lt;/p&gt;
&lt;p&gt;I happened to have a spare ESP32 and a HC-SR501 motion sensor.  A quick
web search revealed &lt;a href="https://esp32io.com/tutorials/esp32-motion-sensor"&gt;this tutorial&lt;/a&gt;,
which I used to get started.  I set my sensor for maximum
time delay as well as maximum range.  I configured the sensor in Home Assistant,
then, added two automations for the sensor: turn on the power to the garage
light smart plug when motion is detected, and turn off the power when motion
is no longer reported.  With the long time delay, we get several minutes of
light before it turns off.&lt;/p&gt;
&lt;p&gt;This entire setup and automation took me maybe 30 minutes, probably much less,
and this is one reason why I like ESPHome: It is easy to automate with an ESP32
and a sensor.  The entire config is in this one stanza:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;binary_sensor:
  &lt;span class="k"&gt;-&lt;/span&gt; platform: gpio
    pin: 13
    name: &amp;quot;motion_sensor&amp;quot;
    device_class: motion
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The automations are super simple too: I set up a trigger of "garage_sensor motion_sensor
started detecting motion," and the action is to turn on the outlet.  I have a related
automation with a trigger of "garage_sensor motion_sensor stopped detecting motion."&lt;/p&gt;
&lt;p&gt;ESP32s are so inexpensive, too, which makes automation like this super affordable.  Now I'm
trying to decide what other automation projects I will do.  I think I will automate
garage door open detection, as well as closing it.  I also want to automate the lights on
the 2nd/3rd floor staircase: the stairs are very dark.  I'm sure I will come up with
other ideas as well.&lt;/p&gt;</content><category term="Home Assistant"></category><category term="diy"></category><category term="home assistant"></category><category term="esp32"></category><category term="home automation"></category><category term="kasa"></category></entry><entry><title>Home Assistant; Ham radio digital voice</title><link href="https://www.unixdude.net/posts/2023/Nov/05/home-assistant-ham-radio-digital-voice/" rel="alternate"></link><published>2023-11-05T00:00:00-04:00</published><updated>2023-11-05T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2023-11-05:/posts/2023/Nov/05/home-assistant-ham-radio-digital-voice/</id><summary type="html">&lt;p&gt;A while ago, I bought a &lt;a href="https://www.ebay.com/itm/302057854467"&gt;Freenove starter kit&lt;/a&gt;.  I
never did much with it until recently, when a friend gave me an &lt;a href="https://en.wikipedia.org/wiki/ESP32"&gt;ESP32&lt;/a&gt;
and pointed me to &lt;a href="https://www.home-assistant.io"&gt;Home Assistant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Freenove kit included a DHT11 temperature/humidity module, so my first Home Assistant
project was to set up a &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2023/Nov/05/home-assistant-ham-radio-digital-voice/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;A while ago, I bought a &lt;a href="https://www.ebay.com/itm/302057854467"&gt;Freenove starter kit&lt;/a&gt;.  I
never did much with it until recently, when a friend gave me an &lt;a href="https://en.wikipedia.org/wiki/ESP32"&gt;ESP32&lt;/a&gt;
and pointed me to &lt;a href="https://www.home-assistant.io"&gt;Home Assistant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Freenove kit included a DHT11 temperature/humidity module, so my first Home Assistant
project was to set up a temperature/humidity sensor for my home office.  It was much easier
than I thought it would be: I downloaded and installed the &lt;a href="https://www.home-assistant.io/installation/alternative"&gt;Home Assistant OVA&lt;/a&gt;, then I installed &lt;a href="https://esphome.io"&gt;ESPHome&lt;/a&gt; on the ESP32, then
I configured the ESP32 with the DHT11 device.&lt;/p&gt;
&lt;p&gt;This is inexpensive, useful, and cool.  I can see me buying many of these ESP32 or similar devices,
using them to monitor and control various things around the house.  And, with the
&lt;a href="https://esphome.io/components/wireguard"&gt;WireGuard support in ESPHome&lt;/a&gt;,
I will be able to monitor remote devices as well, such as the temperature in my travel trailer,
which is parked at a friend's house.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Another thing I have been playing with recently is digital voice in ham radio.  A friend
lent me a &lt;a href="https://www.yaesu.com/indexVS.cfm?cmd=DisplayProducts&amp;amp;ProdCatID=111&amp;amp;encProdID=7CDB93B02164B1FB036530FBD7D37F1A&amp;amp;DivisionID=65&amp;amp;isArchived=0"&gt;Yaesu FT-70D&lt;/a&gt;
and a &lt;a href="https://www.onallbands.com/what-you-need-to-know-about-mmdvm-hotspots/"&gt;MMDVM hotspot&lt;/a&gt; running
&lt;a href="https://w0chp.radio/wpsd/"&gt;WPSD&lt;/a&gt;.  After attaching the hotspot to my home WLAN, and a small bit of
configuration, I have the FT-70D connected to the hotspot, and have a world of digital voice radio
available to me, through the many &lt;a href="https://w0chp.radio/ysf-reflectors/"&gt;YSF reflectors&lt;/a&gt; that exist.&lt;/p&gt;
&lt;p&gt;In addition to the ESP32 modules and sensors mentioned above, the FT-70D and a MMDVM hotspot are now
on my list.&lt;/p&gt;</content><category term="Home Assistant"></category><category term="diy"></category><category term="home assistant"></category><category term="esp32"></category><category term="ysf"></category><category term="home automation"></category><category term="ham radio"></category></entry><entry><title>IC-7300 external keypad</title><link href="https://www.unixdude.net/posts/2023/Oct/03/ic-7300-external-keypad/" rel="alternate"></link><published>2023-10-03T00:00:00-04:00</published><updated>2023-10-03T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2023-10-03:/posts/2023/Oct/03/ic-7300-external-keypad/</id><summary type="html">&lt;p&gt;I recently purchased an &lt;a href="https://www.icomamerica.com/lineup/products/IC-7300/"&gt;Icom IC-7300&lt;/a&gt; ham radio for use at home, and when
researching the radio around the time of purchase, I discovered
&lt;a href="https://www.youtube.com/playlist?list=PL48JZWhCJoH3bGOyfmZVxgRHFqs2VUG8P"&gt;this excellent YouTube video playlist&lt;/a&gt;,
covering many aspects of the radio.&lt;/p&gt;
&lt;p&gt;When I got to &lt;a href="https://www.youtube.com/watch?v=I3b1aNdg3pQ"&gt;video 46&lt;/a&gt;,
I discovered that the IC-7300 supports an external keypad &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2023/Oct/03/ic-7300-external-keypad/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently purchased an &lt;a href="https://www.icomamerica.com/lineup/products/IC-7300/"&gt;Icom IC-7300&lt;/a&gt; ham radio for use at home, and when
researching the radio around the time of purchase, I discovered
&lt;a href="https://www.youtube.com/playlist?list=PL48JZWhCJoH3bGOyfmZVxgRHFqs2VUG8P"&gt;this excellent YouTube video playlist&lt;/a&gt;,
covering many aspects of the radio.&lt;/p&gt;
&lt;p&gt;When I got to &lt;a href="https://www.youtube.com/watch?v=I3b1aNdg3pQ"&gt;video 46&lt;/a&gt;,
I discovered that the IC-7300 supports an external keypad, and decided
I wanted one of my own.  This past weekend, I made one.&lt;/p&gt;
&lt;p&gt;In addition to using that video, I found &lt;a href="http://www.whiskeytangohotel.com/2020/03/icom-ic7300-memory-external-keypad.html"&gt;this page&lt;/a&gt;
detailing another guy's external keypad build.&lt;/p&gt;
&lt;p&gt;I don't have a drill press, but I think my unit came out well.  I could have done a better job with the feet, but this works well enough.&lt;/p&gt;
&lt;p&gt;&lt;img alt="1" src="/images/ic-7300/1.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="2" src="/images/ic-7300/2.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="3" src="/images/ic-7300/3.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="4" src="/images/ic-7300/4.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="5" src="/images/ic-7300/5.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="6" src="/images/ic-7300/6.jpg"&gt;&lt;/p&gt;</content><category term="Ham radio"></category><category term="diy"></category><category term="IC-7300"></category><category term="ham radio"></category></entry><entry><title>Mobile Wireguard clients</title><link href="https://www.unixdude.net/posts/2023/Jul/02/mobile-wireguard-clients/" rel="alternate"></link><published>2023-07-02T00:00:00-04:00</published><updated>2023-07-02T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2023-07-02:/posts/2023/Jul/02/mobile-wireguard-clients/</id><summary type="html">&lt;p&gt;I have been using Wireguard for about a year &amp;amp; a half, when I switched
from ZeroTier to Wireguard for most of my needs.  Unfortunately, since
the start, my Wireguard configuration has been completely manual, and 
very annoying since I had to create a new interface for every client.&lt;/p&gt;
&lt;p&gt;No more &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2023/Jul/02/mobile-wireguard-clients/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have been using Wireguard for about a year &amp;amp; a half, when I switched
from ZeroTier to Wireguard for most of my needs.  Unfortunately, since
the start, my Wireguard configuration has been completely manual, and 
very annoying since I had to create a new interface for every client.&lt;/p&gt;
&lt;p&gt;No more.&lt;/p&gt;
&lt;p&gt;Today I used the &lt;a href="https://www.wireguardconfig.com"&gt;Wireguard Config Generator&lt;/a&gt;
to generate the configs (I did not specify my endpoint on the website
of course).  The result was a single server config with keys for two dozen
mobile clients.  Today I configured three of those mobile clients -- one each for
my MacBook Air, my iPhone, and my iPad.&lt;/p&gt;
&lt;p&gt;I considered using &lt;a href="https://www.netmaker.io"&gt;Netmaker&lt;/a&gt; but decided it was way more than
I needed.  The config generator made that part of the config easy.  Loading the config
into the Mac client was easy.  Loading a config file into the iOS client is not difficult,
but it was way more fun using &lt;a href="https://www.cyberciti.biz/faq/how-to-generate-wireguard-qr-code-on-linux-for-mobile/"&gt;qrencode&lt;/a&gt; to generate a QR code to configure the iOS devices.&lt;/p&gt;
&lt;p&gt;After I used the Wireguard Config Generator, I updated the client files to specify my endpoint,
then I loaded the configs and was off to the races -- with that part anyway.&lt;/p&gt;
&lt;p&gt;I had one more step to make this useful.  The entire point of my Wiregaurd config is to
remotely access my home network. But, since my Wireguard server is on a DigialOcean VM,
and I want my systems to access my home network without masquerading, this required
a configuration change to my FRR config on my DigitalOcean VM.&lt;/p&gt;
&lt;p&gt;I just had to add two blocks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;wg0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ospf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;network&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;broadcast&lt;/span&gt;
&lt;span class="k"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To the &lt;code&gt;router ospf&lt;/code&gt; configuration, I added the subnet I dedicated to my Wireguard clients:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;network 192.168.100.128/27 area 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now everything can route to my Wireguard clients, and my Wireguard clients can access my
entire network.&lt;/p&gt;</content><category term="Networking"></category><category term="wireguard"></category><category term="ipad"></category><category term="iphone"></category><category term="mobile"></category></entry><entry><title>POTA kit</title><link href="https://www.unixdude.net/posts/2023/Jun/14/pota-kit/" rel="alternate"></link><published>2023-06-14T00:00:00-04:00</published><updated>2023-06-14T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2023-06-14:/posts/2023/Jun/14/pota-kit/</id><summary type="html">&lt;p&gt;&lt;a href="https://parksontheair.com"&gt;Parks On The Air&lt;/a&gt;, or POTA, is one of the aspects of amateur radio that I have been
enjoying -- both hunting and activating.  Ever since I starting doing POTA activations, I have been carrying my
equipment in a Rubbermaid container, which is bulky and heavy.  The only thing it has &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2023/Jun/14/pota-kit/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://parksontheair.com"&gt;Parks On The Air&lt;/a&gt;, or POTA, is one of the aspects of amateur radio that I have been
enjoying -- both hunting and activating.  Ever since I starting doing POTA activations, I have been carrying my
equipment in a Rubbermaid container, which is bulky and heavy.  The only thing it has going for it is
that it carries everything I need.&lt;/p&gt;
&lt;p&gt;Pretty much since getting started doing POTA, I have wanted a battery box and a radio box.  I did a lot
of research about battery boxes, and there are many different options, both &lt;a href="https://duckduckgo.com/?q=diy+battery+box"&gt;DIY&lt;/a&gt; and &lt;a href="https://powerwerx.com/solar-portable-power"&gt;ready-made ones for purchase&lt;/a&gt;.  Somewhere I saw a build
that used the &lt;a href="https://www.harborfreight.com/tool-storage-organization/tool-boxes-bags-belts/utility-cases-ammo-boxes/tactical-ammoutility-box-64113.html"&gt;Harbor Freight Tactical Ammo Box&lt;/a&gt;, and
I decided to use that box for my build.  I went with this box because I really like the idea of having all of the controls
and connections under the flip-top lid on that box, rather than on the outside of the box, which is how
most of these boxes are built.&lt;/p&gt;
&lt;p&gt;Over the weekend, with the help of a local ham friend, I built my battery box.  Installed on my box are
dual PowerPole connectors, dual USB connectors behind a rocker switch and 5A fuse, and a 50A circuit breaker as the main power switch.  There is room for more connections should I choose to add them.&lt;/p&gt;
&lt;p&gt;The Harbor Freight box I used has the benefit of being a little larger than the typical battery box, so in
addition to the &lt;a href="https://www.bioennopower.com/collections/lifepo4-batteries-for-communication-equipment-ham-radio/products/copy-of-12v-15ah-lfp-battery-pvc-blf-1215w?variant=19610918405"&gt;Bioenno BLF-1215A&lt;/a&gt;,
I am also able to carry my 40/20/15/10 EFHW &lt;a href="https://www.thingiverse.com/thing:5448369"&gt;antenna&lt;/a&gt;,
&lt;a href="https://www.amazon.com/gp/product/B07Z5VY7B6/"&gt;NanoVNA&lt;/a&gt;, &lt;a href="https://www.amazon.com/Upgraded-Precision-Consumption-Performance-Backlight/dp/B0B8VWNY9X/"&gt;battery monitor&lt;/a&gt;, and Bioenno battery charger -- all inside the battery box.  Today, the ability to
carry all these extra items seems like a benefit; time will tell if that impression holds.&lt;/p&gt;
&lt;p&gt;I also finally cut out the foam in my &lt;a href="https://www.harborfreight.com/3800-weatherproof-protective-case-large-black-63927.html"&gt;Apache 3800&lt;/a&gt;
case to carry my radio (an &lt;a href="http://www.icomamerica.com/en/products/amateur/hf/706/default.aspx"&gt;Icom IC-706MKIIG&lt;/a&gt;), along with its microphone and power cord, and &lt;a href="https://www.niftyaccessories.com/IC-706MKIIG.php"&gt;nifty mini-manual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I am very pleased with the result for both of these, and look forward to using this kit at an upcoming POTA activation.&lt;/p&gt;
&lt;p&gt;&lt;img alt="case" src="/images/battery_box/IMG_9556.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="case" src="/images/battery_box/IMG_9557.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="case" src="/images/battery_box/IMG_9558.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="case" src="/images/battery_box/IMG_9559.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="case" src="/images/battery_box/IMG_9560.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="case" src="/images/battery_box/radio_1.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="case" src="/images/battery_box/radio_2.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="case" src="/images/battery_box/radio_3.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="case" src="/images/battery_box/both.jpeg"&gt;&lt;/p&gt;</content><category term="Ham radio"></category><category term="pota"></category><category term="battery box"></category><category term="radio box"></category><category term="ham radio"></category></entry><entry><title>DKIM, Postfix, and FreeBSD</title><link href="https://www.unixdude.net/posts/2023/May/10/dkim-postfix-and-freebsd/" rel="alternate"></link><published>2023-05-10T00:00:00-04:00</published><updated>2023-05-10T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2023-05-10:/posts/2023/May/10/dkim-postfix-and-freebsd/</id><summary type="html">&lt;p&gt;Recently, I discovered that I was not able to email my wife's mac.com address from my
mail server here.  &lt;a href="https://support.apple.com/en-us/HT204137"&gt;Apple's support document&lt;/a&gt; indicates
that they require DKIM and SPF, and that they support DMARC.  I have long had
&lt;a href="/posts/2019/Feb/14/postfix_relay/"&gt;SPF configured&lt;/a&gt;, but I had not configured DKIM or DMARC.&lt;/p&gt;
&lt;p&gt;Over &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2023/May/10/dkim-postfix-and-freebsd/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Recently, I discovered that I was not able to email my wife's mac.com address from my
mail server here.  &lt;a href="https://support.apple.com/en-us/HT204137"&gt;Apple's support document&lt;/a&gt; indicates
that they require DKIM and SPF, and that they support DMARC.  I have long had
&lt;a href="/posts/2019/Feb/14/postfix_relay/"&gt;SPF configured&lt;/a&gt;, but I had not configured DKIM or DMARC.&lt;/p&gt;
&lt;p&gt;Over the weekend, I set up DKIM.  DKIM is basically a public-key cryptographic solution used
to confirm the server that sent an email.  In order to set this up on my FreeBSD 12 server,
I followed &lt;a href="https://www.prado.it/2012/04/26/how-to-run-postfix-with-opendkim-on-freebsd-9-0/"&gt;this guide&lt;/a&gt;
which is pretty close to what I ended up doing, and I took some inspiration from
&lt;a href="https://www.dan.me.uk/blog/2016/06/01/add-dkim-signing-to-freebsd-servers/"&gt;this guide&lt;/a&gt;.
Even with these guides, I had to make a few changes to meet with success on my FreeBSD 12 system.&lt;/p&gt;
&lt;p&gt;I chose to install the package, not using source: &lt;code&gt;pkg install opendkim&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Next, instead of adding the user to the &lt;code&gt;mail&lt;/code&gt; group, I left off that parameter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;pw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;useradd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/sbin/nologin&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;no&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I had to do this because I was getting errors while trying to start opendkim.  The errors
complained that the &lt;code&gt;opendkim&lt;/code&gt; user was a member of the mail group, and that there were
several members of that group.  I'm not sure why that mattered, but I could only get it to work
this way, and I'm good with that.&lt;/p&gt;
&lt;p&gt;My milter config file is at &lt;code&gt;/usr/local/etc/mail/opendkim.conf&lt;/code&gt;, and the contents are what
the other howto shows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;LogWhy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yes&lt;/span&gt;
&lt;span class="n"&gt;Syslog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yes&lt;/span&gt;
&lt;span class="n"&gt;SyslogSuccess&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yes&lt;/span&gt;
&lt;span class="n"&gt;Canonicalization&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;relaxed&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;simple&lt;/span&gt;
&lt;span class="n"&gt;Domain&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unixdude&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;
&lt;span class="n"&gt;Selector&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iss&lt;/span&gt;
&lt;span class="n"&gt;KeyFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;iss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;private&lt;/span&gt;
&lt;span class="n"&gt;Socket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8891&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;
&lt;span class="n"&gt;ReportAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;
&lt;span class="n"&gt;SendReports&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I added the following two lines to &lt;code&gt;/etc/rc.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;milteropendkim_enable=&amp;quot;YES&amp;quot;
milteropendkim_uid=&amp;quot;opendkim&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I added the following three lines to &lt;code&gt;/usr/local/etc/postfix/main.cf&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I generated the key as shown -- &lt;code&gt;opendkim-genkey -D /var/db/opendkim -d unixdude.net -s iss&lt;/code&gt;.  The
selector (&lt;code&gt;iss&lt;/code&gt; in this case) can be any string you want.  I went with &lt;code&gt;iss&lt;/code&gt; because that is
the system name on which this is running.  This places the files in &lt;code&gt;/var/db/opendkim&lt;/code&gt;, named
&lt;code&gt;iss.private&lt;/code&gt; and &lt;code&gt;iss.txt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You create two records in DNS; for my server, I created &lt;code&gt;iss._domainkey.unixdude.net&lt;/code&gt; as a &lt;code&gt;TXT&lt;/code&gt;
record with the contents of &lt;code&gt;iss.txt&lt;/code&gt; above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root@iss(F12):/usr/local/etc/mail&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="k"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_domainkey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unixdude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;
&lt;span class="n"&gt;iss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_domainkey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unixdude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;descriptive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNKaHQWGIuv7uCByXo9/gQon4BAYKXddNS3oS21tXszTz+Z+BN+ROqZSMKyScdqYdn+dP8TBTnWENKV1BCcJLDRLXi8Nmkiafm4MAswxBtPVRwanJVgHAgPqRuy8KARI/I7LmOt4ZxGkngLgfpqC0BXUBDTIOQJNw+GZJctfKuXQIDAQAB&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root@iss(F12):/usr/local/etc/mail&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I also created &lt;code&gt;_adsp._domainkey.unixdude.net&lt;/code&gt; as 
a &lt;code&gt;TXT&lt;/code&gt; record, with the following contents:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;dkim=unknown
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When I test the key, I receive a message saying that the key is not secure, and my google
searches indicate that this means the server is not using DNSSEC.  I'm okay with this.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;iss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F12&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;testkey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vvv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unixdude&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iss&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;iss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;private&lt;/span&gt;
&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;testkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loaded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;iss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;private&lt;/span&gt;
&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;testkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;checking&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;iss._domainkey.unixdude.net&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;testkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;secure&lt;/span&gt;
&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;testkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OK&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;iss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F12&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After I checked the key, I started/reloaded the services:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;milter&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;opendkim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;postfix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After that, I was off to the races, and I can now email my wife's mac.con address again.&lt;/p&gt;</content><category term="Mail"></category><category term="dkim"></category><category term="postfix"></category><category term="freebsd"></category><category term="icloud"></category></entry><entry><title>FT-7800R install, continued</title><link href="https://www.unixdude.net/posts/2022/Oct/03/ft-7800r-install-continued/" rel="alternate"></link><published>2022-10-03T00:00:00-04:00</published><updated>2022-10-03T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-10-03:/posts/2022/Oct/03/ft-7800r-install-continued/</id><summary type="html">&lt;p&gt;Continuing my earlier post about my Yaesu FT-7800R install, I completed the radio portion
this weekend, so now I can get on the air.&lt;/p&gt;
&lt;p&gt;I had a &lt;a href="https://www.diamondantenna.net/nr770hnmo.html"&gt;Diamond NR770HNMO&lt;/a&gt; antenna, and
bought a &lt;a href="https://www.gigaparts.com/vehicle-specific-bracket-antenna-mount-ford.html"&gt;fender bracket mount for my F150&lt;/a&gt;.
All I needed was an NMO mount and to fish the &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/Oct/03/ft-7800r-install-continued/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Continuing my earlier post about my Yaesu FT-7800R install, I completed the radio portion
this weekend, so now I can get on the air.&lt;/p&gt;
&lt;p&gt;I had a &lt;a href="https://www.diamondantenna.net/nr770hnmo.html"&gt;Diamond NR770HNMO&lt;/a&gt; antenna, and
bought a &lt;a href="https://www.gigaparts.com/vehicle-specific-bracket-antenna-mount-ford.html"&gt;fender bracket mount for my F150&lt;/a&gt;.
All I needed was an NMO mount and to fish the coax line to the radio.&lt;/p&gt;
&lt;p&gt;A local ham friend had an NMO mount and a connector, so on Saturday I went to his house
to complete the install.&lt;/p&gt;
&lt;p&gt;After some doing, we got the coax through the firewall, then we ran it all the way to the
back of the cab, where the radio was mounted.  We crimped on a connector, then discovered
that the cable was too short.  By an inch.&lt;/p&gt;
&lt;p&gt;We noticed that we ran the cable in and out of a bracket in the front footwell, so I removed
one of the bracket's mounting screws and pushed the cable around the bracket.  That gave us
just enough cable length to reach the radio without relocating the radio.  Crisis averted.&lt;/p&gt;
&lt;p&gt;Then we turned it on, and we discovered that its sensitivity wasn't up to par.&lt;/p&gt;
&lt;p&gt;In the end, my friend gave me a loaner Kenwood 2m radio so I would at least be able to get on the air.&lt;/p&gt;
&lt;p&gt;When I got home, I did some experimenting with another local ham, and I found that yes, the Kenwood
is definitely a little bit more sensitive, but the Yaesu seems to be working fine at my house.
I'll use the FT-7800R for a couple weeks, then decide whether to keep or replace it.  If I replace it,
another radio should be very easy to install.&lt;/p&gt;
&lt;p&gt;The only necessary remaining piece for this install is to build or buy a mount for the faceplate.  I'm thinking
of building a wooden something that mounts to the front seat bolts and holds the faceplate in front of
the center console.&lt;/p&gt;
&lt;p&gt;In addition to that, I still want to hide the controller and speaker cables under the carpet.&lt;/p&gt;
&lt;p&gt;Anyway, now on to the pics of what was completed this weekend.&lt;/p&gt;
&lt;p&gt;First, the mounted antenna.  It's a little tight getting the coax through the crack between the fender and
the hood, but it seems to be okay.&lt;/p&gt;
&lt;p&gt;&lt;img alt="antenna" src="/images/ft7800r-install/101-antenna.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The antenna wiring heading toward the firewall:&lt;/p&gt;
&lt;p&gt;&lt;img alt="wiring" src="/images/ft7800r-install/102-wiring.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The wires going through the firewall:&lt;/p&gt;
&lt;p&gt;&lt;img alt="firewall" src="/images/ft7800r-install/103-firewall.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The radio in the back of the cab:&lt;/p&gt;
&lt;p&gt;&lt;img alt="firewall" src="/images/ft7800r-install/104-radio.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The remote face plate in the front:&lt;/p&gt;
&lt;p&gt;&lt;img alt="faceplate" src="/images/ft7800r-install/105-faceplate.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The remote face plate and mike in the front:&lt;/p&gt;
&lt;p&gt;&lt;img alt="faceplate" src="/images/ft7800r-install/106-front.jpg"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Update: A friend pointed out that I missed a couple obvious photos here, and I was also asked about how
tight the fit is between the hood and the fender.&lt;/p&gt;
&lt;p&gt;First, a pic showing the antenna (it is difficult to photo since it's so thin).&lt;/p&gt;
&lt;p&gt;&lt;img alt="antenna" src="/images/ft7800r-install/107-antenna.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Now a couple pictures of the mount, including a closeup:&lt;/p&gt;
&lt;p&gt;&lt;img alt="closeup" src="/images/ft7800r-install/108-closeup.jpg"&gt;
&lt;img alt="mount" src="/images/ft7800r-install/109-mount.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Finally a profile picture of the truck:&lt;/p&gt;
&lt;p&gt;&lt;img alt="profile" src="/images/ft7800r-install/110-profile.jpg"&gt;&lt;/p&gt;</content><category term="Ham radio"></category><category term="ft7800r"></category><category term="f150"></category></entry><entry><title>FT-7800R install</title><link href="https://www.unixdude.net/posts/2022/Sep/25/ft-7800r-install/" rel="alternate"></link><published>2022-09-25T00:00:00-04:00</published><updated>2022-09-25T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-09-25:/posts/2022/Sep/25/ft-7800r-install/</id><summary type="html">&lt;p&gt;This is not my typical type of post, but as I have said, communications and networking are
things that excite me greatly.  It's why I collect antique telephones, why I enjoy scanner
and shortwave listening, why I learned the OSI model and have spent much of my career in
and &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/Sep/25/ft-7800r-install/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is not my typical type of post, but as I have said, communications and networking are
things that excite me greatly.  It's why I collect antique telephones, why I enjoy scanner
and shortwave listening, why I learned the OSI model and have spent much of my career in
and around computer networking.&lt;/p&gt;
&lt;p&gt;It's also why, over the summer, I studied for, took, and passed the Technician amateur license
exam, after which I bought a Baofeng UV-5R.  It didn't take me long to realize that the
UV-5R does not receive anything at my house, so I quickly replaced it with a Yaesu VX-6R, which
I am finding to be an excellent HT.&lt;/p&gt;
&lt;p&gt;I also bought a Yaesu FT-7800R to install in my F150.  I finally got around to that install
today, and I know that there are lots of questions about how to install a ham radio into a
vehicle, so I am documenting my install in this post.&lt;/p&gt;
&lt;p&gt;First, there is a grommet with a nipple on it on both the driver side and the passenger side
of the F150.  I started my install by cutting the nipple slightly and running a fish tape
through the firewall through that grommet.&lt;/p&gt;
&lt;p&gt;&lt;img alt="fish tape in engine compartment" src="/images/ft7800r-install/1-fish-tape-engine.jpg"&gt;
&lt;img alt="fish tape in engine compartment" src="/images/ft7800r-install/2-fish-tape-engine.jpg"&gt;&lt;/p&gt;
&lt;p&gt;As expected, the fish tape came out in the footwell:&lt;/p&gt;
&lt;p&gt;&lt;img alt="fish tape in footwell" src="/images/ft7800r-install/3-fish-tape-footwell.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I ran the power cable through the grommet to the back of the truck, where I am installing
the FT-7800R.  Conveniently, the F150 has cable raceways under the door trim:&lt;/p&gt;
&lt;p&gt;&lt;img alt="power cable behind trim" src="/images/ft7800r-install/4-power-cable-behind-trim.jpg"&gt;
&lt;img alt="power cable in raceway" src="/images/ft7800r-install/5-power-cable-front-raceway.jpg"&gt;&lt;/p&gt;
&lt;p&gt;In this picture of the raceway you can also see where the faceplate and speaker cables leave the trim and go under the seat:&lt;/p&gt;
&lt;p&gt;&lt;img alt="power cable in raceway" src="/images/ft7800r-install/6-power-cable-front-raceway.jpg"&gt;
&lt;img alt="power cable in raceway" src="/images/ft7800r-install/8-power-cable-rear-raceway.jpg"&gt;&lt;/p&gt;
&lt;p&gt;At the B-pillar, I came out of the cable raceway but stayed below the trim.  I tried
but was unable to push all the way through. (I did not use fish tape for this part.)
It's possible that the cable raceway only exists in the door wells, or that the bundle
of cables bunches up at the pillar, with some of the cables go up the pillar.&lt;/p&gt;
&lt;p&gt;&lt;img alt="power cable in raceway" src="/images/ft7800r-install/7-power-cable-B-pillar.jpg"&gt;&lt;/p&gt;
&lt;p&gt;At the C-pillar, I pushed the cables under the trim and around the seat belt bolt:&lt;/p&gt;
&lt;p&gt;&lt;img alt="power cable in raceway" src="/images/ft7800r-install/9-c-pillar-cables.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I used L-brackets to mount a piece of wood to the passenger-side rear seat belt bolts.
It works very well, and is solid, even without any nuts holding the board in place.
The seat does push slightly against the radio when the seatback is moved up or down, but
during normal use there is plenty of room behind the rear seat for the radio.&lt;/p&gt;
&lt;p&gt;&lt;img alt="power cable in raceway" src="/images/ft7800r-install/11-radio-mounted.jpg"&gt;&lt;/p&gt;
&lt;p&gt;In addition to power, I ran the speaker and faceplate cables through the cable raceway.
Those cables come out right at the B pillar and go under the front seat.  I would
like to hide those cables under the carpet, so they are only visible under the seat.&lt;/p&gt;
&lt;p&gt;&lt;img alt="power cable in raceway" src="/images/ft7800r-install/12-b-pillar-cables.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The engine compartment has lots of places to reach ground. I chose this center-mounted
bolt:&lt;/p&gt;
&lt;p&gt;&lt;img alt="power cable in raceway" src="/images/ft7800r-install/13-negative+firewall.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I added an ATO fuse holder to the positive cable right at the battery, and I zip tied
the positive power cable to other things along the way to the grommet:&lt;/p&gt;
&lt;p&gt;&lt;img alt="power cable in raceway" src="/images/ft7800r-install/14-positive.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I do not currently have an antenna or a mount for the face plate, but I will be fixing
both of those issues this week.  For my first test, I used a ground plane antenna I
made about a month ago.&lt;/p&gt;
&lt;p&gt;&lt;img alt="power cable in raceway" src="/images/ft7800r-install/15-first_test.jpg"&gt;
&lt;img alt="power cable in raceway" src="/images/ft7800r-install/16-ground_plane_antenna.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I received an excellent signal report on a repeater that I cannot hit with my HT, so
I count this as a win.&lt;/p&gt;
&lt;p&gt;There are two more things to do.  First, I need to install a permanent antenna; the plan
is to use an NMO mount on the roof.  Second, I need a mount for the faceplate and
microphone; the plan for that is to get the FT-7800R version of the &lt;a href="https://www.lidoradio.com/products/lm-300-1001-seat-bolt-mount-with-microphone-hanger-for-yaesu-ft-857-ft-7800-ft-7900-ft-8800-ft-8900"&gt;Lido LM-300-1001&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I should call out that I forgot to install a ferrite core in the power feed, so I may
suffer from engine noise.  If I do, I will splice the line and install a ferrite core.&lt;/p&gt;</content><category term="Ham radio"></category><category term="ft7800r"></category><category term="f150"></category><category term="ham radio"></category></entry><entry><title>Using the program map type in autofs</title><link href="https://www.unixdude.net/posts/2022/Sep/15/using-the-program-map-type-in-autofs/" rel="alternate"></link><published>2022-09-15T09:50:00-04:00</published><updated>2022-09-15T09:50:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-09-15:/posts/2022/Sep/15/using-the-program-map-type-in-autofs/</id><summary type="html">&lt;p&gt;I recently learned about the &lt;code&gt;program&lt;/code&gt; map type in the Linux automounter.&lt;/p&gt;
&lt;p&gt;You can read about it &lt;a href="https://man.cx/auto.master#heading3"&gt;here&lt;/a&gt;, but there is little information about it,
and I was unable to find any web pages about it, so I am writing this post since it might help others.&lt;/p&gt;
&lt;p&gt;The NFS automounter &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/Sep/15/using-the-program-map-type-in-autofs/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently learned about the &lt;code&gt;program&lt;/code&gt; map type in the Linux automounter.&lt;/p&gt;
&lt;p&gt;You can read about it &lt;a href="https://man.cx/auto.master#heading3"&gt;here&lt;/a&gt;, but there is little information about it,
and I was unable to find any web pages about it, so I am writing this post since it might help others.&lt;/p&gt;
&lt;p&gt;The NFS automounter on Linux can take a static map, which we all know, including wildcard.  The static map
is in the format of &lt;code&gt;key options export_location&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Well, the automounter also supports a &lt;code&gt;program&lt;/code&gt; map type.  The &lt;code&gt;program&lt;/code&gt; map type specifics a program to run,
and the program returns the export location for any key in that mount location:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/mnt/nfs program:/usr/local/sbin/mapper.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It's really quite simple: The program takes the &lt;code&gt;key&lt;/code&gt; as argument 1, and returns the &lt;code&gt;export_location&lt;/code&gt; that
would be found in a static map.  The program does not return anything else -- it returns only the location of
the NFS export.  If the program returns anything else, autofs reports an error in the logs.  The documentation
does say that it can return "everything but the key," but this was not my experience.&lt;/p&gt;
&lt;p&gt;In my example, if the user executes &lt;code&gt;cd /mnt/nfs/blah&lt;/code&gt;, the automounter executes &lt;code&gt;/usr/local/sbin/mapper.py blah&lt;/code&gt;,
and the script might return something like &lt;code&gt;filer.example.com:/volume1/maps/abc/123&lt;/code&gt;, which would then be mounted
at &lt;code&gt;/mnt/nfs/blah&lt;/code&gt; as expected.&lt;/p&gt;
&lt;p&gt;This can be useful if you want a fully dynamic automount map that is maintained by a group other than the sysadmins
of a server.  In my case, a development organization maintains a list of exports in a file that the script retrieves
with HTTP.  The script then parses that list of exports in the program, and any given key returns the correct location for the
automounter to mount.  The developers can now update their own autofs maps without involving the admins.&lt;/p&gt;</content><category term="NFS"></category><category term="autofs"></category><category term="nfs"></category></entry><entry><title>Better spam blocking</title><link href="https://www.unixdude.net/posts/2022/Sep/15/better-spam-blocking/" rel="alternate"></link><published>2022-09-15T09:30:00-04:00</published><updated>2022-09-15T09:30:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-09-15:/posts/2022/Sep/15/better-spam-blocking/</id><summary type="html">&lt;p&gt;As mentioned previously, I continue to be inundated with spam email.  Fortunately,
every spam has an observable email format: the email comes in the form of user@word1.word2.TLD.&lt;/p&gt;
&lt;p&gt;This allows me to update my &lt;code&gt;blocked_senders&lt;/code&gt; file to defer every email in that format with a 450, using
this &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/Sep/15/better-spam-blocking/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;As mentioned previously, I continue to be inundated with spam email.  Fortunately,
every spam has an observable email format: the email comes in the form of user@word1.word2.TLD.&lt;/p&gt;
&lt;p&gt;This allows me to update my &lt;code&gt;blocked_senders&lt;/code&gt; file to defer every email in that format with a 450, using
this pattern:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;450&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;No&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;such&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When I first started doing this, I was manually watching inbound email logs to see what was deferred.  I
would then update the &lt;code&gt;blocked_senders&lt;/code&gt; file to add the domain as a 521 (for obvious spam), or with an
"OK" for obviously valid email or unknown spam.  Then I rebuild the &lt;code&gt;blocked_senders&lt;/code&gt; map and reload postfix.&lt;/p&gt;
&lt;p&gt;After a while, I noticed that the domain (word2.TLD) is always a parked domain.  I wrote a script to
check each domain found in the deferred email logs to detect whether the domain is parked.  With this
information, the script makes the decision and updates postfix for me: Parked domains are added to
&lt;code&gt;blocked_senders&lt;/code&gt; with a 521, and other domains are added with an "OK" to allow my server to receive
the mail.&lt;/p&gt;
&lt;p&gt;This is basically a simple knock-to-enter form of blocking, and so far it is working very well.&lt;/p&gt;
&lt;p&gt;So now I get emails like this, as my scripts do their work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Adding spam domain: [mydealmenia.com]
Adding valid domain: [mail.goodreads.com]
Adding valid domain: [readaloudrevival.com]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All totally automatic now.&lt;/p&gt;
&lt;p&gt;The code I used can be found &lt;a href="https://github.com/ataridude/block_spam"&gt;here&lt;/a&gt;.&lt;/p&gt;</content><category term="Mail"></category><category term="postfix"></category></entry><entry><title>Update</title><link href="https://www.unixdude.net/posts/2022/Aug/05/update/" rel="alternate"></link><published>2022-08-05T00:00:00-04:00</published><updated>2022-08-05T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-08-05:/posts/2022/Aug/05/update/</id><summary type="html">&lt;p&gt;I've been busy at home, but not working in my home lab.  Lately I have been preoccupied by a few things.&lt;/p&gt;
&lt;p&gt;First, I have been busy with prepping -- I can see how things are going, and I predict we will need
stores of supplies, so I have been busy building &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/Aug/05/update/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've been busy at home, but not working in my home lab.  Lately I have been preoccupied by a few things.&lt;/p&gt;
&lt;p&gt;First, I have been busy with prepping -- I can see how things are going, and I predict we will need
stores of supplies, so I have been busy building those stores of supplies.  Specifically, I have been
going through &lt;a href="https://www.cityprepping.com"&gt;The Prepper's Roadmap&lt;/a&gt; with my wife, and we have been 
learning a lot.&lt;/p&gt;
&lt;p&gt;Second, I studied for and passed the technician class amateur radio license exam.  I bought a &lt;a href="https://rigreference.com/rigs/6009-baofeng-uv-5r"&gt;Baofeng
UV-5R&lt;/a&gt; and find that I am too far from the local repeaters to use it, so I'll sell this and find a better HT.  I also picked
up a &lt;a href="https://rigreference.com/rigs/4345-yaesu-ft-7800re"&gt;Yaesu FT-7800R&lt;/a&gt; for my truck, and hope to get that installed soon.&lt;/p&gt;
&lt;p&gt;Third, my family and I traveled to Orlando for a week at Disney World -- we went to the Magic Kingdom
and Hollywood Studios, but unfortunately we missed EPCOT since I got sick and have been sick for the
last week.  We hope to head down to EPCOT sometime in the next few months to make up for the day we
missed.  Speaking of Disney, Galaxy's Edge is quite possibly the best themed area I have ever visited,
and Rise of the Resistance is without question the best theme experience I have ever had in my life.&lt;/p&gt;
&lt;p&gt;Back to the update...  We have more prepping to do -- skills to learn, materials to gather, and bags
and vehicles to pack -- but after that I hope to get back to my home lab.&lt;/p&gt;</content><category term="General"></category><category term="update"></category><category term="prepping"></category><category term="disney"></category><category term="ham radio"></category></entry><entry><title>Dealing with spam</title><link href="https://www.unixdude.net/posts/2022/Aug/01/dealing-with-spam/" rel="alternate"></link><published>2022-08-01T00:00:00-04:00</published><updated>2022-08-01T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-08-01:/posts/2022/Aug/01/dealing-with-spam/</id><summary type="html">&lt;p&gt;Somehow I have been added to several mailing lists, all run by the same organization.  The emails look legit, and
are ones that I might have subscribed to, but I cannot get off of them no matter what I do -- it seems that they
ignore all requests to be removed &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/Aug/01/dealing-with-spam/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Somehow I have been added to several mailing lists, all run by the same organization.  The emails look legit, and
are ones that I might have subscribed to, but I cannot get off of them no matter what I do -- it seems that they
ignore all requests to be removed from the list.  Postfix to the rescue: Postfix has a &lt;code&gt;smtpd_sender_restrictions&lt;/code&gt;
setting, which allows the user to deny specific senders -- but the caveat is that it uses the envelope sender,
not the "from" header in the message.&lt;/p&gt;
&lt;p&gt;I took note of the envelope senders, and have added those to a &lt;code&gt;blocked_senders&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;6045&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*-&lt;/span&gt;&lt;span class="mi"&gt;2315&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;redacted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;521&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;No&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;such&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;My &lt;code&gt;smtpd_sender_restrictions&lt;/code&gt; configuration includes the line &lt;code&gt;check_sender_access pcre:/usr/local/etc/postfix/blocked_senders,&lt;/code&gt;
which includes the single line above.  Earlier versions of my blocked_senders file had multiple
rows for this one sender, but I finally realized that the first and last numbers (6045 &amp;amp; 2315) are
the account number, and that the middle number was an ever-increasing campaign ID.&lt;/p&gt;
&lt;p&gt;Now, when mail comes in from those addresses, it is rejected, and I don't ever see it. And, for some
reason, this particular sender keeps sending me a half-dozen emails a day, despite getting 521 errors
for every email.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;More than this, though, I have noticed that spammers have gotten much more sophisticated: they register
real domains and run their spam servers on static IP addresses with real A &amp;amp; PTR DNS records, so they
look legitimate and they pass most of Postfix's spam tests.  I mark every such email as spam, and I add
the envelope sending domain to the same blocked senders file mentioned above.  Every day this
blocked_sender config catches multiple attempts from these same spammers. Until they register more real
hostnames and domain names, I might be good on spam blocking again!&lt;/p&gt;</content><category term="Mail"></category><category term="postfix"></category></entry><entry><title>Learning Python</title><link href="https://www.unixdude.net/posts/2022/May/20/learning-python/" rel="alternate"></link><published>2022-05-20T00:00:00-04:00</published><updated>2022-05-20T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-05-20:/posts/2022/May/20/learning-python/</id><summary type="html">&lt;p&gt;I have been programming in Perl since the early 1990s.  My early scripts were what you would expect them to be, but my skill
of course increased over time.  I have never found a thing I wanted to do that I could not do in Perl and/or shell scripting &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/May/20/learning-python/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have been programming in Perl since the early 1990s.  My early scripts were what you would expect them to be, but my skill
of course increased over time.  I have never found a thing I wanted to do that I could not do in Perl and/or shell scripting
(Bourne when portability is needed, Bash when it is not).&lt;/p&gt;
&lt;p&gt;For my job, I need to learn Python, and a friend recommends the book &lt;a href="https://automatetheboringstuff.com"&gt;Automate the Boring Stuff with Python&lt;/a&gt;.
In addition to the book, the author also has a Udemy course, and I am working my way through that right now.  One of the examples given
in the course is a Tic-Tac-Toe game.&lt;/p&gt;
&lt;p&gt;Earlier this week, as I was going through the course, I had &lt;a href="https://www.imdb.com/title/tt0086567/"&gt;WarGames&lt;/a&gt; playing silently on the TV.
Right when the movie got to "put X in the center square," my course also got to "put X in the center square."  See attached pic ... not
faked, and not timed.  It just worked out this way.&lt;/p&gt;
&lt;p&gt;Anyway, I decided to &lt;a href="https://github.com/ataridude/learning-python"&gt;write a Tic-Tac-Toe game in Python&lt;/a&gt;, and seeing as I have 1- never written
a game in my life, and 2- never written a line of Python, I think this is a pretty good first attempt.  The only thing I took from the
course example was the idea for the hash data type; 100% of the rest of this was my own.&lt;/p&gt;
&lt;p&gt;&lt;img alt="WarGames" src="/images/WarGames.jpg"&gt;&lt;/p&gt;</content><category term="Unix"></category><category term="python"></category><category term="perl"></category></entry><entry><title>NAS shakeup</title><link href="https://www.unixdude.net/posts/2022/May/12/nas-shakeup/" rel="alternate"></link><published>2022-05-12T00:00:00-04:00</published><updated>2022-05-12T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-05-12:/posts/2022/May/12/nas-shakeup/</id><summary type="html">&lt;p&gt;For my storage needs, my first NAS was a Synology DS415+.  This was my primary NAS
until I purchased a DS1618+, at which time it became my backup unit.  When I filled
up the DS1618+, I had a few options: buy a small NAS and use some 4TB disks I &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/May/12/nas-shakeup/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;For my storage needs, my first NAS was a Synology DS415+.  This was my primary NAS
until I purchased a DS1618+, at which time it became my backup unit.  When I filled
up the DS1618+, I had a few options: buy a small NAS and use some 4TB disks I had on hand,
or buy bigger disks, or buy a NAS with more storage bays.  I chose to buy a DS220+, into
which I shoved two 4TB drives, and this became a second primary onsite unit.&lt;/p&gt;
&lt;p&gt;A couple weeks ago, the DS415+ died, leaving me with no local backup.  (I have a DS118
offsite at a friend's house, which is used as one of my two offsite backup targets.)
I purchased a DS1821+ as a new primary system, and the DS1618+ became my local backup
unit.  All of my NASes are set up for SHR (primary is SHR2), and all of my NAS transitions
have been as seamless as one would expect from Synology: the process was as simple as:
move the drives, (re)install the OS, and go.&lt;/p&gt;
&lt;p&gt;I will be selling the DS220+ soon, because I have added yet another spare 4TB drive to
the DS1821+, and am in the process of relocating data from the 220 to the 1821.  This
also frees up the two 4TB drives that were in the DS220+, and those will go into the
other two NAS units.&lt;/p&gt;
&lt;p&gt;I never like losing a NAS, but it's nice that this worked as well as one could hope.
As a bonus, I got an upgrade to the latest offering from Synology, which also allows
me to free up another drive bay: I can switch from SSD cache to NVMe cache -- when I
buy an NVMe drive or two.&lt;/p&gt;</content><category term="General"></category><category term="synology"></category></entry><entry><title>ECMP in OSPF</title><link href="https://www.unixdude.net/posts/2022/Feb/20/ecmp-in-ospf/" rel="alternate"></link><published>2022-02-20T00:00:00-05:00</published><updated>2022-02-20T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-02-20:/posts/2022/Feb/20/ecmp-in-ospf/</id><summary type="html">&lt;p&gt;I have recently switched most of my offsite network connections to
WireGuard, away from ZeroTier.  This is great for all of my systems
except for one: the NAS (a Synology DS118) I have at a friend's house
for offsite backup.  That NAS can run ZeroTier and WireGuard, but
I don't &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/Feb/20/ecmp-in-ospf/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have recently switched most of my offsite network connections to
WireGuard, away from ZeroTier.  This is great for all of my systems
except for one: the NAS (a Synology DS118) I have at a friend's house
for offsite backup.  That NAS can run ZeroTier and WireGuard, but
I don't know of any dynamic routing protocol options for it, so I can
have only a single WireGuard connection rather than the two I want.
My solution here is to create a ZeroTier network between that NAS and
the two VMs I have at DigitalOcean.  For my purposes, that is close
enough to having two WireGuard links and the ability to route to
both of them.&lt;/p&gt;
&lt;p&gt;Another issue I wanted to resolve was the CPU load on my USG: with
WireGuard running on the USG, high traffic utilization on the WireGurad
links results in
100% CPU load on the USG, and that slows everything down.  The solution there was to
add WireGuard links from my Pi-Hole systems at home to my DigitalOcean
VMs, and to increase the OSPF link cost from the USG to the DigitalOcean
VMs.  As long as my USG is up, I'll have connectivity to my DOVMs,
but if one of my Pi-Hole systems is up, I will have better connectivity
to the DOVMs.&lt;/p&gt;
&lt;p&gt;I also wanted to set all of this up with redundant links and ECMP such
that any link can be down, and have everything continue to work.&lt;/p&gt;
&lt;p&gt;Below is a current network diagram.  The offsite links are WireGuard with
the exception of the ZeroTier network (shown in green) that connects the two DOVMs and
the NAS.  (The two DOVMs are of course also connected by a WireGuard link.)
A single OSPF area is used throughout, for all of the routing.&lt;/p&gt;
&lt;p&gt;This has been an enjoyable project, and a great learning experience.&lt;/p&gt;
&lt;p&gt;&lt;img alt="network" src="/images/complete_network_2022-02.jpg"&gt;&lt;/p&gt;</content><category term="Networking"></category><category term="ospf"></category><category term="routing"></category><category term="ecmp"></category><category term="wireguard"></category><category term="zerotier"></category><category term="usg"></category><category term="digitalocean"></category></entry><entry><title>OSPF update, Cable cleanup, and finished rack</title><link href="https://www.unixdude.net/posts/2022/Feb/11/cable-cleanup/" rel="alternate"></link><published>2022-02-11T00:00:00-05:00</published><updated>2022-02-11T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-02-11:/posts/2022/Feb/11/cable-cleanup/</id><summary type="html">&lt;p&gt;A quick update on my OSPF cutover.  With one exception, everything has worked great.
The one exception is that OSPF would not work over the WireGuard link between my USG
and my primary DigitalOcean VM that runs FreeBSD 12 and FRR7.  I thought that was odd,
since OSPF worked fine &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/Feb/11/cable-cleanup/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;A quick update on my OSPF cutover.  With one exception, everything has worked great.
The one exception is that OSPF would not work over the WireGuard link between my USG
and my primary DigitalOcean VM that runs FreeBSD 12 and FRR7.  I thought that was odd,
since OSPF worked fine over WireGuard between the USG and another VM at DigitalOcean,
running Ubuntu 20.04 LTS and FRR8.&lt;/p&gt;
&lt;p&gt;After many web searches, I found &lt;a href="https://docs.netgate.com/pfsense/en/latest/vpn/wireguard/routing.html"&gt;this page&lt;/a&gt;
that mentions the two requirements to getting OSPF working over WireGuard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The WireGuard interface must be set to Non-Broadcast network type&lt;/li&gt;
&lt;li&gt;OSPF neighbors must be statically configured&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once I did that on both the USG and the FreeBSD/FRR7 system, my two routers neighbored
correctly, and my FreeBSD/FRR7 VM obtained the entire LSDB.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Two weeks ago I finished racking everything in my new rack, and last weekend I
cleaned up the cables behind and below the rack.&lt;/p&gt;
&lt;p&gt;As you can see from these "before" pics, the cables were a mess.  There was
way too much slack, and just a jumble of cables below the rack.&lt;/p&gt;
&lt;p&gt;&lt;img alt="before-1" src="/images/lab/before-1.jpg"&gt;
&lt;img alt="before-2" src="/images/lab/before-2.jpg"&gt;
&lt;img alt="before-3" src="/images/lab/before-3.jpg"&gt;&lt;/p&gt;
&lt;p&gt;This jumble has been there for at least a year, and I finally bundled the cables and
moved the slack to the other side of the wall.  I think the result is pretty awesome.&lt;/p&gt;
&lt;p&gt;&lt;img alt="after-under-1" src="/images/lab/after-under-1.jpg"&gt;
&lt;img alt="after-under-2" src="/images/lab/after-under-2.jpg"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The finished lab looks pretty good.  Many thanks to &lt;a href="https://haydenjames.io/home-lab-beginners-guide-hardware/"&gt;Hayden James&lt;/a&gt;
for the inspiration here.  You can see my progress &lt;a href="/tag/rack/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="rack" src="/images/lab/rack.jpg"&gt;&lt;/p&gt;
&lt;p&gt;For those who are interested, here's what's in and around that rack:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;U12: TRENDnet 24-port Keystone patch panel, with VCE inline couplers and VCE blanks&lt;/li&gt;
&lt;li&gt;U11: Ubiquiti USW-Lite-16-PoE and Ubiquiti USG&lt;/li&gt;
&lt;li&gt;U10: Cisco 2611 (Lab R1)&lt;/li&gt;
&lt;li&gt;U9: Cisco 2610 (Lab R2)&lt;/li&gt;
&lt;li&gt;U8: Cisco 2610 (Lab R3)&lt;/li&gt;
&lt;li&gt;U7: Cisco 2960 (Lab S1)&lt;/li&gt;
&lt;li&gt;U6: Cisco 2960 (Lab S2)&lt;/li&gt;
&lt;li&gt;U5: Cisco 3750 (Lab S3)&lt;/li&gt;
&lt;li&gt;U3-U4: Shelf holding Raspberry Pi 4B (8GB) and Lenovo M900 Tiny&lt;/li&gt;
&lt;li&gt;U2: Empty&lt;/li&gt;
&lt;li&gt;U1: Pyle PDU&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I left U2 empty so that I can reach the latches that allow my Networx rack to swing out.
Similarly, there is no shelf at U11; the UI devices are simply resting atop the Cisco in U10.&lt;/p&gt;
&lt;p&gt;Below the rack are my Synology DS220+, a Grandstream DP750, a Linksys PAP2, and a UPS for the
infrastructure (not the lab devices).&lt;/p&gt;
&lt;p&gt;The monitor above the rack is connected to my Raspberry Pi 4B.  I would like to use it as
some sort of dashboard, but I haven't done anything with that yet.  That's a project for
another day.&lt;/p&gt;</content><category term="Home lab"></category><category term="cables"></category><category term="rack"></category><category term="routing"></category><category term="ospf"></category><category term="wireguard"></category><category term="usg"></category><category term="ubiquiti"></category><category term="digitalocean"></category><category term="frr"></category></entry><entry><title>Lab update</title><link href="https://www.unixdude.net/posts/2022/Jan/31/lab-update/" rel="alternate"></link><published>2022-01-31T00:00:00-05:00</published><updated>2022-01-31T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-01-31:/posts/2022/Jan/31/lab-update/</id><summary type="html">&lt;p&gt;I have been hard at work these last few weeks in my home lab, and have done quite a bit.  Here are a
few of the things I have done:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installed &lt;a href="https://github.com/nirui/sshwifty"&gt;sshwifty&lt;/a&gt;, a really cool, useful
package that a friend pointed me to.&lt;/li&gt;
&lt;li&gt;Built a &lt;a href="https://www.freeccnaworkbook.com/blog/ccna/how-to-make-a-t1-crossover"&gt;T1 crossover cable&lt;/a&gt; to connect &amp;#8230;&lt;/li&gt;&lt;a class="label label-primary read-more" href="/posts/2022/Jan/31/lab-update/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;I have been hard at work these last few weeks in my home lab, and have done quite a bit.  Here are a
few of the things I have done:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installed &lt;a href="https://github.com/nirui/sshwifty"&gt;sshwifty&lt;/a&gt;, a really cool, useful
package that a friend pointed me to.&lt;/li&gt;
&lt;li&gt;Built a &lt;a href="https://www.freeccnaworkbook.com/blog/ccna/how-to-make-a-t1-crossover"&gt;T1 crossover cable&lt;/a&gt; to connect the two routers I have in my home lab that have a T1 CSU/DSU WIC installed.&lt;/li&gt;
&lt;li&gt;Installed &lt;a href="https://www.portainer.io"&gt;Portainer&lt;/a&gt; on my production Docker Swarm&lt;/li&gt;
&lt;li&gt;Renumbered my home network from 192.168.1.0/24 to 192.168.8.0/24.  I undertook this effort because
I have a NAS hosted at a friend's house, and his network also uses the 192.168.1.0/24 address space, so
that made it difficult for me to get to my NAS -- sure, I could get to it, but every system that needed
access to it needed to be on my ZeroTier storage network.  Now, I can route directly to it, and return
packets are routed to my network instead of to his.&lt;/li&gt;
&lt;li&gt;Deployed WireGuard extensively, using FRR, OSPF, and Anycast to access systems.  Because of
CPU utilization issues I discovered after doing this, I might move my WireGuard routing/endpoint to my raspberry pi or to a VM in order to work around those issues.&lt;/li&gt;
&lt;li&gt;Added more monitoring under &lt;a href="https://kuma.unixdude.net/status"&gt;Kuma&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Deployed a new NAS, a &lt;a href="https://www.synology.com/en-us/products/DS220+"&gt;Synology DS220+&lt;/a&gt; to take some load off my DS1618+ and to use it as cold storage.&lt;/li&gt;
&lt;li&gt;Through the generosity of a friend, I have replaced my three Cisco 2950s with two 2960-Xs and one 3750G.&lt;/li&gt;
&lt;li&gt;I have finished racking all my devices.&lt;/li&gt;
&lt;li&gt;I have cabled up my Cisco lab again.  I have also connected the lab to my home network via my
&lt;a href="https://store.ui.com/products/unifi-security-gateway"&gt;Ubiquiti USG&lt;/a&gt;'s
LAN2 port, so that I can route to it.  I have console access to all of the devices, using &lt;a href="https://www.amazon.com/Gearmo-Serial-Windows-Certified-Drivers/dp/B004ETDC8K/"&gt;a 4-port
USB-to-serial adapter&lt;/a&gt;
and some mini USB cables (for the 2960s) connected to my Raspberry Pi, but I also want network access.
 The current lab setup, which will hopefully be useful for much learning, is shown here:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="lab network" src="/images/lab-network-2022-01.jpg"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I installed a patch panel, which cleaned up the rack a bit.  Here are before &amp;amp; after pics.  Because
my switch and router are not rack-mount devices, it's not as clean as it could be, but I still think
this came out very well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="before" src="/images/patch-panel/before.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="after" src="/images/patch-panel/after.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;Next up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure the newly recabled Cisco lab.&lt;/li&gt;
&lt;li&gt;Finish migrating data to the DS220+.&lt;/li&gt;
&lt;li&gt;Clean up the power and ethernet cables behind and below the rack.&lt;/li&gt;
&lt;/ul&gt;</content><category term="Home lab"></category><category term="update"></category><category term="docker"></category><category term="portainer"></category><category term="T1"></category><category term="ubiquiti"></category><category term="usg"></category><category term="wireguard"></category><category term="rack"></category><category term="cables"></category></entry><entry><title>Goodbye BGP, hello OSPF</title><link href="https://www.unixdude.net/posts/2022/Jan/12/goodbye-bgp-hello-ospf/" rel="alternate"></link><published>2022-01-12T00:00:00-05:00</published><updated>2022-01-12T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-01-12:/posts/2022/Jan/12/goodbye-bgp-hello-ospf/</id><summary type="html">&lt;p&gt;Soon after I learned about &lt;a href="https://en.wikipedia.org/wiki/Anycast"&gt;Anycast&lt;/a&gt;, I employed it 
on my home network, so that I can have
multiple instances of &lt;a href="https://pi-hole.net"&gt;Pi-Hole&lt;/a&gt;, mostly so that I can
take down my Raspberry Pi without hearing from the family about how the Internet is down.&lt;/p&gt;
&lt;p&gt;Until last night, I was using &lt;a href="https://www.cloudflare.com/learning/security/glossary/what-is-bgp/"&gt;BGP &amp;#8230;&lt;/a&gt;&lt;a class="label label-primary read-more" href="/posts/2022/Jan/12/goodbye-bgp-hello-ospf/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Soon after I learned about &lt;a href="https://en.wikipedia.org/wiki/Anycast"&gt;Anycast&lt;/a&gt;, I employed it 
on my home network, so that I can have
multiple instances of &lt;a href="https://pi-hole.net"&gt;Pi-Hole&lt;/a&gt;, mostly so that I can
take down my Raspberry Pi without hearing from the family about how the Internet is down.&lt;/p&gt;
&lt;p&gt;Until last night, I was using &lt;a href="https://www.cloudflare.com/learning/security/glossary/what-is-bgp/"&gt;BGP&lt;/a&gt; (as part of &lt;a href="https://frrouting.org"&gt;FRR&lt;/a&gt;) for Anycast,
&lt;a href="/posts/2021/Mar/11/frr-and-anycast/"&gt;running FRR on my Raspberry Pi&lt;/a&gt; and some other devices, and peering those with each other
and with my router.&lt;/p&gt;
&lt;p&gt;Well, I got tired of the full mesh that BGP requires, so last night I switched to
OSPF.  It still supports Anycast, but does not require a full mesh of routers, making
it much more suitable to my needs.  I mean, of course I knew BGP was not the right
long-term answer, but it was easy and all of my coworkers were able to help me with any
configuration questions -- and I got to say that I ran BGP at home, which was fun.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I have been using &lt;a href="https://www.zerotier.com"&gt;ZeroTier&lt;/a&gt; as my VPN solution ever since
&lt;a href="https://mindlesstux.com/2018/09/23/zerotier-multsite-lan-part-1-zerotier-and-making-a-multi-site-lan-man/"&gt;a friend mentioned it&lt;/a&gt;.
I want to have some redundancy in case ZeroTier goes down, so last night I configured &lt;a href="https://www.wireguard.com"&gt;WireGuard&lt;/a&gt; on my Ubiquiti &lt;a href="https://store.ui.com/products/unifi-security-gateway"&gt;USG&lt;/a&gt;,
as well as one of my offsite systems.  I prefer to run this on my router anyway, since
I don't want my whole network to go down if my Raspberry Pi goes down.  If my network goes down because my router is down,
well, then I have bigger problems than not being able to access my remote systems.&lt;/p&gt;
&lt;p&gt;So, I'll use WireGuard as the primary, and ZeroTier as the backup.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;One of my main goals right now is that I want to retire my Rasperry Pi 3B unit in favor of a
PoE-powered Pi 4B unit, freeing up a power oulet, reducing cables, and generally simplifying
my setup.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I'm not done yet, but I'm making good progress on these goals.&lt;/p&gt;</content><category term="Networking"></category><category term="bgp"></category><category term="anycast"></category><category term="usg"></category><category term="frr"></category><category term="ubiquiti"></category><category term="ospf"></category><category term="raspi"></category><category term="wireguard"></category><category term="zerotier"></category></entry><entry><title>MacBook Pro recovery</title><link href="https://www.unixdude.net/posts/2022/Jan/04/macbook-pro-recovery/" rel="alternate"></link><published>2022-01-04T00:00:00-05:00</published><updated>2022-01-04T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-01-04:/posts/2022/Jan/04/macbook-pro-recovery/</id><summary type="html">&lt;p&gt;My work laptop, a 2018 MacBook Pro, needs a new battery and so I will be shipping it off to
have that serviced.  Prior to getting that serviced, I need a temporary system, so I 
went to the office to grab one of the spares we have, another 2018 MBP &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/Jan/04/macbook-pro-recovery/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;My work laptop, a 2018 MacBook Pro, needs a new battery and so I will be shipping it off to
have that serviced.  Prior to getting that serviced, I need a temporary system, so I 
went to the office to grab one of the spares we have, another 2018 MBP.  This system was
used by a former coworker, one who retired months ago, and he
no longer remembers the firmware password he configured on the system.&lt;/p&gt;
&lt;p&gt;I thought this system was a brick, until an Apple expert pointed me to the &lt;a href="https://support.apple.com/guide/apple-configurator-2/revive-or-restore-an-intel-based-mac-apdebea5be51/mac"&gt;DFU restore option
using Apple Configurator 2&lt;/a&gt;.
The startup key sequence for this is ... tricky.  I tried it a few times, but was not successful
until I watched &lt;a href="https://www.youtube.com/watch?v=UaVgBP4gJsU"&gt;this YouTube video&lt;/a&gt; that demonstrates
the process.&lt;/p&gt;
&lt;p&gt;Using DFU mode, I first tried the Revive option.  The laptop booted back to the firmware prompt, so
I then tried the Restore option, which caused this laptop to boot into Internet Recovery mode.
Perfect!  Now I have this unit installing its original OS -- Mojave -- and will update to Big Sur
once it is done.&lt;/p&gt;
&lt;p&gt;Internet Recovery is cool, but slow.  It's a little faster over ethernet versus wifi, especially
with a gigabit connection, but it's still slow.  Anyway, this thing is working now and is no
longer a brick, so it's good now.&lt;/p&gt;</content><category term="General"></category><category term="mac"></category></entry><entry><title>Upgrading to DSM7</title><link href="https://www.unixdude.net/posts/2022/Jan/03/upgrading-to-dsm7/" rel="alternate"></link><published>2022-01-03T00:00:00-05:00</published><updated>2022-01-03T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2022-01-03:/posts/2022/Jan/03/upgrading-to-dsm7/</id><summary type="html">&lt;p&gt;I've been meaning to upgrade my Synology NASes to DSM7.  I upgraded my DS415+
last week, and it went smoothly, so today I researched all the packages I have installed on my 
primary unit, a DS1618+.  I found that all but two would upgrade seamlessly;
the two trouble packages were &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2022/Jan/03/upgrading-to-dsm7/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've been meaning to upgrade my Synology NASes to DSM7.  I upgraded my DS415+
last week, and it went smoothly, so today I researched all the packages I have installed on my 
primary unit, a DS1618+.  I found that all but two would upgrade seamlessly;
the two trouble packages were Plex Media Server and ZeroTier.  Both of these
are supported on DSM7 -- see instructions for &lt;a href="https://www.blackvoid.club/plex-migration-with-dsm-7/"&gt;PMS&lt;/a&gt;
and &lt;a href="https://docs.zerotier.com/devices/synology/"&gt;ZeroTier&lt;/a&gt; -- but are more involved
than simply installing a package.  In particular, PMS requires a very specific procedure
to migrate from DSM6.&lt;/p&gt;
&lt;p&gt;I had ZeroTier up and running quickly and easily using the linked instructions, but Plex Media Server
gave me a lot of trouble,
so I figured I would post about it in case others run into the same issue.&lt;/p&gt;
&lt;p&gt;I had PMS running on DSM6, and I wanted to migrate my installation to DSM7.  This is not
as simple as upgrading a package, so I took care to perform the upgrade as instructed.
Following the instructions linked above, I downloaded PMS directly from Plex, then I
began a manual installation.&lt;/p&gt;
&lt;p&gt;During the installation, the wizard presented an error
indicating a failed install (sorry but I did not take a screenshot).
I then started doing lots of research and tried the installation several times.  I also saw the 
migration log at &lt;code&gt;/volume1/Plex/Migration.log&lt;/code&gt;, and it showed success, so that gave me an
idea: maybe the installation really did succeed, even though the wizard showed a failure.
I cleaned out everything (did a remove+erase of the PMS package, restored &lt;code&gt;/volume1/Plex&lt;/code&gt;,
removed &lt;code&gt;/volume1/PlexMediaServer&lt;/code&gt;) and reran the installation.  Predictably the wizard
showed a failure, and I just left it and tailed the migration log until the log showed success:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Plex Media Server migration to DSM 7 started:  Mon Jan  3 15:37:31 EST 2022
=== Mon Jan  3 15:37:31 EST 2022 === Start: Change ownership
=== Mon Jan  3 15:37:38 EST 2022 === Completed: Change ownership
=== Mon Jan  3 15:37:38 EST 2022 === Start: Convert symbolic links
=== Mon Jan  3 15:38:55 EST 2022 === Completed:  Convert symbolic links
=== Mon Jan  3 15:38:55 EST 2022 === Start: Migrate Plex Media Server
=== Mon Jan  3 15:40:42 EST 2022 === Completed:  Migrate Plex Media Server
=== Mon Jan  3 15:40:42 EST 2022 === Completed:  Migrate Plex Media Server
=== Mon Jan  3 15:40:42 EST 2022 === Start: Clean /volume1/Plex
=== Mon Jan  3 15:40:43 EST 2022 === Completed: Clean /volume1/Plex
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I exited the wizard, and all was well.&lt;/p&gt;
&lt;p&gt;There is one other change I did on the final, successful installation: when I removed
the PMS package after the first install (per instructions it requires two installs for a successful migration
from DSM6), I also removed the PlexMediaServer shared folder.  Maybe that was key:
I did not remove that shared folder after the first install, until my final attempt.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Unfortunately DSM7 is complaining about my 3rd party RAM upgrade (2x 8GB sticks that
were removed from my Lenovo M900 when I upgraded that to 32GB), but otherwise DSM7
is great, and the upgrade went smoothly with the exception of Plex.&lt;/p&gt;</content><category term="Networking"></category><category term="plex"></category><category term="synology"></category><category term="dsm"></category><category term="zerotier"></category></entry><entry><title>Retiring my Dell R610</title><link href="https://www.unixdude.net/posts/2021/Dec/22/retiring-my-dell-r610/" rel="alternate"></link><published>2021-12-22T00:00:00-05:00</published><updated>2021-12-22T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-12-22:/posts/2021/Dec/22/retiring-my-dell-r610/</id><summary type="html">&lt;p&gt;Ever since &lt;a href="https://mindlesstux.com/"&gt;a friend&lt;/a&gt; gave me a Dell R610, I have used that as
my primary home lab server.  Due to its age, I find that I am unable to run the most 
recent versions of some software packages, including the latest iterations of VMware
ESXi and vCenter.  Also, my &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Dec/22/retiring-my-dell-r610/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Ever since &lt;a href="https://mindlesstux.com/"&gt;a friend&lt;/a&gt; gave me a Dell R610, I have used that as
my primary home lab server.  Due to its age, I find that I am unable to run the most 
recent versions of some software packages, including the latest iterations of VMware
ESXi and vCenter.  Also, my unit sits in a small room near the 3rd floor AC return in my house,
and this means that the heat it generates is pulled into the AC system, which affects my home's HVAC
operation.&lt;/p&gt;
&lt;p&gt;For these and other reasons, I have decided to retire the R610 and replace it.  A while back,
I heard about &lt;a href="https://www.servethehome.com/introducing-project-tinyminimicro-home-lab-revolution/"&gt;ServeTheHome's TinyMiniMicro project&lt;/a&gt;, so I read some of their articles and decided to purchase a Lenovo M900 with an i7 CPU.  I upgraded my unit to 32GB RAM (the max), and this model includes vPro technology, which
is a plus or a minus depending on who you ask.  This unit will sit in my rack, rather
than on the floor leaning against the wall.  It will be a huge bonus that the M900 generates
less heat and uses less power than the R610.&lt;/p&gt;
&lt;p&gt;My new M900 is much less capable overall than my R610: my R610 had a dual 300GB HDs in a
mirror, 192GB RAM, and dual Xeon 3.0 GHz for a total of 16 vCPUs.  The M900 has a single
256GB SSD, 32GB RAM, and a single 2.8GHz i7 CPU for a total of 8 vCPUs.  Even so, I think
this was a great purchase
based on my use case, which is to run ESXi and a dozen or so VMs.  Running vCSA 6, I maxed out on the R610 out at
40GB RAM usage, 10GB of which was vCSA -- so if I avoid vCSA, I'll stay below 30GB RAM usage.
Per-thread, the M900 is about 30% faster than the R610, so overall I think this is a huge win.&lt;/p&gt;
&lt;p&gt;Having less RAM means I will have to be more selective about the VMs I run.  Fortunately, since this type of
setup is so cheap, if I need more capacity, I'll just buy another one of these 1L systems, be
it a Lenovo or a Dell or an HP.  So far, the M900 has exceeded my expectations.&lt;/p&gt;
&lt;p&gt;Getting ESXi instsalled was an interesting experience: I couldn't get the M900 to boot from USB or PXE --
it seemed stuck on booting the included Windows installation.  I quickly learned the reason for this: the
M900 was configured for UEFI booting only; BIOS booting was disabled.  I enabled BIOS booting, downloaded the
Lenovo custom build of ESXi 7.0u2 and added it to my BIOS-only PXE setup, and started my install.  I was off
to the races, and so far I haven't found any issues with this build on this hardware.&lt;/p&gt;
&lt;p&gt;After I got ESXi 7 installed on it, I installed vCSA 7, then added both the R610 and M900 to that vCenter
Server so I could use vMotion to migrate all of the VMs.  I had a few VMs on the local storage on the
R610 -- notably my UniFi Controller so that I can upgrade my Ubiquiti devices -- and it's so cool
that vCenter Server can migrate from local storage to local storage on different servers, without an intermediate
stop on a shared datastore.  Obviously 256-300GB space is not enough for many VMs; most of my VMs are
stored on NFS.&lt;/p&gt;
&lt;p&gt;Another thing that really impressed me last night is that all of my VMs migrated without issue:
No complaints about CPU mismatch.  All VMs are now migrated, but I powered down a few of them
to save RAM.  With vCSA powered down, this system will be perfect for my needs:&lt;/p&gt;
&lt;p&gt;&lt;img alt="CPU/RAM Utilization" src="/images/m900/utilization.png"&gt;&lt;/p&gt;
&lt;p&gt;I have a lot of cleanup to do here, but it's amazing how quiet and cool this area is, now that the R610
is powered down.&lt;/p&gt;
&lt;p&gt;&lt;img alt="M900 under rack" src="/images/m900/under-rack.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;The powered-down R610:&lt;/p&gt;
&lt;p&gt;&lt;img alt="R610" src="/images/m900/r610.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;The eBay seller did me right: this thing was super clean and looks practically new:&lt;/p&gt;
&lt;p&gt;&lt;img alt="front" src="/images/m900/front.jpeg"&gt;
&lt;img alt="top" src="/images/m900/top.jpeg"&gt;
&lt;img alt="inside" src="/images/m900/inside.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;One last thing: I have decided to convert my PXE setup to UEFI-only: at this point, I have zero need for
BIOS PXE booting, and UEFI will be better.  That will be an upcoming project.&lt;/p&gt;</content><category term="Home lab"></category><category term="esxi"></category><category term="r610"></category><category term="m900"></category><category term="tinyminimicro"></category><category term="rack"></category></entry><entry><title>Wall-mount rack</title><link href="https://www.unixdude.net/posts/2021/Nov/27/wall-mount-rack/" rel="alternate"></link><published>2021-11-27T00:00:00-05:00</published><updated>2021-11-27T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-11-27:/posts/2021/Nov/27/wall-mount-rack/</id><summary type="html">&lt;p&gt;Since I bought my Cisco equipment, I have had it racked in the cheap, two-post desktop rack
that came with the equipment when I bought it.  It was pretty bad, but it worked:&lt;/p&gt;
&lt;p&gt;&lt;img alt="original rack" src="/images/original-rack.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I really wanted something better than this, so I started doing some web searches to get
ideas &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Nov/27/wall-mount-rack/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Since I bought my Cisco equipment, I have had it racked in the cheap, two-post desktop rack
that came with the equipment when I bought it.  It was pretty bad, but it worked:&lt;/p&gt;
&lt;p&gt;&lt;img alt="original rack" src="/images/original-rack.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I really wanted something better than this, so I started doing some web searches to get
ideas on what I could do better.  Along the way, I discovered &lt;a href="https://haydenjames.io/home-lab-beginners-guide-hardware/"&gt;Hayden James's home lab beginner's guide&lt;/a&gt;,
and decided I wanted a wall-mount rack.  I did a lot of research about wall-mount racks, and
I settled on the &lt;a href="https://www.networxproducts.com/12u-adjustable-depth-open-frame-swing-out-wall-mount-rack-301-series-flat-packed"&gt;Networks adjustable depth, swing-out 12U rack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The rack arrived last week, and I was able to mount it earlier this week.  I still
have lots of work to do here, and this is going to be a huge improvement over the original
setup.&lt;/p&gt;
&lt;p&gt;&lt;img alt="wall mount rack" src="/images/wall-mount-rack.jpg"&gt;&lt;/p&gt;</content><category term="Home lab"></category><category term="rack"></category></entry><entry><title>healthchecks.io</title><link href="https://www.unixdude.net/posts/2021/Nov/15/healthchecksio/" rel="alternate"></link><published>2021-11-15T00:00:00-05:00</published><updated>2021-11-15T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-11-15:/posts/2021/Nov/15/healthchecksio/</id><summary type="html">&lt;p&gt;Recently, &lt;a href="http://mindlesstux.com"&gt;a friend&lt;/a&gt; introduced me to &lt;a href="https://healthchecks.io"&gt;healthchecks.io&lt;/a&gt;, a service for monitoring cron jobs.&lt;br&gt;
A week or so ago, I configured several of my cron jobs to be monitored through this system, and it has already helped me:
yesterday I received a notification that an rsync job did not run &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Nov/15/healthchecksio/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Recently, &lt;a href="http://mindlesstux.com"&gt;a friend&lt;/a&gt; introduced me to &lt;a href="https://healthchecks.io"&gt;healthchecks.io&lt;/a&gt;, a service for monitoring cron jobs.&lt;br&gt;
A week or so ago, I configured several of my cron jobs to be monitored through this system, and it has already helped me:
yesterday I received a notification that an rsync job did not run, and the reason for that failure turned out to be
a filesystem that was unintentionally unmounted.  I remounted the filesystem, and today I received a notification that
the rsync job finished as expected.  What a great service.&lt;/p&gt;</content><category term="Networking"></category><category term="monitoring"></category></entry><entry><title>Printer update</title><link href="https://www.unixdude.net/posts/2021/Nov/09/printer-update/" rel="alternate"></link><published>2021-11-09T00:00:00-05:00</published><updated>2021-11-09T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-11-09:/posts/2021/Nov/09/printer-update/</id><summary type="html">&lt;p&gt;Here's a months-overdue update on that &lt;a href="https://www.unixdude.net/posts/2021/Sep/07/docker-build/"&gt;HP Envy printer&lt;/a&gt;:  I wasn't able to
return the printer, and I still wanted a better
scanner app than the HP's built-in one, so I decided to take the
Raspberry Pi 4 that I mentioned in an earlier post and attach the printer
directly &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Nov/09/printer-update/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here's a months-overdue update on that &lt;a href="https://www.unixdude.net/posts/2021/Sep/07/docker-build/"&gt;HP Envy printer&lt;/a&gt;:  I wasn't able to
return the printer, and I still wanted a better
scanner app than the HP's built-in one, so I decided to take the
Raspberry Pi 4 that I mentioned in an earlier post and attach the printer
directly to it.  The goal of doing this was having better printing
than what I was doing before, where the printer was on my IoT VLAN,
and my print clients are all on my home VLAN.&lt;/p&gt;
&lt;p&gt;In addition to having better printing functionality, I also wanted a better scanner app as I just mentioned. And, I wanted all of it working through &lt;a href="https://traefik.io/traefik/"&gt;Traefik&lt;/a&gt;, so that I can access the scanservjs app, printer admin page, and CUPS admin page all through Traefik.&lt;/p&gt;
&lt;p&gt;As I mentioned, I got to learn about &lt;code&gt;docker build&lt;/code&gt;, because there was no scanservjs image for ARM.  Fortunately, building for ARM is super fast on my M1 MacBook Air. I mean, my Intel iMac could build the ARM image too, but it takes a lot less time on my M1 MBA -- a minute or two on the M1 vs 1,000 seconds on the Intel, so I won't be building the ARM image on my iMac again!&lt;/p&gt;
&lt;p&gt;I have now automated the build process mentioned in the earlier post: every now and again, I will pull the latest code from sbs20's scanservjs repo, then build it using his Dockerfile, with this script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;IMAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ataridude/scanservjs&amp;quot;&lt;/span&gt;

&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-z&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; tag&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-1
docker&lt;span class="w"&gt; &lt;/span&gt;image&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IMAGE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IMAGE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:latest&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;image&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IMAGE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;:&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;image&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IMAGE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I know there are ways to fully automate that &lt;code&gt;docker build&lt;/code&gt; process, and I'll get to that point at some time,
but for now it's nice to have an easy way to update the image.&lt;/p&gt;
&lt;p&gt;As you might expect, my Raspberry Pi print server is installed via &lt;a href="https://github.com/ataridude/ansible/blob/master/playbook_print_server.yml"&gt;an Ansible playbook&lt;/a&gt;.
I should look into the playbook and &lt;code&gt;docker-container-scanner&lt;/code&gt; role, since this was the first Docker-oriented role I wrote, and I'm sure there is much that could be improved in the role and the playbook.&lt;/p&gt;</content><category term="General"></category><category term="docker"></category><category term="printer"></category><category term="scanner"></category><category term="raspberry pi"></category></entry><entry><title>Update on migration to Docker/Traefik</title><link href="https://www.unixdude.net/posts/2021/Nov/05/update-on-migration-to-dockertraefik/" rel="alternate"></link><published>2021-11-05T00:00:00-04:00</published><updated>2021-11-05T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-11-05:/posts/2021/Nov/05/update-on-migration-to-dockertraefik/</id><summary type="html">&lt;p&gt;I have been working hard these last many weeks in order to move all services off of my main DigitalOcean Droplet/VM.  In the process, I have been moving everything to Docker, with full automation via Ansible.  I have finally achieved this goal, for the web services anyway, and now &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Nov/05/update-on-migration-to-dockertraefik/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have been working hard these last many weeks in order to move all services off of my main DigitalOcean Droplet/VM.  In the process, I have been moving everything to Docker, with full automation via Ansible.  I have finally achieved this goal, for the web services anyway, and now I can deploy all of my web services with one or two Ansible commands: a bootstrap playbook (needed only for DigitalOcean VMs), and  a deploy playbook (good for VMs at home as well as ones at DigitalOcean).&lt;/p&gt;
&lt;p&gt;I have uploaded my code &lt;a href="https://github.com/ataridude/ansible"&gt;to GitHub&lt;/a&gt;.  For DigitalOcean VMs, I start with &lt;a href="https://github.com/ataridude/ansible/blob/master/playbook_bootstrap.yml"&gt;playbook_bootstrap.yml&lt;/a&gt;, and for all VMs, I run &lt;a href="https://github.com/ataridude/ansible/blob/master/playbook_blog_server.yml"&gt;playbook_blog_server.yml&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This single command now sets up everything that used to be an Apache vhost on my main VM -- and all "vhosts" now run through &lt;a href="https://traefik.io/traefik/"&gt;Traefik&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a good milestone to reach, because it means I have now accomplished my goal of treating these services as "&lt;a href="https://en.wikipedia.org/wiki/Infrastructure_as_code"&gt;infrastructure as code&lt;/a&gt;": I no longer make changes on the web server -- all changes are done in Ansible and/or Docker, then pushed out to the server.&lt;/p&gt;
&lt;p&gt;Next up, I will work on moving my mail server (postfix, dovecot, spamassassin).&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;While working on this project, one of the things I ran into is that the Pelican search plugin I have been using, &lt;a href="https://github.com/getpelican/pelican-plugins/tree/master/tipue_search"&gt;tipue_search&lt;/a&gt;, is no longer supported.  At first, this kept my main site on Apache, but eventually I decided I needed to get this sorted.  I made &lt;a href="https://github.com/ataridude/pelican_tipue_search"&gt;my own copy of tipue_search&lt;/a&gt; and added it to the &lt;a href="https://github.com/ataridude/unixdude.net/blob/master/Dockerfile"&gt;Dockerfile&lt;/a&gt; I am using to build this site, and now I have it working in my Dockerized blog implementation.  I had considered switching to the brand-new &lt;a href="https://github.com/rehanhaider/pelican-algolia/tree/main/pelican/plugins/pelican_algolia"&gt;pelican-algolia plugin&lt;/a&gt;, and while I still think that is a great solution I decided to stick with the tipue_search plugin I've been using for years.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This Dockerfile uses a multi-stage build process, which I like because it lowers the requirements for my build server: the multi-stage build means that Pelican is not actually installed on my build server -- the entire build is done in a container.  I got this idea from a friend, who &lt;a href="https://gitlab.com/blcarman/blog/-/blob/master/Dockerfile"&gt;does this with his blog&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Hopefully I will now find it easier to update this and my &lt;a href="https://www.ataridude.net"&gt;Atari blog&lt;/a&gt;.&lt;/p&gt;</content><category term="Website"></category><category term="traefik"></category><category term="docker"></category></entry><entry><title>MinFS</title><link href="https://www.unixdude.net/posts/2021/Oct/28/minfs/" rel="alternate"></link><published>2021-10-28T00:00:00-04:00</published><updated>2021-10-28T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-10-28:/posts/2021/Oct/28/minfs/</id><summary type="html">&lt;p&gt;Over the last month, I have been continuing my work at automating my systems and have made a lot of
progress in that effort.&lt;/p&gt;
&lt;p&gt;Part of that will be relocating some files that I still want web-accessible, but not on this website.
Enter &lt;a href="https://www.digitalocean.com/products/spaces/"&gt;DigitalOcean Spaces&lt;/a&gt;, and &lt;a href="https://github.com/minio/minfs"&gt;MinFS&lt;/a&gt; to access it &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Oct/28/minfs/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Over the last month, I have been continuing my work at automating my systems and have made a lot of
progress in that effort.&lt;/p&gt;
&lt;p&gt;Part of that will be relocating some files that I still want web-accessible, but not on this website.
Enter &lt;a href="https://www.digitalocean.com/products/spaces/"&gt;DigitalOcean Spaces&lt;/a&gt;, and &lt;a href="https://github.com/minio/minfs"&gt;MinFS&lt;/a&gt; to access it.&lt;/p&gt;
&lt;p&gt;Set was super simple: After installation, I edited &lt;code&gt;/etc/minfs/config.json&lt;/code&gt; to set my Spaces
access key and secret key, then added the /etc/fstab entry, created the directory, and mounted it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/etc/fstab&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;https://nyc3.digitaloceanspaces.com/unixdude /mnt/unixdude minfs defaults,cache=/tmp/unixdude-minfs 0 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root@ansible-test(U20):67:/mnt/unixdude/ataridude&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;Filesystem&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;Size&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Used&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Avail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Use&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mounted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;
&lt;span class="n"&gt;MinFS&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mnt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;unixdude&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root@ansible-test(U20):68:/mnt/unixdude/ataridude&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;
&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rw&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rw&lt;/span&gt;&lt;span class="o"&gt;----&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;67748394&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Oct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;atari&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5200&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;jumpy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root@ansible-test(U20):69:/mnt/unixdude/ataridude&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The URL for that file is: &lt;a href="https://unixdude.nyc3.digitaloceanspaces.com/ataridude/atari-5200-jumpy-video.mov"&gt;https://unixdude.nyc3.digitaloceanspaces.com/ataridude/atari-5200-jumpy-video.mov&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pretty slick.  I'll be adding more to that space over time.&lt;/p&gt;
&lt;p&gt;Also: 64T - wow!&lt;/p&gt;</content><category term="Website"></category><category term="minfs"></category></entry><entry><title>acme.sh and Let's Encrypt certificates</title><link href="https://www.unixdude.net/posts/2021/Oct/18/acme_sh-and-letsencrypt-certificates/" rel="alternate"></link><published>2021-10-18T00:00:00-04:00</published><updated>2021-10-18T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-10-18:/posts/2021/Oct/18/acme_sh-and-letsencrypt-certificates/</id><summary type="html">&lt;p&gt;I have been needing to cut over to acme v2 for a long time, and I didn't bother doing it until way
too late -- this weekend.  As a result of my tardiness, my iPhone has not been able to receive email
from my mail server for more than a month &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Oct/18/acme_sh-and-letsencrypt-certificates/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have been needing to cut over to acme v2 for a long time, and I didn't bother doing it until way
too late -- this weekend.  As a result of my tardiness, my iPhone has not been able to receive email
from my mail server for more than a month now.&lt;/p&gt;
&lt;p&gt;My current mail server runs dovecot + postfix (plus some other stuff), manually installed on FreeBSD,
and I have been trying to get Docker Mailserver working on a new Ubuntu server and have been having
nothing but trouble with that, so I finally gave up.  On the new setup I will still install everything
with Ansible, it just won't be Dockerized, and I'm okay with this.&lt;/p&gt;
&lt;p&gt;Tonight I decided that in the interim I needed to at least fix the SSL certificates. While doing this,
 I ran into a problem that I cannot believe is not called out anywhere, so I'm writing about it. To be
fair, this is documented &lt;a href="https://github.com/acmesh-official/acme.sh/wiki/Server"&gt;here&lt;/a&gt;, but no howto I found mentions it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://letsencrypt.org/docs/client-options/"&gt;Let's Encrypt's client page&lt;/a&gt; lists &lt;a href="https://github.com/acmesh-official/acme.sh"&gt;acme.sh&lt;/a&gt;, but does not bother to mention that one must pass in the &lt;code&gt;--server&lt;/code&gt; parameter in order
to use the Let's Encrypt CA with &lt;code&gt;acme.sh&lt;/code&gt;.  One must do this because the default CA for acme.sh
is ZeroSSL.&lt;/p&gt;
&lt;p&gt;In fact, none of the dozen or so howtos I read made any mention of this!  And, since I had never heard
of ZeroSSL until tonight, I had no idea that it was a competitor to Let's Encrypt.&lt;/p&gt;
&lt;p&gt;In order to create the Let's Encrypt certificate for my mail server (mail.unixdude.net), I set the 
&lt;code&gt;DO_API_KEY&lt;/code&gt; environment variable, then ran:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;acme.sh --issue -d mail.unixdude.net --dns dns_dgon --server letsencrypt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The magic there, for the Let's Encrypt user, is the &lt;code&gt;--server letsencrypt&lt;/code&gt; parameter -- because as I mentioned the default is
ZeroSSL. If you try it without specifying the server, parts of this work and other parts of this do
not work, and the problem is not obvious, or at least it was not obvious to me.&lt;/p&gt;
&lt;p&gt;In any case, I now have new certs running, and have a fully functioning system again -- which gives me
time to cut over to a new server.&lt;/p&gt;
&lt;p&gt;I hope this post helps others who are running into the same issue I was hitting.&lt;/p&gt;</content><category term="Website"></category><category term="encryption"></category><category term="letsencrypt"></category><category term="ssl"></category></entry><entry><title>Blog automation</title><link href="https://www.unixdude.net/posts/2021/Sep/26/blog-automation/" rel="alternate"></link><published>2021-09-26T00:00:00-04:00</published><updated>2021-09-26T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-09-26:/posts/2021/Sep/26/blog-automation/</id><summary type="html">&lt;p&gt;This is a short post after a lot of work.&lt;/p&gt;
&lt;p&gt;I have been busy these last few weeks automating the installation of &lt;a href="https://www.docker.com"&gt;Docker&lt;/a&gt;,
&lt;a href="https://traefik.io/traefik/"&gt;Traefik&lt;/a&gt;, and &lt;a href="https://www.ataridude.net"&gt;my Atari blog&lt;/a&gt; with &lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt;.
I have reached the point that I can take a fresh install of Ubuntu 20.04 LTS and end up &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Sep/26/blog-automation/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is a short post after a lot of work.&lt;/p&gt;
&lt;p&gt;I have been busy these last few weeks automating the installation of &lt;a href="https://www.docker.com"&gt;Docker&lt;/a&gt;,
&lt;a href="https://traefik.io/traefik/"&gt;Traefik&lt;/a&gt;, and &lt;a href="https://www.ataridude.net"&gt;my Atari blog&lt;/a&gt; with &lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt;.
I have reached the point that I can take a fresh install of Ubuntu 20.04 LTS and end up with a
completely functional blog server.  The "fresh install" requires only my user, SSH key, and passwordless
sudo configuration... once I have that, Ansible takes care of everything else.  I simply run
&lt;code&gt;ansible-playbook playbook_blog_server.yml&lt;/code&gt; ... et voila.&lt;/p&gt;
&lt;p&gt;Now to work on correcting some of the things I did wrong here, and moving the unixdude.net blog into a
Docker container behind Traefik.&lt;/p&gt;
&lt;p&gt;For those who are interested, I have &lt;a href="https://github.com/ataridude/ansible"&gt;pushed the code&lt;/a&gt;.&lt;/p&gt;</content><category term="Website"></category><category term="docker"></category><category term="ansible"></category></entry><entry><title>Docker build</title><link href="https://www.unixdude.net/posts/2021/Sep/07/docker-build/" rel="alternate"></link><published>2021-09-07T00:00:00-04:00</published><updated>2021-09-07T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-09-07:/posts/2021/Sep/07/docker-build/</id><summary type="html">&lt;p&gt;I have been having a rough couple months with printers: My Samsung C410w is getting old, so I wanted to
replace it.  My wife recently heard about HP Instant Ink, so she wanted to try that service, but I
decided to buy a monochrome Brother printer -- which was great except &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Sep/07/docker-build/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have been having a rough couple months with printers: My Samsung C410w is getting old, so I wanted to
replace it.  My wife recently heard about HP Instant Ink, so she wanted to try that service, but I
decided to buy a monochrome Brother printer -- which was great except my wife decided she needed to be
able to print on cardstock, which the Brother could not do.  So, we returned the Brother and picked up an HP
Envy 6055 -- and proceeded to print more than 750 pages last month.  Suddenly, Instant Ink doesn't look
so affordable.&lt;/p&gt;
&lt;p&gt;Anyway, in order to go back to a laser/LED printer, I need to find a replacement to the Envy's scanner.
Well, for 15+ years I have had a CanoScan LiDE 30, which still works fine.  I had been using it for
years with &lt;a href="http://www.ellert.se/twain-sane/"&gt;Mattias Ellert's excellent TWAIN SANE Mac utilities&lt;/a&gt;,
but Mattias has not maintained this for 4 years now, so I switched to using scanimage on a Raspberry Pi.&lt;/p&gt;
&lt;p&gt;Scanimage is fine for me, but there's no WAF there -- and now that I need to increase the WAF of my
scanner setup, and now that I'm learning about
Docker, I wanted to create a Docker image containing a scanner utility that I could run on a Raspberry
Pi connected to the scanner, which could then be left in a convenient location for my wife to use.&lt;/p&gt;
&lt;p&gt;In doing some research for
this project, tonight I found &lt;a href="https://github.com/sbs20/scanservjs"&gt;this nice front end&lt;/a&gt;, which is
also &lt;a href="https://hub.docker.com/r/sbs20/scanservjs"&gt;available as a Docker image&lt;/a&gt;.  Unfortunately, that
Docker image is only available for amd64 architecture -- but of course my Raspberry Pi is arm64.&lt;/p&gt;
&lt;p&gt;I next tried building the image on the raspi, using the Dockerfile in the github source, but even with
an 8GB 4b model, 25+ minutes and it still had a ways to go -- and, it ran out of disk space.&lt;/p&gt;
&lt;p&gt;Thankfully, I happen to have a M1 MacBook Air, so I fired up the new M1-specific version of Docker Desktop on that, and built an arm64 image
-- in about 30 seconds!&lt;/p&gt;
&lt;p&gt;I quickly &lt;a href="https://hub.docker.com/r/ataridude/scanservjs"&gt;pushed that to Docker Hub&lt;/a&gt;, then easily ran it 
on my Raspberry Pi with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;docker container run --device=/dev/bus/usb/001/003 --name scanner -p 8080:8080 --rm ataridude/scanservjs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I'm not done yet, but this is a good place to stop tonight.&lt;/p&gt;</content><category term="General"></category><category term="docker"></category><category term="raspberry pi"></category><category term="scanner"></category></entry><entry><title>Traefik</title><link href="https://www.unixdude.net/posts/2021/Aug/12/traefik/" rel="alternate"></link><published>2021-08-12T00:00:00-04:00</published><updated>2021-08-12T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-08-12:/posts/2021/Aug/12/traefik/</id><summary type="html">&lt;p&gt;Lately I have been learning about Docker, and I want to convert my current setup to Docker,
where it makes sense to do that.  I currently run about 20 vhosts on this Digital Ocean droplet, and
at least one of those has a MySQL back end.  I also run Postfix &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Aug/12/traefik/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Lately I have been learning about Docker, and I want to convert my current setup to Docker,
where it makes sense to do that.  I currently run about 20 vhosts on this Digital Ocean droplet, and
at least one of those has a MySQL back end.  I also run Postfix/Dovecot/Sieve for mail.  And,
some other things run on here.&lt;/p&gt;
&lt;p&gt;As part of my Docker studies, I was talking to a friend recently about my setup, and we were
discussing whether Docker is the right solution for the things I mentioned.  For now I'm
going to hold off on using Docker for my mail server, but I know there are some
container-based mail server solutions; I will look at those later, once I have migrated at least
some of the vhosts.&lt;/p&gt;
&lt;p&gt;My friend and I started by discussing the vhosts I run.  Enter &lt;a href="https://traefik.io"&gt;Traefik&lt;/a&gt;, a free, Docker-
based and Docker-oriented proxy solution.  Even better: containers are automatically registered
with Traefik, and from what I have seen so far the only configuration necessary is to set some
tags on the containers as they are run, in your docker-compose file.&lt;/p&gt;
&lt;p&gt;I decided to take one of my vhosts -- &lt;a href="http://www.ataridude.net/"&gt;www.ataridude.net&lt;/a&gt; -- and run
it in/with Traefik.  I had some good success last night, and while it is not completely ready yet,
you can add this host entry to your system if you want to see it before it goes live:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;159.65.169.236&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ataridude&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To get this up and running, I built a docker-compose file based off of the one found in the
&lt;a href="https://doc.traefik.io/traefik/getting-started/quick-start/"&gt;Traefik quick-start&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3&amp;#39;&lt;/span&gt;

&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# The official v2 Traefik docker image&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traefik&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Enables the web UI and tells Traefik to listen to docker&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insecure&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;providers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# The HTTP port&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;80:80&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# The Web UI (enabled by --api.insecure=true)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;8080:8080&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# So that Traefik can listen to the Docker events&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;atariblog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ataridude&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;private&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;atariblog&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;traefik.http.routers.atariblog.rule=Host(`www.ataridude.net`)&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The observant reader will note that the Traefik admin console is open and available.  Ordinarily this would not be a good idea,
but port 8080 is only available via ZeroTier (my Digital Ocean firewall configuration blocks port 8080), and if someone
joins my ZeroTier network, I have bigger issues than the Traefik admin console.&lt;/p&gt;
&lt;p&gt;My blogs are Pelican-based, but I'm trying to get away from installing software on my systems,
at least as much as possible, so I decided to build the ataridude.net image using &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/"&gt;Docker multi-
stage image builds&lt;/a&gt;.  This
means I do not need Pelican or anything else installed on my server -- I only need Docker.&lt;/p&gt;
&lt;p&gt;Here is the Dockerfile I'm using to build that image:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;FROM python:3 AS builder
WORKDIR /usr/src/app

COPY requirements.txt ./requirements.txt
RUN pip install -r requirements.txt
ADD content ./content
ADD theme ./theme
COPY pelicanconf.py ./
RUN pelican /usr/src/app/content/ -s pelicanconf.py

FROM nginx:latest

COPY --from=0 /usr/src/app/output /usr/share/nginx/html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I based this on my friend Brad's &lt;a href="https://gitlab.com/blcarman/blog/-/blob/master/Dockerfile"&gt;Dockerfile&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It's not as automated as I'd like, but it does work, and I will continue to improve it.&lt;/p&gt;
&lt;p&gt;In addition to greater automation, I plan to start moving vhosts from my FreeBSD droplet over to a new Docker- and Ubuntu-based droplet.&lt;/p&gt;</content><category term="Website"></category><category term="traefik"></category><category term="docker"></category></entry><entry><title>June 2021 update</title><link href="https://www.unixdude.net/posts/2021/Jun/14/june-2021-update/" rel="alternate"></link><published>2021-06-14T00:00:00-04:00</published><updated>2021-06-14T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-06-14:/posts/2021/Jun/14/june-2021-update/</id><summary type="html">&lt;p&gt;I've been busy over the last few weeks, so there will be several updates in here.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Over the weekend I updated my Ubiquiti switches, which required that I shut down my ESXi servers.  The
R610 came back just fine, but the raspi4 ARM one did not.  The problem on the &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Jun/14/june-2021-update/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've been busy over the last few weeks, so there will be several updates in here.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Over the weekend I updated my Ubiquiti switches, which required that I shut down my ESXi servers.  The
R610 came back just fine, but the raspi4 ARM one did not.  The problem on the Raspberry Pi was
the &lt;a href="https://github.com/pftf/RPi4/issues/104"&gt;known UEFI config corruption issue&lt;/a&gt;, when the UEFI config
is saved on the SD chip.&lt;/p&gt;
&lt;p&gt;I thought maybe I would have to buy a new SD chip, but it turns out that only the RPI_EFI.fd file was
corrupt.  Unfortunately my previous blog posts did not serve their purpose -- I was not able to use them
to reinstall the Raspberry Pi ESXi ARM fling, and had to do all the research again, so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rudimartinsen.com/2020/10/07/esxi-on-arm-fling-install-on-rpi/"&gt;ESXi on ARM installation howto&lt;/a&gt; (there are many; this is the one I used last night)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.vmware.com/arm/2020/10/17/esxi-arm-with-iscsi/"&gt;ESXi on iSCSI on ARM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since my SD chip was fine -- "diff -r" showed that only RPI_EFI.fd had changed since install -- I copied the
RPI_EFI.fd file to the SD chip, then booted the Raspberry pi.&lt;/p&gt;
&lt;p&gt;I updated the EFI config as shown in step 3 of the install link above (the step which removes the 3GB RAM limit),
then I reconfigured the EFI to boot from iSCSI, as shown in the second link.  That post does not mention an issue
specific to Synology NASes, so I'll mention it here: when using a Synology NAS, the Boot LUN must be 1, not the
default of 0.&lt;/p&gt;
&lt;p&gt;After that, I was able to boot my ESXi-on-ARM raspi again.  It is currently sitting on my desk,
and I'll probably leave it there, since I do not have remote console to it: with it on my desk, I can
easily connect a monitor and keyboard when needed.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I decided I wanted to refresh my VMware skills, so I signed up for VMUG Advantage again about a week ago.  One
night last week I set up vCSA and then a cluster of 3 ESXi VMs.  VMware's unsupported-but-works-fine-in-a-lab
nested virtualization functionality is awesome, and I was feeling generous so I gave those 3 ESXi VMs 32GB and
8 vCPUs.  Since the R610 is not supported on v7 VMware products (the CPU is too old), I'm only running ESXi and
vCSA v6.7, but that's good enough for now.  It might be time to upgrade soon.&lt;/p&gt;
&lt;p&gt;I put those nested ESXi VMs on my lab VLAN, and I have discovered an interesting issue: I cannot use Netboot.xyz
with VMs in that cluster.  I'm still trying to figure out why, but they just don't work.  The ESXi VMs are on
VLAN 7 (lab VLAN, 192.168.7.0/24), and any VM on that VLAN that is hosted directly on the R610 will PXE boot to
netboot.xyz without issue, and I can install any OS.  However, nested VMs (those running on the ESXi VMs) will
PXE boot to my menu, and can PXE boot local things, but they will not PXE boot netboot.xyz -- the netboot.xyz
menu loads, but no OS can be installed; see screenshot below.  Again, if I do exactly the same thing with
a VM on the R610, it works perfectly. Bizarre.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Failed netboot.xyz install" src="/images/failed-netbootxyz-install.jpg"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;One specific reason for signing up for VMUG Advantuage again was that I want to play with NSX again, and to play
with vSAN for the first time.  Those are both upcoming projects.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Another fun thing I did over the weekend was to telnet to an Ubuntu VM from my Atari 800.  There is a really cool
peripheral currently available for Atari 8-bit computers called the &lt;a href="https://fujinet.online"&gt;FujiNet&lt;/a&gt;, and using
a terminal program, one can use telnet.  I have &lt;a href="https://www.ataridude.net/posts/2021/Jun/14/telnetting-via-fujinet/"&gt;written up more on my Atari blog&lt;/a&gt;.&lt;/p&gt;</content><category term="Networking"></category><category term="vmware"></category><category term="atari"></category><category term="raspberry pi"></category><category term="esxi"></category><category term="ubiquiti"></category></entry><entry><title>ZeroTier Is Fun</title><link href="https://www.unixdude.net/posts/2021/May/18/zerotier-is-fun/" rel="alternate"></link><published>2021-05-18T00:00:00-04:00</published><updated>2021-05-18T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-05-18:/posts/2021/May/18/zerotier-is-fun/</id><summary type="html">&lt;p&gt;I recently installed a &lt;a href="https://www.synology.com/en-us/products/DS118"&gt;Synology DS118&lt;/a&gt; at a friend's house
for remote backup using &lt;a href="https://www.synology.com/en-us/dsm/feature/hyper_backup"&gt;Synology's Hyper Backup solution&lt;/a&gt;.
The DS118 is on my ZeroTier "storage" network, a network shared by the main Synology at my house -- that way,
my main NAS backs up to a local system (that is, something &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/May/18/zerotier-is-fun/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently installed a &lt;a href="https://www.synology.com/en-us/products/DS118"&gt;Synology DS118&lt;/a&gt; at a friend's house
for remote backup using &lt;a href="https://www.synology.com/en-us/dsm/feature/hyper_backup"&gt;Synology's Hyper Backup solution&lt;/a&gt;.
The DS118 is on my ZeroTier "storage" network, a network shared by the main Synology at my house -- that way,
my main NAS backs up to a local system (that is, something on the same layer 2 network), which makes that part
easy.  I was able to prime the backup at my house and ensure that everything worked, then I gave the DS118 to my
friend to take to his house -- and the backup worked exactly as it did when both units were at my house.
This is why I like ZeroTier.&lt;/p&gt;
&lt;p&gt;Today I realized that the DS118 is not sending notification emails, and I definitely want it to be able to send email
when it has something to report.  I enabled notifications on the DS118 and configured it to send me mail.  It seems
my friend's ISP is blocking outbound email, because every test message failed -- that is, until I reconfigured
the DS118 to relay through the raspberry pi at my house, which is on the same ZeroTier "storage" network.&lt;/p&gt;
&lt;p&gt;The raspberry pi is my home mail relay, through which all other systems at my house send mail to my DigitalOcean droplet:
the raspi and the droplet are on the same ZeroTier network.&lt;/p&gt;
&lt;p&gt;So, now I have notifications from my DS118, relayed through the raspi at my house, using two ZeroTier networks.&lt;/p&gt;
&lt;p&gt;ZeroTier is fun.&lt;/p&gt;</content><category term="Networking"></category><category term="networking"></category><category term="zerotier"></category></entry><entry><title>PXE booting on ARM64</title><link href="https://www.unixdude.net/posts/2021/Apr/23/pxe-booting-on-arm64/" rel="alternate"></link><published>2021-04-23T00:00:00-04:00</published><updated>2021-04-23T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-04-23:/posts/2021/Apr/23/pxe-booting-on-arm64/</id><summary type="html">&lt;p&gt;As previously mentioned, my next goal was going to be PXE booting VMs running on the
ESXi ARM Fling.  Using &lt;a href="https://discourse.ubuntu.com/t/netbooting-the-live-server-installer-via-uefi-pxe-on-arm-aarch64-arm64-and-x86-64-amd64/19240"&gt;this page&lt;/a&gt; as a guide, I now have this working.&lt;/p&gt;
&lt;p&gt;That guide is pretty good, but I had to do adapt it to my setup.&lt;/p&gt;
&lt;p&gt;As instructed, I started by &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Apr/23/pxe-booting-on-arm64/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;As previously mentioned, my next goal was going to be PXE booting VMs running on the
ESXi ARM Fling.  Using &lt;a href="https://discourse.ubuntu.com/t/netbooting-the-live-server-installer-via-uefi-pxe-on-arm-aarch64-arm64-and-x86-64-amd64/19240"&gt;this page&lt;/a&gt; as a guide, I now have this working.&lt;/p&gt;
&lt;p&gt;That guide is pretty good, but I had to do adapt it to my setup.&lt;/p&gt;
&lt;p&gt;As instructed, I started by downloading the grub EFI binary and installing that
on my TFTP server, at &lt;code&gt;tftp.unixdude.net/grubnetaa64.efi.signed&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I updated my &lt;a href="https://store.ui.com/products/unifi-security-gateway"&gt;USG&lt;/a&gt; to add a new IP subnet and VLAN
for the ARM64 VMs, so that I could set up a PXE configuration specifically for those VMs, without
affecting the PXE setup I have for x64 systems.  Yes, if I ran my own DHCP server, I could have added
configuration to it to detect the client architecture and to have it send the correct boot code based
on that.  This way was easy, and it has the benefit of not affecting my home network in the case that the DHCP
server VM is down. (High WAF in the network not going down.)&lt;/p&gt;
&lt;p&gt;On the new subnet, I specify the DNS server (my &lt;a href="https://www.unixdude.net/posts/2021/Mar/11/frr-and-anycast/"&gt;anycast IP address&lt;/a&gt;), and
I point the "DHCP network boot" options to my TFTP server, with a boot filename of &lt;code&gt;/grubnetaa64.efi.signed&lt;/code&gt;.
I also specify the DHCP TFTP Server IP address.&lt;/p&gt;
&lt;p&gt;On the filer, I extracted the &lt;code&gt;grub.cfg&lt;/code&gt;, &lt;code&gt;initrd&lt;/code&gt;, and &lt;code&gt;vmlinuz&lt;/code&gt; files as instructed.  Initially
I tried putting those files into a &lt;code&gt;/arm64&lt;/code&gt; directory on my filer, but that did not work for me, so
I moved them to the root directory and was able to PXE boot the VM right away.&lt;/p&gt;
&lt;p&gt;I added the &lt;code&gt;grub.cfg&lt;/code&gt; entry as indicated, modifying it to point to my local copy of the
Ubuntu image.&lt;/p&gt;
&lt;p&gt;After that, I booted the VM.  The first time I booted it, I ran out of memory because
I had only given the VM 1GB of RAM.  I increased that to 4GB (half the memory of the raspi)
and was able to successfully PXE boot a VM and install Ubuntu.&lt;/p&gt;
&lt;p&gt;&lt;img alt="arm-pxe2" src="/images/arm-pxe2.png"&gt;
&lt;img alt="arm-pxe4" src="/images/arm-pxe4.png"&gt;&lt;/p&gt;
&lt;p&gt;I consider this a success despite its impracticality: I cannot realistically PXE boot VMs if
I have to dedicate half the server's memory in order to do it.&lt;/p&gt;</content><category term="Home lab"></category><category term="virtualization"></category><category term="vmware"></category><category term="pxe"></category><category term="home lab"></category></entry><entry><title>ESXi on ARM Fling - Update</title><link href="https://www.unixdude.net/posts/2021/Apr/20/esxi-on-arm-update/" rel="alternate"></link><published>2021-04-20T00:00:00-04:00</published><updated>2021-04-20T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-04-20:/posts/2021/Apr/20/esxi-on-arm-update/</id><summary type="html">&lt;p&gt;Not long after my last post, the PoE HAT for my Raspberry Pi died -- to be more accurate, one of the components
on the board disintegrated.  I don't know if this was a manufacturing defect or the result of a bad solder job
related to the fan, or something else &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Apr/20/esxi-on-arm-update/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Not long after my last post, the PoE HAT for my Raspberry Pi died -- to be more accurate, one of the components
on the board disintegrated.  I don't know if this was a manufacturing defect or the result of a bad solder job
related to the fan, or something else.  In any case, disposed of that HAT and ordered the GeeekPi PoE HAT.  My
ESXi-on-ARM setup has been up and running since, connected by a single cable.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Raspi 4" src="/images/raspi4.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I have this system booting from iSCSI, so there are no local filesystems -- the SD card is used only to initiate
the boot process, the system boots from iSCSI, and datastores are on the filer and are accessed via NFS.  I love
the elegance of this setup.&lt;/p&gt;
&lt;p&gt;&lt;img alt="ESX-ARM" src="/images/esxarm.jpg"&gt;&lt;/p&gt;
&lt;p&gt;So far, I have created several VMs: Alpine, CentOS 8, Ubuntu, Raspberry Pi OS, and FreeBSD.  I haven't really
done much with any of this, but in my time with it so far I am impressed with its speed.  Speed-wise, it obviously doesn't
compare to my R610, but for about $100, it's great for what it is, and it makes an excellent geek toy.  And yes, I bought it mostly as a toy, but I do plan to
use it for some real-world services: In addition to general OS play, I plan to at least add a VM here to my &lt;a href="https://www.unixdude.net/posts/2021/Mar/11/frr-and-anycast/"&gt;anycast DNS setup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I might also build a VM on this server in order to relocate my UniFi controller.  I'm undecided
because I'm not sure how
much I like the problem that involves: if the raspi dies, so does my ability to run my controller. Solving this problem is important since I
currently run my UniFi controller in a VM that is hosted on my R610 and is NFS mounted.  I do need to find
another solution to the UniFi controller issue, since there are two switches between my R610 and my filer --
meaning that whenever I upgrade one of those switches, I have to reloate the controller VM to my iMac. This
is not how you should do it!&lt;/p&gt;
&lt;p&gt;I haven't installed vSphere in a while, but now that I have two ESXi servers, I might do that again, so
that I can manage this entire setup more easily.&lt;/p&gt;</content><category term="Home lab"></category><category term="virtualization"></category><category term="vmware"></category><category term="raspberry pi"></category></entry><entry><title>ESXi on ARM Fling</title><link href="https://www.unixdude.net/posts/2021/Apr/07/esxi-on-arm-fling/" rel="alternate"></link><published>2021-04-07T00:00:00-04:00</published><updated>2021-04-07T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-04-07:/posts/2021/Apr/07/esxi-on-arm-fling/</id><summary type="html">&lt;p&gt;I recently decided that I wanted to play with the &lt;a href="https://flings.vmware.com/esxi-arm-edition"&gt;ESXi-on-ARM Fling&lt;/a&gt;, so
I purchased a &lt;a href="https://www.raspberrypi.org/products/raspberry-pi-4-model-b/"&gt;Raspberry Pi 4B&lt;/a&gt; (8GB).
I received my unit so I set about installing ESXi.&lt;/p&gt;
&lt;p&gt;I followed VMware's instructions in their "Fling-on-Raspberry-Pi" document.  It's not a difficult
process, but there are a few things to &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Apr/07/esxi-on-arm-fling/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently decided that I wanted to play with the &lt;a href="https://flings.vmware.com/esxi-arm-edition"&gt;ESXi-on-ARM Fling&lt;/a&gt;, so
I purchased a &lt;a href="https://www.raspberrypi.org/products/raspberry-pi-4-model-b/"&gt;Raspberry Pi 4B&lt;/a&gt; (8GB).
I received my unit so I set about installing ESXi.&lt;/p&gt;
&lt;p&gt;I followed VMware's instructions in their "Fling-on-Raspberry-Pi" document.  It's not a difficult
process, but there are a few things to note about the process found in that document.&lt;/p&gt;
&lt;p&gt;One of the first steps is to update the Raspberry Pi's EEPROM; VMware's document says to
use the Raspberry Pi Imager to flash an SD chip with the "Raspberry Pi EEPROM boot recovery" utility,
but I found this to not be available in the Imager utility.  With a little help from my favorite search engine, I found
&lt;a href="https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md"&gt;the official documentation on updating the boot EEPROM&lt;/a&gt;,
which includes commands to do it from a running instance of Raspberry Pi OS.  With that I was able
to confirm that my raspi is up-to-date.&lt;/p&gt;
&lt;p&gt;One thing to note is that the official PoE HAT is not supported (at least, not out of the box), because
its fan is controlled by the I2C, which is nonfunctional when running ESXi.  Unfortunately for me, I did
not know about this limitation before buying the official PoE HAT; I chose to solve this problem by
soldering leads from pins 4 &amp;amp; 6 on the GPIO directly to the fan -- I want the fan to always run anyway,
so that is a fine solution for me.&lt;/p&gt;
&lt;p&gt;The main use for a micro SD chip is to configure the UEFI, so don't buy a large one.  In my experience,
the micro SD chip is also your main boot device (without one inserted, my unit won't boot).  Also, you
need a USB drive on which to install ESXi.  NFS datastores are supported, so I am mounting those from
my NAS.  I use one datastore for installation ISOs, and one for VMs.&lt;/p&gt;
&lt;p&gt;I am looking into installing ESXi on an iSCSI LUN but so far I have not been able to get that
to work with my Synology: the Raspberry Pi connects (I see this on the Synology), but the LUN does not
show up in the device list on the raspi.&lt;/p&gt;
&lt;p&gt;Be sure to follow the instructions on configuring the NTP client, since it works differently than an
x86_64 ESXi server does.&lt;/p&gt;
&lt;p&gt;So far I have installed Ubuntu 20 and CentOS 8.  This is looking like a great little toy!&lt;/p&gt;</content><category term="Home lab"></category><category term="virtualization"></category><category term="vmware"></category><category term="raspberry pi"></category></entry><entry><title>M1 MacBook Air</title><link href="https://www.unixdude.net/posts/2021/Apr/06/m1-macbook-air/" rel="alternate"></link><published>2021-04-06T00:00:00-04:00</published><updated>2021-04-06T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-04-06:/posts/2021/Apr/06/m1-macbook-air/</id><summary type="html">&lt;p&gt;I recently decided to upgrade my personal laptop.  Until recently, I was using a 2015 MacBook Pro that I
bought in 2016 after Apple announced they were bringing the butterfly keyboard to the MBP.  My goal for
that purchase was for it to last until Apple released a better keyboard &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Apr/06/m1-macbook-air/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently decided to upgrade my personal laptop.  Until recently, I was using a 2015 MacBook Pro that I
bought in 2016 after Apple announced they were bringing the butterfly keyboard to the MBP.  My goal for
that purchase was for it to last until Apple released a better keyboard -- and it worked.  Last month I
traded my 2015 MBP for a new 2020 M1-powered MacBook Air, and I could not be happier with this upgrade:
The M1 is an amazing CPU, the keyboard is awesome, and the M1 MBA is a phenomenal package.&lt;/p&gt;
&lt;p&gt;Because of my love of operating systems (specifically Unix-based ones, obviously), one of the first
things I did with this system was to download the &lt;a href="https://b2b.parallels.com/Apple-Silicon"&gt;technical preview of Parallels Desktop for M1&lt;/a&gt;, so that I could run VMs on this new laptop.&lt;/p&gt;
&lt;p&gt;So far, I have installed &lt;a href="https://alpinelinux.org/downloads/"&gt;Alpine&lt;/a&gt;, &lt;a href="https://www.debian.org/distrib/netinst"&gt;Debian&lt;/a&gt;, &lt;a href="https://getfedora.org/en/server/download/"&gt;Fedora&lt;/a&gt;, &lt;a href="https://github.com/vmware/photon/wiki/Downloading-Photon-OS"&gt;Photon OS&lt;/a&gt;, &lt;a href="https://ubuntu.com/download/server/arm"&gt;Ubuntu&lt;/a&gt;, &lt;a href="https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewARM64"&gt;Windows 10&lt;/a&gt;, and &lt;a href="https://www.freebsd.org/where/"&gt;FreeBSD&lt;/a&gt;.  Most of
those distros/OSes install exactly as you would hope, but a few required some special tweaks.&lt;/p&gt;
&lt;p&gt;For Alpine and Photon OS, I found that the Parallels VM must be configured as a Debian VM.&lt;/p&gt;
&lt;p&gt;For FreeBSD, I used "Other Linux" as the OS type, and the most important part for FreeBSD is to
configure the VM to use only 1 vCPU -- it will not boot with more than 1 vCPU.&lt;/p&gt;
&lt;p&gt;So far I am extremely impressed with this M1 unit.  With the ability to run such a variety of
operating systems in VMs, it will prove even more useful to me.&lt;/p&gt;</content><category term="General"></category><category term="unix"></category><category term="virtualization"></category></entry><entry><title>Lab, and network upgrade</title><link href="https://www.unixdude.net/posts/2021/Mar/12/catalyst/" rel="alternate"></link><published>2021-03-12T00:00:00-05:00</published><updated>2021-03-12T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-03-12:/posts/2021/Mar/12/catalyst/</id><summary type="html">&lt;p&gt;I like networking -- always have.  However, today, my networking knowledge is only okay -- but I want it to be great!  My goal is to
achieve CCNP certification in 6 months.  To help with this effort, I have added a Cisco lab to my home network.
It is old equipment (2x &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Mar/12/catalyst/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I like networking -- always have.  However, today, my networking knowledge is only okay -- but I want it to be great!  My goal is to
achieve CCNP certification in 6 months.  To help with this effort, I have added a Cisco lab to my home network.
It is old equipment (2x 2610, 1x 2611, 3x 2950) running IOS 11 and 12, but that's okay, and it will soon be
upgraded: as I cut over to Ubiquiti equipment for my home network, the 2960s I am using today will move to the lab,
and I will add a layer 3 switch as well.  The lab routers will also be upgraded to something running IOS 15, but I'm not sure what yet.&lt;/p&gt;
&lt;p&gt;I like network diagrams, so for fun, here is a diagram of my current home network:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Home network 2021" src="/images/home_network_2021-03.jpg"&gt;&lt;/p&gt;
&lt;p&gt;And here is my Cisco lab:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Cisco lab 2021-03" src="/images/cisco_lab_2021-03.jpg"&gt;&lt;/p&gt;
&lt;p&gt;As you can probably imagine, I have been fun expanding my use of VLANs and BGP in my home network.&lt;/p&gt;
&lt;p&gt;I have further plans as well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduce a MySQL cluster.  This will use an anycast address (see earlier post on anycast) so that clients
can specify the anycast address and not care which server they talk to.&lt;/li&gt;
&lt;li&gt;Introduce a router between my lab and my home network.  Current plan is to use Cumulus VX for this, because
I want to learn Cumulus Linux as well.&lt;/li&gt;
&lt;li&gt;I want the lab completely separated from my home network; as you can see from the diagrams above, the lab
is connected to my home network.  This will change as I introduce Cumulus VX to the mix.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Planned network upgrades:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The 2960 in the middle will be replaced with a &lt;a href="https://store.ui.com/collections/unifi-network-routing-switching/products/usw-lite-16-poe"&gt;Ubiquiti USW-Lite-16-PoE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The MikroTik hap AC in the entertainment center will be replaced with a &lt;a href="https://store.ui.com/collections/unifi-network-routing-switching/products/usw-flex-mini"&gt;USW-Flex-Mini&lt;/a&gt; and a &lt;a href="https://store.ui.com/collections/unifi-network-access-points/products/unifi-6-long-range-access-point"&gt;U6-LR-US&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The HP ProCurve at my desk will be replaced with a &lt;a href="https://store.ui.com/collections/unifi-network-routing-switching/products/unifi-switch-8-150w"&gt;US-8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At that point, all of the switches and APs will be PoE, meaning I will have only a single place for battery
backup of the entire network, and fewer wall warts.&lt;/p&gt;</content><category term="Home lab"></category><category term="networking"></category><category term="cisco"></category><category term="homelab"></category></entry><entry><title>FRR and Anycast</title><link href="https://www.unixdude.net/posts/2021/Mar/11/frr-and-anycast/" rel="alternate"></link><published>2021-03-11T00:00:00-05:00</published><updated>2021-03-11T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-03-11:/posts/2021/Mar/11/frr-and-anycast/</id><summary type="html">&lt;p&gt;&lt;a href="https://frrouting.org"&gt;FRR&lt;/a&gt; is one of the things I have wanted to configure on my Raspberry Pi, specifically to enable
&lt;a href="https://en.wikipedia.org/wiki/Anycast"&gt;anycast&lt;/a&gt; for Pi-Hole.  The reason to do this is that I do not want my Raspberry Pi to be a single
point of failure on the network, especially since it has been &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2021/Mar/11/frr-and-anycast/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://frrouting.org"&gt;FRR&lt;/a&gt; is one of the things I have wanted to configure on my Raspberry Pi, specifically to enable
&lt;a href="https://en.wikipedia.org/wiki/Anycast"&gt;anycast&lt;/a&gt; for Pi-Hole.  The reason to do this is that I do not want my Raspberry Pi to be a single
point of failure on the network, especially since it has been connected via wifi, to date anyway.
Once I finish my transition to UniFi, it will be moved to ethernet.&lt;/p&gt;
&lt;p&gt;Anycast is useful for services like DNS, DHCP, and MySQL,
and is easier, better in some cases, than using a load balancer.  I wanted to use anycast on my home
network so that I can upgrade or reboot my Raspberry Pi, while ensuring that such maintenance
activity does not negatively affect users on my network.&lt;/p&gt;
&lt;p&gt;I started out by creating a DNS entry:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pihole-anycast.unixdude.net has address 192.168.2.1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This entry is not strictly required, it's just a convenience.&lt;/p&gt;
&lt;p&gt;I then installed FRR on multiple systems -- my Raspberry Pi and a VM
running Ubuntu 20.04.2 LTS, running on my ESXi server.&lt;/p&gt;
&lt;p&gt;On each system, I added a loopback address; on the Ubuntu VM I added the following block
to &lt;code&gt;/etc/netplan/00-installer-config.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ethernets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;networkd&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lo&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m m-Double"&gt;192.168.2.1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On the Raspberry Pi, running Raspbian (stretch), I created a file with the following contents,
saved as &lt;code&gt;/etc/network/interfaces.d/lo&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lo&lt;/span&gt;
&lt;span class="nx"&gt;iface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;loopback&lt;/span&gt;

&lt;span class="kt"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nx"&gt;iface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;static&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m m-Double"&gt;192.168.2.1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;netmask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m m-Double"&gt;255.255.255.255&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pihole&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To ensure that this file is loaded, you  might need to confirm that &lt;code&gt;/etc/network/interfaces&lt;/code&gt;
includes the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;source-directory /etc/network/interfaces.d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are two important things to note in the examples above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;that the address is a /32,&lt;/li&gt;
&lt;li&gt;and that it is added to the loopback interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, configure FRR to publish that loopback address to the network.  I do this using BGP,
and the relevant part of my configuration is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bgp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;65007&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m m-Double"&gt;192.168.1.254&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remote&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;65007&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;family&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ipv4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;unicast&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;redistribute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;connected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;anycast&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;family&lt;/span&gt;
&lt;span class="p"&gt;!&lt;/span&gt;
&lt;span class="nx"&gt;access&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;seq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;permit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m m-Double"&gt;192.168.2.1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="p"&gt;!&lt;/span&gt;
&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;anycast&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;permit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;
&lt;span class="p"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, I am using BGP ASN 65007 on my home network.  My router's IP address is 192.168.1.254,
so I have FRR peer with that address.  Note the route
map and access list configured to publish the loopback's /32 address.&lt;/p&gt;
&lt;p&gt;We can take a look at my Ubiquiti USG's BGP routes for that address, and we see the two routes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;admin&lt;/span&gt;&lt;span class="nv"&gt;@ubnt&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bgp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;192.168.2.1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="n"&gt;BGP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;routing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;192.168.2.1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="nl"&gt;Paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;#1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Default&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Routing&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;Not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;advertised&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;any&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;peer&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;Local&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mf"&gt;192.168.2.249&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;192.168.2.249&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;192.168.2.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;Origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;incomplete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localpref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;best&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;Last&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;update&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mar&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;Local&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mf"&gt;192.168.2.250&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;192.168.2.250&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;192.168.2.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;Origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;incomplete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localpref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;Last&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;update&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mar&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;

&lt;span class="k"&gt;admin&lt;/span&gt;&lt;span class="nv"&gt;@ubnt&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And here is its routing table:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;admin&lt;/span&gt;&lt;span class="nv"&gt;@ubnt&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;
&lt;span class="nl"&gt;Codes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OSPF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ISIS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BGP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;selected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FIB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;

&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0.0.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1/0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;via&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;172.16.0.254&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eth0&lt;/span&gt;
&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;192.168.2.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;directly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eth1&lt;/span&gt;&lt;span class="mf"&gt;.2&lt;/span&gt;
&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;192.168.2.1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;200/0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;via&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;192.168.2.249&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eth1&lt;/span&gt;&lt;span class="mf"&gt;.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;d17h41m&lt;/span&gt;
&lt;span class="k"&gt;admin&lt;/span&gt;&lt;span class="nv"&gt;@ubnt&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(some data removed)&lt;/p&gt;
&lt;p&gt;Now, anything on my home
network can reach 192.168.2.1/32, and it does not matter which Pi-Hole answers the request, because both
are configured identically.  (I have to manually keep their configurations in sync today, but I am
working on that.)&lt;/p&gt;
&lt;p&gt;As I mentioned earlier, a setup like this is useful for DNS, as I am doing here.  It is also useful
for DHCP, where multiple DHCP servers use the same back end, and are all configured with the same
DHCP server identifier.  Using this configuration, the DHCP service stays up as long as at least one
DHCP server is available; the backend database ensures consistency between the pools advertised by
the servers.&lt;/p&gt;
&lt;p&gt;Speaking of databases, this solution works similarly with MySQL: one can build a Percona cluster, where
all servers share a single IP address via anycast.  Clients connect to the anycast address, and the
cluster keeps all servers updated to the latest changes.&lt;/p&gt;</content><category term="Networking"></category><category term="dns"></category><category term="frr"></category><category term="networking"></category><category term="pi-hole"></category><category term="anycast"></category><category term="raspberry pi"></category></entry><entry><title>General update</title><link href="https://www.unixdude.net/posts/2021/Mar/10/2021-03-general-update/" rel="alternate"></link><published>2021-03-10T00:00:00-05:00</published><updated>2021-03-10T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2021-03-10:/posts/2021/Mar/10/2021-03-general-update/</id><summary type="html">&lt;p&gt;It has been a while since I did much of interest in the home lab, but that is changing this week.&lt;/p&gt;
&lt;p&gt;I am starting to rework lots of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This blog content is now tracked in a bitbucket repo&lt;/li&gt;
&lt;li&gt;I am upgrading my home network to UniFi hardware&lt;/li&gt;
&lt;li&gt;I am &amp;#8230;&lt;/li&gt;&lt;a class="label label-primary read-more" href="/posts/2021/Mar/10/2021-03-general-update/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;It has been a while since I did much of interest in the home lab, but that is changing this week.&lt;/p&gt;
&lt;p&gt;I am starting to rework lots of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This blog content is now tracked in a bitbucket repo&lt;/li&gt;
&lt;li&gt;I am upgrading my home network to UniFi hardware&lt;/li&gt;
&lt;li&gt;I am moving to an IaC setup&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first part was easy: create a repo, then push to it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;remote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="nv"&gt;@bitbucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;org&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;unixdude&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;blog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I should have done that a long time ago, but at least I had it tracked in a repo.  Now it is tracked in a
remote repo.  I will eventually migrate this server to Linux so that I can use containers; right now it runs
FreeBSD.&lt;/p&gt;
&lt;p&gt;The second part comes after much consideration of what I wanted to do.  My 3-story house has many WiFi dead spots,
and I'm tired of that: it means that my Airport Express and Ring doorbell often don't work well.  I decided to go
with a UniFi setup, mostly for the single management pane and the ease of adding and upgrading hardware.  I should
have the new hardware sometime this week, and I hope to get it installed soon after I receive it.&lt;/p&gt;
&lt;p&gt;Regarding the IaC setup, that is something several friends have done, and is something I should have done sooner.&lt;/p&gt;
&lt;p&gt;I'm working toward having more cattle and fewer pets, and I'm working toward automated installs of that cattle.
I'm starting with Pi-Hole, which I use on a pet Raspberry Pi today.  When I'm done, Pi-Hole will be installed
on the raspi as well as a VM, and those two systems will share an IP address via anycast, so either one can go
down without affecting users on my network.&lt;/p&gt;
&lt;p&gt;I'm also working toward using containers for things like Pi-Hole.  All of this will be installed and configured
via Ansible.&lt;/p&gt;
&lt;p&gt;Speaking of Ansible, it is taking over some of the responsibilities of my PXE setup: my PXE setup now defaults to
a very basic install of Ubuntu 20.04.2 LTS, and Ansible will now be responsible for installing and configuring
packages such as NTP and other user- and system-configuration.&lt;/p&gt;</content><category term="Home lab"></category><category term="unix"></category><category term="ansible"></category><category term="pi-hole"></category><category term="raspberry pi"></category></entry><entry><title>NFS automounter</title><link href="https://www.unixdude.net/posts/2019/Sep/16/nfs-automounter/" rel="alternate"></link><published>2019-09-16T00:00:00-04:00</published><updated>2019-09-16T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2019-09-16:/posts/2019/Sep/16/nfs-automounter/</id><summary type="html">&lt;p&gt;In &lt;a href="https://www.unixdude.net/posts/2019/Feb/20/scanner/"&gt;an earlier post&lt;/a&gt;, I mentioned the NFS automounter.
I make use of the NFS automounter everywhere.  And by "everywhere," I mean "nearly every Unix system I install."
FreeBSD, NeXT systems, Mac OS X, Linux -- they all get the configuration.&lt;/p&gt;
&lt;p&gt;The NFS automounter is useful because of the ease of &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2019/Sep/16/nfs-automounter/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;In &lt;a href="https://www.unixdude.net/posts/2019/Feb/20/scanner/"&gt;an earlier post&lt;/a&gt;, I mentioned the NFS automounter.
I make use of the NFS automounter everywhere.  And by "everywhere," I mean "nearly every Unix system I install."
FreeBSD, NeXT systems, Mac OS X, Linux -- they all get the configuration.&lt;/p&gt;
&lt;p&gt;The NFS automounter is useful because of the ease of use: if I need a file, I simply cd to the correct
location and use the file.&lt;/p&gt;
&lt;p&gt;I install my automounts in /auto, so I cd to /auto/documents or /auto/downloads or whatever.  My ESXi server
uses files that on other systems are located under /auto/esx.&lt;/p&gt;
&lt;p&gt;To make best use of this, I use the same user ID on all systems, and for security best practices, I set root squash
even though I'm the only user on the filer.&lt;/p&gt;
&lt;p&gt;Also, because my filer is a Synology, I am able to share audio/video between iTunes and Synology's DS Audio/DS Video.
I do this by storing my iTunes library under /auto/media, and I set DS Audio and DS Video to use files found under
/volume1/media on the Synology.&lt;/p&gt;
&lt;p&gt;The NFS filer is also useful remotely, because of &lt;a href="https://www.unixdude.net/posts/2019/Sep/10/home-network-update-2019-09/"&gt;my use of ZeroTier&lt;/a&gt;.  The NFS automounter,
with its automatic disconnects, works particularly well in this type of situation.&lt;/p&gt;</content><category term="NFS"></category><category term="unix"></category><category term="nfs"></category><category term="synology"></category><category term="zerotier"></category></entry><entry><title>Home Network update 2019-09</title><link href="https://www.unixdude.net/posts/2019/Sep/10/home-network-update-2019-09/" rel="alternate"></link><published>2019-09-10T00:00:00-04:00</published><updated>2019-09-10T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2019-09-10:/posts/2019/Sep/10/home-network-update-2019-09/</id><summary type="html">&lt;p&gt;My home network has changed significantly in recent months.&lt;/p&gt;
&lt;p&gt;First, I purchased three MikroTik devices, an &lt;a href="https://mikrotik.com/product/RB260GS"&gt;RB260GS&lt;/a&gt; for my office and two
&lt;a href="https://mikrotik.com/product/RB962UiGS-5HacT2HnT"&gt;hAP AC&lt;/a&gt;, one for my office and one for my garage.  This allowed
me to simplify my network and it provides for several changes.  My network now looks &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2019/Sep/10/home-network-update-2019-09/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;My home network has changed significantly in recent months.&lt;/p&gt;
&lt;p&gt;First, I purchased three MikroTik devices, an &lt;a href="https://mikrotik.com/product/RB260GS"&gt;RB260GS&lt;/a&gt; for my office and two
&lt;a href="https://mikrotik.com/product/RB962UiGS-5HacT2HnT"&gt;hAP AC&lt;/a&gt;, one for my office and one for my garage.  This allowed
me to simplify my network and it provides for several changes.  My network now looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Home network 2019" src="/images/home_network_2019.jpg"&gt;&lt;/p&gt;
&lt;p&gt;As a result, I can upgrade the Synology RT1900ac without taking down my entire home network. I can upgrade the
office switch or hAP AC without affecting my family's network access, and updates to the garage hAP AC will only
affect my R610-based home lab.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;A while ago I was introduced to &lt;a href="http://www.zerotier.com/"&gt;Zerotier&lt;/a&gt;.  I gave it
a look and found an extremely useful networking solution.  To use it, one need only do a few simple things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create a Zerotier login&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a network&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the software on your systems/devices&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Join those systems/devices to your network&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Approve the join requests (if your network is private)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href="https://my.zerotier.com/"&gt;Zerotier admin UI&lt;/a&gt; shows the IP addresses of each system, and it allows the
user to set a nickname for each device.&lt;/p&gt;
&lt;p&gt;Using this solution, I was able to completely disable global SSH access to all of my systems:
now, the only way to SSH to my systems is to be on my Zerotier network or my home network.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I created a services VM that sits on both ZeroTier and my home network; this VM forwards packets between
ZeroTier and my home network, so with a few simple routes added to a few devices, I can now access my entire home
network from anywhere:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Synology RT1900ac has routes to the Zerotier subnet (via the services VM) and the lab subnet (via the hAP AC in the garage)&lt;/li&gt;
&lt;li&gt;My laptop has routes to the home and lab subnets, via the services VM&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;macOS has long had a very cool feature where you can use per-domain DNS servers, so I use my home-based DNS
servers to resolve *.unixdude.net no matter where I am.  This, coupled with these new routes, allows me to
resolve everything at home by hostname, and to connect to it.  This is immensely useful.&lt;/p&gt;</content><category term="Home lab"></category><category term="network"></category><category term="zerotier"></category><category term="mikrotik"></category><category term="synology"></category><category term="macos"></category><category term="dns"></category></entry><entry><title>SSH, screen, and tunnels - oh my</title><link href="https://www.unixdude.net/posts/2019/Aug/28/ssh-screen-tunnels-oh-my/" rel="alternate"></link><published>2019-08-28T00:00:00-04:00</published><updated>2019-08-28T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2019-08-28:/posts/2019/Aug/28/ssh-screen-tunnels-oh-my/</id><summary type="html">&lt;p&gt;I was recently asked about SSH, tunnels, and reconnecting disconnected sessions. Some people use
&lt;a href="https://mosh.org/"&gt;mosh&lt;/a&gt;, but I take a different approach, one that does not require any special
server software on the target server.&lt;/p&gt;
&lt;p&gt;As with mosh, I recognize that sessions will become disconnected.  As such, I run a
&lt;a href="https://www.gnu.org/software/screen/"&gt;screen &amp;#8230;&lt;/a&gt;&lt;a class="label label-primary read-more" href="/posts/2019/Aug/28/ssh-screen-tunnels-oh-my/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I was recently asked about SSH, tunnels, and reconnecting disconnected sessions. Some people use
&lt;a href="https://mosh.org/"&gt;mosh&lt;/a&gt;, but I take a different approach, one that does not require any special
server software on the target server.&lt;/p&gt;
&lt;p&gt;As with mosh, I recognize that sessions will become disconnected.  As such, I run a
&lt;a href="https://www.gnu.org/software/screen/"&gt;screen&lt;/a&gt; session
on a server in the data center, and I initiate all SSH connections from that screen session. I use
screen instead of tmux, mostly because it is extremely simple to create a new screen tab/window from
the command line.  I have created aliases to run a command in a new screen tab.&lt;/p&gt;
&lt;p&gt;Here is a sample ~/.screenrc file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;escape ^Xx
startup_message off
vbell off
backtick 0 10 10 dfh
backtick 1 10 10 s_uptime
hardstatus alwayslastline &amp;quot;%{.bG}%H%{-}%{.bW} %-w%{.rW}%f%n %t%{-}%+w %=%{..G}[ %l ]%{..Y} %`&amp;quot;
defscrollback 5000
termcapinfo xterm* ti@:te@
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this screenrc file, we note that I run 2 commands every 10 seconds, and that the output of those
commands shows up in my status line.  &lt;code&gt;dfh&lt;/code&gt; simply prints the output of &lt;code&gt;df -h&lt;/code&gt; for a certain
filesystem, usually /, in a short format, followed by the current time. &lt;code&gt;s_uptime&lt;/code&gt; shows load average
for the box.&lt;/p&gt;
&lt;p&gt;Early on, I used an alias to create new screen windows/tabs.  I have switched to using a shell script
because I found that when the process terminated (e.g., when the remote server disconnected), the window/tab
disappeared without any explanation as to what happened.  My script catches that and keeps the tab open
until I acknowledge it.&lt;/p&gt;
&lt;p&gt;In this script, the variable &lt;code&gt;$MAIN_SCREENS&lt;/code&gt; holds the hostnames of all systems on which I want to run screen (this
allows this script to function correctly even on systems without screen support), and &lt;code&gt;$SHORT_HOSTNAME&lt;/code&gt;
is the name of the local system.&lt;/p&gt;
&lt;p&gt;Here is the script I use: (the first line is a shebang, but that messes up markdown)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;!/bin/sh
COMMAND=&amp;quot;$*&amp;quot;
lines=`echo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$MAIN_SCREENS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SHORT_HOSTNAME&lt;/span&gt;`
if&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-eq&lt;span class="w"&gt; &lt;/span&gt;0&lt;span class="w"&gt; &lt;/span&gt;];&lt;span class="w"&gt; &lt;/span&gt;then
&lt;span class="w"&gt;    &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;This&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;one&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;systems&lt;span class="w"&gt; &lt;/span&gt;running&lt;span class="w"&gt; &lt;/span&gt;screen,&lt;span class="w"&gt; &lt;/span&gt;so&lt;span class="w"&gt; &lt;/span&gt;simply&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;command
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;COMMAND&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;
else
&lt;span class="w"&gt;    &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;This&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;runs&lt;span class="w"&gt; &lt;/span&gt;screen,&lt;span class="w"&gt; &lt;/span&gt;so&lt;span class="w"&gt; &lt;/span&gt;proceed&lt;span class="w"&gt; &lt;/span&gt;as&lt;span class="w"&gt; &lt;/span&gt;normal

FILENAME=`mktemp&lt;span class="w"&gt; &lt;/span&gt;~/.screen_tab.XXXXXX`
cat&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;EOF&lt;/span&gt;
&lt;span class="err"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="err"&gt;function&lt;/span&gt; &lt;span class="err"&gt;clean_up&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="err"&gt;Perform&lt;/span&gt; &lt;span class="err"&gt;program&lt;/span&gt; &lt;span class="err"&gt;exit&lt;/span&gt; &lt;span class="err"&gt;housekeeping&lt;/span&gt;
    &lt;span class="err"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;&amp;quot;Command&lt;/span&gt; &lt;span class="err"&gt;exited&lt;/span&gt; &lt;span class="err"&gt;with&lt;/span&gt; &lt;span class="err"&gt;exitcode&lt;/span&gt; &lt;span class="err"&gt;\${EXITCODE}&amp;quot;&lt;/span&gt;
    &lt;span class="err"&gt;echo&lt;/span&gt;
    &lt;span class="err"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;&amp;quot;Press&lt;/span&gt; &lt;span class="err"&gt;ENTER&lt;/span&gt; &lt;span class="err"&gt;to&lt;/span&gt; &lt;span class="err"&gt;continue...&amp;quot;&lt;/span&gt;
    &lt;span class="err"&gt;echo&lt;/span&gt;
    &lt;span class="err"&gt;read&lt;/span&gt;
    &lt;span class="err"&gt;rm&lt;/span&gt; &lt;span class="err"&gt;-f&lt;/span&gt; &lt;span class="err"&gt;${FILENAME}&lt;/span&gt;
    &lt;span class="err"&gt;exit&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;trap&lt;/span&gt; &lt;span class="err"&gt;clean_up&lt;/span&gt; &lt;span class="err"&gt;SIGINT&lt;/span&gt;

&lt;span class="err"&gt;${COMMAND}&lt;/span&gt;
&lt;span class="na"&gt;EXITCODE=&lt;/span&gt;&lt;span class="s"&gt;\$?&lt;/span&gt;
&lt;span class="err"&gt;if&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt; &lt;span class="err"&gt;\$EXITCODE&lt;/span&gt; &lt;span class="err"&gt;-gt&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;];&lt;/span&gt; &lt;span class="err"&gt;then&lt;/span&gt;
    &lt;span class="err"&gt;clean_up&lt;/span&gt;
&lt;span class="err"&gt;fi&lt;/span&gt;
&lt;span class="err"&gt;rm&lt;/span&gt; &lt;span class="err"&gt;-f&lt;/span&gt; &lt;span class="err"&gt;${FILENAME}&lt;/span&gt;
&lt;span class="err"&gt;EOF&lt;/span&gt;
&lt;span class="err"&gt;chmod&lt;/span&gt; &lt;span class="err"&gt;755&lt;/span&gt; &lt;span class="err"&gt;${FILENAME}&lt;/span&gt;
&lt;span class="na"&gt;COMMAND=&lt;/span&gt;&lt;span class="s"&gt;`echo&lt;/span&gt; &lt;span class="err"&gt;${COMMAND}&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;sed&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;s/.unixdude.net//&amp;#39;`&lt;/span&gt;

&lt;span class="na"&gt;TERMTYPE=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="err"&gt;if&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt; &lt;span class="err"&gt;${TERM}&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;quot;screen.xterm-256color&amp;quot;&lt;/span&gt; &lt;span class="err"&gt;];&lt;/span&gt; &lt;span class="err"&gt;then&lt;/span&gt;
    &lt;span class="na"&gt;TERMTYPE=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-T xterm&amp;quot;&lt;/span&gt;
&lt;span class="err"&gt;fi&lt;/span&gt;
&lt;span class="err"&gt;screen&lt;/span&gt; &lt;span class="err"&gt;${TERMTYPE}&lt;/span&gt; &lt;span class="err"&gt;-t&lt;/span&gt; &lt;span class="err"&gt;&amp;quot;${COMMAND}&amp;quot;&lt;/span&gt; &lt;span class="err"&gt;&amp;quot;${FILENAME}&amp;quot;&lt;/span&gt;

&lt;span class="err"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since I always run screen on systems I consider to be jump hosts, I use aliases
to connect to those systems.  Here is an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;alias cjb &amp;quot;tabname jump-rdu-01; ssh jump-rdu-01.rdu.domain.com -t &amp;#39;screen -Rd&amp;#39;; tabname LOCAL_SHELL&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;tabname&lt;/code&gt; is a short script (it could be an alias) that changes the name of the window/tab in my
terminal program: (again, the first line is a shebang)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt; !/bin/bash
printf &amp;quot;\e]1;%s\a&amp;quot; $1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A big trick to all of this is reconnecting after a disconnection.  My solution here is to use a common,
persistent, known value for &lt;code&gt;${SSH_AUTH_SOCKET}&lt;/code&gt;.  To do that, I modify &lt;code&gt;SSH_AUTH_SOCKET&lt;/code&gt; variable
on login.  First, I create a symlink called &lt;code&gt;~/.ssh_auth_socket_${SHORT_HOSTNAME}&lt;/code&gt;
to the actual &lt;code&gt;$SSH_AUTH_SOCKET&lt;/code&gt;, and then I set &lt;code&gt;$SSH_AUTH_SOCKET&lt;/code&gt; with a value of
&lt;code&gt;~/.ssh_auth_socket_${SHORT_HOSTNAME}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The value here is that &lt;code&gt;$SSH_AUTH_SOCKET&lt;/code&gt; never changes between logins, so any existing shell sessions, and any newly
created ones, all reference the same &lt;code&gt;$SSH_AUTH_SOCKET&lt;/code&gt;, and they always work.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SHORT_HOSTNAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n n-Quoted"&gt;`hostname`&lt;/span&gt;
&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;maxdepth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.ssh_auth_sock*&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mtime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;maxdepth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.screen_tab*&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mtime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;?&lt;/span&gt;&lt;span class="n"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n n-Quoted"&gt;`echo $SSH_AUTH_SOCK | grep $SHORT_HOSTNAME | wc -l`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NEW_SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;SUDO_USER&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ssh_auth_sock_$&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;SHORT_HOSTNAME&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ln&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;NEW_SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;$NEW_SSH_AUTH_SOCK&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;endif&lt;/span&gt;
&lt;span class="n"&gt;endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is tcsh code, but bash can do the same thing of course.&lt;/p&gt;</content><category term="Networking"></category><category term="shell"></category><category term="unix"></category><category term="ssh"></category></entry><entry><title>macOS Mail issue with postfix</title><link href="https://www.unixdude.net/posts/2019/May/14/macos-mail-postfix/" rel="alternate"></link><published>2019-05-14T00:00:00-04:00</published><updated>2019-05-14T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2019-05-14:/posts/2019/May/14/macos-mail-postfix/</id><summary type="html">&lt;p&gt;I recently got a new MacBook Pro, and as I was setting up the mail configuration on that laptop,
I found that I was unable to send mail through my mail server.  I use Apple Mail, and usually
it works great for me, but in this case it was not &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2019/May/14/macos-mail-postfix/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently got a new MacBook Pro, and as I was setting up the mail configuration on that laptop,
I found that I was unable to send mail through my mail server.  I use Apple Mail, and usually
it works great for me, but in this case it was not working with my Postfix server.&lt;/p&gt;
&lt;p&gt;I made several attempts at fixing this issue, but I always got the same error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;postfix&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;submission&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;smtpd&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;70940&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;NOQUEUE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RCPT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REDACTED&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;X.X.X.X&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;554&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5.7.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="nv"&gt;@anywhere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Recipient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;rejected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Access&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;denied&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="nv"&gt;@example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="nv"&gt;@anywhere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;proto&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ESMTP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;helo&lt;/span&gt;&lt;span class="o"&gt;=&amp;lt;[&lt;/span&gt;&lt;span class="n"&gt;REDACTED&lt;/span&gt;&lt;span class="o"&gt;]&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After exhausting everything I could think of, and after much troubleshooting, I determined
that all settings were correct: other systems could send mail through my Postfix server,
but I still had the problem with the new laptop.&lt;/p&gt;
&lt;p&gt;At one point I had the idea to disable Apple Mail's SMTP server checkbox that sets the
application to "Automatically manage connection settings," so I did that and I confirmed the
settings that it had been automatically managing -- the port and TLS/SSL setting (587/SSL)
and authentication configuration.&lt;/p&gt;
&lt;p&gt;Once I disabled the automatic option, everything worked correctly.  I didn't actually change any
configuration, and all of the settings were correct, it just doesn't work automatically.&lt;/p&gt;
&lt;p&gt;I post this that others might find it useful, and that I might find it when I set up my
next system.&lt;/p&gt;</content><category term="Mail"></category><category term="email"></category><category term="postfix"></category><category term="macos"></category></entry><entry><title>Scanner</title><link href="https://www.unixdude.net/posts/2019/Feb/20/scanner/" rel="alternate"></link><published>2019-02-20T00:00:00-05:00</published><updated>2019-02-20T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2019-02-20:/posts/2019/Feb/20/scanner/</id><summary type="html">&lt;p&gt;I own a CanoScan LiDE 30.  This scanner is about 15 years old, and back
when I got it new, it was supported on Mac OS X.  Canon stopped updating
the drivers a couple years later, so I switched to &lt;a href="http://www.ellert.se/twain-sane/"&gt;TWAIN-SANE&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When I did that, I wrote a "scan" shell &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2019/Feb/20/scanner/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I own a CanoScan LiDE 30.  This scanner is about 15 years old, and back
when I got it new, it was supported on Mac OS X.  Canon stopped updating
the drivers a couple years later, so I switched to &lt;a href="http://www.ellert.se/twain-sane/"&gt;TWAIN-SANE&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When I did that, I wrote a "scan" shell script that uses scanimage to
grab a TIFF from the scanner, and then mogrify (part of ImageMagick) to
convert the TIFF to JPEG.  My scan script saves scans to an NFS automounted
directory, so it doesn't matter what computer I scan with, I just happened
to do it on my iMac.  Or my MacBook Pro - it didn't matter.&lt;/p&gt;
&lt;p&gt;Unfortunately, Mattias stopped updating his drivers a few years ago, so
I wanted to find another way to use my perfectly good LiDE 30.&lt;/p&gt;
&lt;p&gt;I own a Raspberry Pi 3, and I knew that the TWAIN-SANE drivers that Mattias
used were simply ports of the open source Linux counterparts, so I installed
the SANE and ImageMagick packages on my Raspi and used that for scanning.  I
used the same scan script that I had on the Mac, and with the NFS
automount, everything worked as it had before.&lt;/p&gt;
&lt;p&gt;Until this week, that is, when I relocated my Raspi to my living room to connect it
to my TV.&lt;/p&gt;
&lt;p&gt;Once again, I was looking for a scanning solution.  I can't use my Macs (the only
computers in my office).  My R610 is in my garage, which is not convenient to
scanning.  I don't want to carry my scanner to the living room to connect to the
Raspi, so what can I do?&lt;/p&gt;
&lt;p&gt;The answer is easy: I run a single FreeBSD VM on my Synology DS1618+.  A quick search, and I
discovered sane-backends and sane-fronends are ported to FreeBSD.  The question
remained: Can my Synology connect a USB page scanner to one of its VMs, and will
that work properly?  In mere moments, I had the SANE packages and ImageMagick
installed on the Synology-hosted FreeBSD VM.  And, moments later, I was scanning
successfully using exactly the same script I started with on the iMac a decade ago.&lt;/p&gt;
&lt;p&gt;Ah, the magic of open source and NFS automounts.&lt;/p&gt;
&lt;p&gt;The FreeBSD port has some problems, but it's fine as long as I don't run "scanimage -L" --
that crashes the VM, either a full lockup or a kernel panic and reboot.  But, since
my scanner works with scanimage, that's all I care about.  I just avoid the "-L" parameter,
and all is well.&lt;/p&gt;</content><category term="General"></category><category term="unix"></category><category term="scanner"></category><category term="raspberry pi"></category><category term="nfs"></category><category term="synology"></category></entry><entry><title>Postfix relay configuration</title><link href="https://www.unixdude.net/posts/2019/Feb/14/postfix_relay/" rel="alternate"></link><published>2019-02-14T00:00:00-05:00</published><updated>2019-02-14T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2019-02-14:/posts/2019/Feb/14/postfix_relay/</id><summary type="html">&lt;p&gt;Like most people in my industry, I use multiple email addresses at multiple providers.
Used to be, I could configure all of my email addresses in my mail client and just send
through my mail server and -- voila -- my email would go out as whatever address I
wanted to use &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2019/Feb/14/postfix_relay/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Like most people in my industry, I use multiple email addresses at multiple providers.
Used to be, I could configure all of my email addresses in my mail client and just send
through my mail server and -- voila -- my email would go out as whatever address I
wanted to use.&lt;/p&gt;
&lt;p&gt;Then along came Sender Policy Framework (SPF).  SPF is a great email-related technology
that is designed to protect the integrity of sending domains.  Unfortunately for me, 
adoption of SPF meant that I could no longer send mail through my mail server using one
of my other email addresses.  Specifically, I could no longer send mail through my
server as my gmail.com or mac.com addresses.  I couldn't complain, because my server is
an origination point for gmail.com or mac.com.&lt;/p&gt;
&lt;p&gt;Fortunately, there's a fix for this: &lt;a href="http://www.postfix.org/postconf.5.html#sender_dependent_relayhost_maps" title="Postfix's sender_dependent_relayhost_maps feature"&gt;Postfix's "sender_dependent_relayhost_maps" feature&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The idea: configure all of my devices to send mail through my mail server, and to have
the mail server itself relay as necessary depending on sending address.  My goal: send
mail directly if it originates from my domain; relay gmail mail through smtp.gmail.com,
and relay iCloud mail through smtp.mail.me.com.&lt;/p&gt;
&lt;p&gt;To use that, I defined a few settings in my postfix main.cf file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;smtp_sender_dependent_authentication = yes
sender_dependent_relayhost_maps = hash:/usr/local/etc/postfix/sender_relay
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/usr/local/etc/postfix/sasl_passwd
smtp_tls_note_starttls_offer = yes
smtp_tls_policy_maps = hash:/usr/local/etc/postfix/tls_policy
smtp_tls_security_level = encrypt
smtp_use_tls = yes
smtp_enforce_tls = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_mechanism_filter = plain
smtp_sasl_tls_security_options = noanonymous
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For my server, smtp_sender_dependent_authentication is not strictly necessary, because
I am the only one sending through my mail server.  I include it here because it is
needed for a more general solution.&lt;/p&gt;
&lt;p&gt;The real magic occurs as a result of sender_dependent_relayhost_maps.  This setting
configures the different relays based on sending address.  My sender_relay file looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;gmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;me&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;span class="nx"&gt;submission&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The smtp_sasl_password_maps configuration is also needed because both
Gmail and iCloud require authentication before an email can be relayed through their
servers.  To do this, I have configured application-specific passwords in both systems,
and the sasl_passwd file looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;gmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;gmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;PASSWORD&lt;/span&gt;
&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;PASSWORD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The TLS policy maps are required because the relays require encryption; the tls_policy file's
contents are:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;[smtp.gmail.com]:587 encrypt
[smtp.mail.me.com]:587 encrypt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Of course, you must run postmap on each of these files prior to using them.&lt;/p&gt;
&lt;p&gt;On FreeBSD, which is my OS of choice, things were slightly more complicated than they
otherwise might have been.  I was not able to use the default postfix package, because it is
not compiled with Cyrus SASL client support.  A quick &lt;code&gt;make configure&lt;/code&gt; in
&lt;code&gt;/usr/ports/mail/postfix&lt;/code&gt; allowed me to enable Cyrus SASL client support.  After a
&lt;code&gt;make&lt;/code&gt; and &lt;code&gt;make install&lt;/code&gt; I was ready to test. Many thanks to &lt;a href="https://blog.bradlab.tech/"&gt;Brad&lt;/a&gt; for
helping me test.&lt;/p&gt;
&lt;p&gt;Now I can eliminate all of the extra accounts on all of my devices.&lt;/p&gt;</content><category term="Mail"></category><category term="postfix"></category><category term="spf"></category><category term="email"></category></entry><entry><title>Network upgrade</title><link href="https://www.unixdude.net/posts/2018/Dec/28/network_update/" rel="alternate"></link><published>2018-12-28T00:00:00-05:00</published><updated>2018-12-28T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2018-12-28:/posts/2018/Dec/28/network_update/</id><summary type="html">&lt;p&gt;I have a 3-story house, and my office is on the third floor.  Wifi connectivity in the bonus
room over the garage was terrible, so I brainstormed ideas with coworkers and friends about
how to fix this.  As a temporary measure I ran a long ethernet cable from the office &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2018/Dec/28/network_update/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have a 3-story house, and my office is on the third floor.  Wifi connectivity in the bonus
room over the garage was terrible, so I brainstormed ideas with coworkers and friends about
how to fix this.  As a temporary measure I ran a long ethernet cable from the office to the
bonus room, but this had a very low WAF (wife acceptance factor).&lt;/p&gt;
&lt;p&gt;Another idea was to try a wifi extender off of my AT&amp;amp;T fiber Internet router.  This has
higher WAF, but it didn't really seem to help, so I returned it.&lt;/p&gt;
&lt;p&gt;A coworker and I came up with a neat idea: I have a conduit running between the 3rd-floor attic
space and the garage.  What about running a long ethernet cable through that conduit, then
moving my router down there?  Great idea, but how do I get the Internet signal to the router?&lt;/p&gt;
&lt;p&gt;Another coworker had the solution for that: put a managed switch at both ends of the conduit.
He just happened to have two spare HP ProCurve 1810-24G switches, so I ran an ethernet cable
through the conduit, and voila.&lt;/p&gt;
&lt;p&gt;More specifically: I created a VLAN on the switches for the connection between the Fiber/Ethernet
transceiver to the router.  Then I trunked that VLAN over the conduit-cable.  I also trunked my
"Internal" VLAN over the same cable to get it back up to the office.&lt;/p&gt;
&lt;p&gt;As a bonus, I got to move my noisy R610 to the garage, making my office much quieter.  Storage
is still in the office, but the server is now remote.  It's nice to have iDRAC, now that my server
is remote to me.&lt;/p&gt;
&lt;p&gt;Now I have excellent wifi service on the first floor and bonus room.  So, what about the office
and other parts of the second floor?  I installed my Synology RT1900ac as a wifi access point
in the office; it is now my office switch, and it serves wifi to the parts of the house that
the AT&amp;amp;T router does not reach.&lt;/p&gt;</content><category term="Home lab"></category><category term="synology"></category><category term="r610"></category></entry><entry><title>testssl.sh</title><link href="https://www.unixdude.net/posts/2018/Jul/02/testssl_sh/" rel="alternate"></link><published>2018-07-02T00:00:00-04:00</published><updated>2018-07-02T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2018-07-02:/posts/2018/Jul/02/testssl_sh/</id><summary type="html">&lt;p&gt;Last week, I needed to make some changes to my employer's production website, but
before I made those changes in production, I wanted to test them. Unfortunately
for me, our dev server is unreachable by Qualys, so I had to come up with another
way to test those changes.&lt;/p&gt;
&lt;p&gt;Enter &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2018/Jul/02/testssl_sh/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last week, I needed to make some changes to my employer's production website, but
before I made those changes in production, I wanted to test them. Unfortunately
for me, our dev server is unreachable by Qualys, so I had to come up with another
way to test those changes.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href="http://www.testssl.sh/"&gt;testssl.sh&lt;/a&gt;.  testssl.sh is a shell script that
can be used to do testing very simliar to what Qualys does, from a Unix system.&lt;/p&gt;
&lt;p&gt;To get started, clone the testssl.sh repo:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git clone https://github.com/drwetter/testssl.sh.git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I was able to make and test the changes I needed on our dev system, before going
to production.  I was able to confirm that my changes were correct, in a non-production environment.&lt;/p&gt;
&lt;p&gt;Many thanks to Dirk Wetter for this excellent tool.&lt;/p&gt;
&lt;p&gt;Check it out.&lt;/p&gt;</content><category term="Networking"></category><category term="ssl"></category><category term="shell"></category><category term="unix"></category></entry><entry><title>Lab update</title><link href="https://www.unixdude.net/posts/2018/Jun/28/lab_update/" rel="alternate"></link><published>2018-06-28T00:00:00-04:00</published><updated>2018-06-28T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2018-06-28:/posts/2018/Jun/28/lab_update/</id><summary type="html">&lt;p&gt;As mentioned in &lt;a href="/posts/2017/Dec/03/homelab/"&gt;an earlier post&lt;/a&gt;, my ESXi server has been
running in a VMware Fusion VM on my iMac.  My iMac has 24 GB RAM and 4 logical CPUs; I 
dediated 10 GB RAM and 2 vCPUs to the ESXi VM.&lt;/p&gt;
&lt;p&gt;Last week, I upgraded to a Dell R610 &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2018/Jun/28/lab_update/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;As mentioned in &lt;a href="/posts/2017/Dec/03/homelab/"&gt;an earlier post&lt;/a&gt;, my ESXi server has been
running in a VMware Fusion VM on my iMac.  My iMac has 24 GB RAM and 4 logical CPUs; I 
dediated 10 GB RAM and 2 vCPUs to the ESXi VM.&lt;/p&gt;
&lt;p&gt;Last week, I upgraded to a Dell R610 with 96GB RAM and dual Xeon 3 GHz CPUs (16 vCPUs).
Although ESXi 6.7 is unsupported on the R610, I installed it and so far it is working great.
I am really enjoying the breathing room that so many more CPUs and so much more RAM gives me.
Now I can create VMs pretty much as big as I would ever want.&lt;/p&gt;
&lt;p&gt;I also made two changes to my PXE configuration.&lt;/p&gt;
&lt;p&gt;First, I added a default boot option to the PXE config.  Now, it automatically
starts a CentOS 7 install after 10 seconds, complete with a kickstart file that adds my user and
installs my SSH keys.  Mere minutes after I boot a new VM, it is up and running
CentOS 7 and I can SSH into it.&lt;/p&gt;
&lt;p&gt;Second, I updated my PXE environment to add &lt;a href="http://www.netboot.xyz/"&gt;netboot.xyz&lt;/a&gt;.
Previously I had the ability to install a half-dozen or so OSes via PXE.  Now I can install many more
OSes just as easily.&lt;/p&gt;
&lt;p&gt;My next update will be to add a managed switch, so that I can use link aggregation
for my DS415+ and R610.&lt;/p&gt;</content><category term="Home lab"></category><category term="r610"></category><category term="pxe"></category></entry><entry><title>I love SSH tunnels</title><link href="https://www.unixdude.net/posts/2018/Mar/15/ssh_tunnels/" rel="alternate"></link><published>2018-03-15T00:00:00-04:00</published><updated>2018-03-15T00:00:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2018-03-15:/posts/2018/Mar/15/ssh_tunnels/</id><summary type="html">&lt;p&gt;Everyone who knows me well knows that tunnels in SSH represent one of my all-time-favorite features, ever.  Why?  Simple: They
are so immensely useful.&lt;/p&gt;
&lt;p&gt;Say you are debugging an issue on server, as I am today, and you need a mail server running on that server.  But, that server is &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2018/Mar/15/ssh_tunnels/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Everyone who knows me well knows that tunnels in SSH represent one of my all-time-favorite features, ever.  Why?  Simple: They
are so immensely useful.&lt;/p&gt;
&lt;p&gt;Say you are debugging an issue on server, as I am today, and you need a mail server running on that server.  But, that server is a
production system, and you cannot install a mail server on it.  Want a quick "mail server"?  Use an SSH tunnel:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo ssh -L 25:mail.domain.com:25 daniel@localhost&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will ssh back to localhost as user daniel, but will set up a listener on port 25 that points to mail.domain.com, port 25.&lt;/p&gt;
&lt;p&gt;Voila... a temporary "mail server" on your system, torn down when you no longer need it.&lt;/p&gt;
&lt;p&gt;You can also use tunnels for many other things.  I also use SSH to tunnel VNC, RDP, Synergy, Video Station from my Synology -- and I even use it to access my ESXi console.&lt;/p&gt;
&lt;p&gt;SSH tunnels are easy to implement in an SSH config file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;host demo
hostname demo.example.com
user daniel
ForwardAgent yes
LocalForward 5022 192.168.0.2:22
LocalForward 5947 192.168.0.47:5900
LocalForward 24800 192.168.0.2:24800
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Networking"></category><category term="unix"></category><category term="shell"></category><category term="ssh"></category></entry><entry><title>Home network/home lab</title><link href="https://www.unixdude.net/posts/2017/Dec/03/homelab/" rel="alternate"></link><published>2017-12-03T00:00:00-05:00</published><updated>2017-12-03T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2017-12-03:/posts/2017/Dec/03/homelab/</id><summary type="html">&lt;p&gt;I am frequently asked about my home network/home lab setup.  The summary is that I currently
use a Synology RT1900ac router, and two Synology NAS devices: a DS415+ as primary storage,
and a DS214se as backup.&lt;/p&gt;
&lt;p&gt;For a number of years, I had a first-generation Drobo; later I added &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2017/Dec/03/homelab/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I am frequently asked about my home network/home lab setup.  The summary is that I currently
use a Synology RT1900ac router, and two Synology NAS devices: a DS415+ as primary storage,
and a DS214se as backup.&lt;/p&gt;
&lt;p&gt;For a number of years, I had a first-generation Drobo; later I added a
second generation Drobo S.  I liked those, but I wanted something
beefier and I wanted to switch from DAS to NAS.  I researched the
available options, and since I am a ZFS fan, I considered rolling my own server running FreeNAS.
I settled on Synology, in large part because of the user interface.&lt;/p&gt;
&lt;p&gt;I sold the Drobos and bought a Synology DS415+ NAS, and today I use that
for my main storage.  My DS415+ is configured with 3x WD Red 3TB and 1x WD Red 4TB, in SHR;
this gives about 9TB of usable space.  I have a dozen or so NFS exports from the DS415+, and
three iSCSI LUNs.&lt;/p&gt;
&lt;p&gt;All of my systems, both physical and virtual, are configured for the same user ID, and all Unix
systems use the NFS automounter.  My iMac also mounts the iSCSI LUNs, for things like
iMovie and iPhoto that require block-level storage.&lt;/p&gt;
&lt;p&gt;Due to the size of the backup need, I chose a Synology as a backup device.  Since this is only for
backup, I chose a low-end DS214se; that unit is loaded with 2x WD Red 4TB configured as an 8TB JBOD.&lt;/p&gt;
&lt;p&gt;When I first bought the DS415+, I moved data from my iMac's hard drive over to the NAS, but
that wasn't really fully utilizing it.  I later learned two things that completely changed my world:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First, ESXi can be virtualized inside of VMware Fusion.  This was exciting because I did not have 
money or space for a virtualization lab -- but I did have an iMac with 32GB RAM in it.  I prefer
ESXi to Fusion for virtualization, but to that point had not been running ESXi at home, and was at
that time using Fusion for all of my virtualization needs.&lt;/li&gt;
&lt;li&gt;Second, ESXi can use NFS datastores. Fusion requires block-level storage, so I was excited to learn
that ESXi can use NFS storage.  (At this point, I was very new to ESXi administration.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ever since learning these two things about ESXi, I have run an ESXi server at home.  I started running
ESXi inside a VMware Fusion VM, and today that VM is running ESXi 6.5.0 Update 1. Eventually I would
like to migrate this to an Intel NUC, but for now it runs as a VM in VMware Fusion.  ESXi sees 10GB of RAM
and 2 out of my iMac's 4 CPUs.  I connect to my ESXi server two ways: either via Fusion Pro, or via
ESXi's built-in web client.&lt;/p&gt;
&lt;p&gt;Back to the Synology: The Synology NAS can act as a PXE server, so I have configured pxelinux with a
menu that can boot several Linux distros, ESXi, and other things.  When I want to install an operating
system into a VM, I either use PXE, or I attach an ISO directly to the VM.&lt;/p&gt;
&lt;p&gt;Nearly all of my virtualization has now been moved to ESXi.  I currently have more than 20 unique OSes
installed in VMs in ESX, mostly BSD variants or Linux distros.  In VMware Fusion, I run NeXTSTEP
3.3 and OPENSTEP 4.2; these do not seem to run in ESXi, and are the only OSes I run in Fusion anymore.
Well, other than ESXi itself, that is...&lt;/p&gt;
&lt;p&gt;Once I do buy real hardware for it, the migration will be easy: I will install ESXi on the new
system, point it to the existing NFS exports, add the VMs, and start them up.&lt;/p&gt;</content><category term="Home lab"></category><category term="nas"></category><category term="unix"></category><category term="esxi"></category><category term="synology"></category><category term="iscsi"></category></entry><entry><title>How to build a Pelican contact form</title><link href="https://www.unixdude.net/posts/2017/Nov/29/pelican-contact-form/" rel="alternate"></link><published>2017-11-29T00:00:00-05:00</published><updated>2017-11-29T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2017-11-29:/posts/2017/Nov/29/pelican-contact-form/</id><summary type="html">&lt;p&gt;One of the first things I wanted to configure on this site was a contact form.  I searched and found that &lt;a href="https://iainhouston.com/blog/make-contact-form.html" target="_blank"&gt;Iain Houston documented how he configured one&lt;/a&gt;.  I took his ideas and implemented my own slightly different version.&lt;/p&gt;
&lt;p&gt;Where he used a separate template, I chose to use the &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2017/Nov/29/pelican-contact-form/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;One of the first things I wanted to configure on this site was a contact form.  I searched and found that &lt;a href="https://iainhouston.com/blog/make-contact-form.html" target="_blank"&gt;Iain Houston documented how he configured one&lt;/a&gt;.  I took his ideas and implemented my own slightly different version.&lt;/p&gt;
&lt;p&gt;Where he used a separate template, I chose to use the base template and create a Pelican page for my contact form.&lt;/p&gt;
&lt;p&gt;The contents of my &lt;code&gt;content/pages/contact.md&lt;/code&gt; file are shown here.  This results in a page being created at &lt;code&gt;/pages/contact/index.html&lt;/code&gt;, which I then added to MENUITEMS.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Title:&lt;span class="w"&gt; &lt;/span&gt;Contact&lt;span class="w"&gt; &lt;/span&gt;me
Slug:&lt;span class="w"&gt; &lt;/span&gt;contact

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;col-md-12&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;jumbotron&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Contact&lt;span class="w"&gt; &lt;/span&gt;me&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;I&amp;#39;d&lt;span class="w"&gt; &lt;/span&gt;love&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;hear&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;you.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/php/submit.php&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;form-group col-md-6&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;form-control&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;form-group col-md-6&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;form-control validate email&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Enter email&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;antispam&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;Leave&lt;span class="w"&gt; &lt;/span&gt;this&lt;span class="w"&gt; &lt;/span&gt;empty:
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;br&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;form-group col-md-12&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;form-control&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;rows=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;5&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Message&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;form-group col-md-3 offset-md-3&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;submit&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;btn btn-primary&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;content/php/submit.php&lt;/code&gt; file is similarly simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="vm"&gt;?&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;_POST&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;&amp;#39;url&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;_POST&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;&amp;#39;url&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;was&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;submitted&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;ouremail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your@email.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;Important&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;we&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;any&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;want&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;them&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;included&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;we&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;need&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;them&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;here&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;also&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;This is the form that was just submitted:&lt;/span&gt;
&lt;span class="ss"&gt;    Name:  $_POST[name]&lt;/span&gt;
&lt;span class="ss"&gt;    E-Mail: $_POST[email]&lt;/span&gt;
&lt;span class="ss"&gt;    Message: $_POST[message]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;From&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;submitters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;they&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;supplied&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;isn&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t trying to hack our form).&lt;/span&gt;
&lt;span class="s1"&gt;    // Otherwise send from our email address.&lt;/span&gt;
&lt;span class="s1"&gt;    if( $_POST[&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;] &amp;amp;&amp;amp; !preg_match( &amp;quot;/[\r\n]/&amp;quot;, $_POST[&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;]) ) {&lt;/span&gt;
&lt;span class="s1"&gt;      $headers = &amp;quot;From: $_POST[email]&amp;quot;;&lt;/span&gt;
&lt;span class="s1"&gt;    } else {&lt;/span&gt;
&lt;span class="s1"&gt;      $headers = &amp;quot;From: $ouremail&amp;quot;;&lt;/span&gt;
&lt;span class="s1"&gt;    }&lt;/span&gt;

&lt;span class="s1"&gt;    // finally, send the message&lt;/span&gt;
&lt;span class="s1"&gt;    mail($ouremail, &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Contact&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;submitted&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, $body, $headers );&lt;/span&gt;
&lt;span class="s1"&gt;    header(&amp;#39;&lt;/span&gt;&lt;span class="nl"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;thank&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;you&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="vm"&gt;?&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You will also need a thank-you page.  Here's mine, saved as &lt;code&gt;content/pages/thankyou.md&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thank&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;contacting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;
&lt;span class="n"&gt;slug&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thank&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;you&lt;/span&gt;

&lt;span class="n"&gt;Your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;been&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Iain's script implements simple spam control.  To use it properly, you need to add some custom CSS so that the antispam field is hidden from view:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="na"&gt;.antispam&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="no"&gt;none&lt;/span&gt;&lt;span class="c1"&gt;;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Website"></category><category term="pelican"></category><category term="php"></category></entry><entry><title>Sharing Unix shell config between systems</title><link href="https://www.unixdude.net/posts/2017/Nov/11/sharing-unix-shell-config-between-systems/" rel="alternate"></link><published>2017-11-11T00:00:00-05:00</published><updated>2017-11-11T00:00:00-05:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2017-11-11:/posts/2017/Nov/11/sharing-unix-shell-config-between-systems/</id><summary type="html">&lt;p&gt;Like most people who work on Unix, I have shell accounts on hundreds of systems.  Very few
of these systems share a home directory (e.g., via NFS), so I need another way to maintain
a common shell configuration between systems.&lt;/p&gt;
&lt;p&gt;Based on the design of a former coworker, I &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2017/Nov/11/sharing-unix-shell-config-between-systems/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Like most people who work on Unix, I have shell accounts on hundreds of systems.  Very few
of these systems share a home directory (e.g., via NFS), so I need another way to maintain
a common shell configuration between systems.&lt;/p&gt;
&lt;p&gt;Based on the design of a former coworker, I have built such a system using git, symlinks, and
scripts.&lt;/p&gt;
&lt;p&gt;I use four git repos for my Unix account configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a "bin" directory for home&lt;/li&gt;
&lt;li&gt;a "bin" directory for work&lt;/li&gt;
&lt;li&gt;a "bin" directory for everywhere&lt;/li&gt;
&lt;li&gt;an environment directory&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of those directories are private git repos, stored on Bitbucket.  I will
eventually host my own git repo, but for now I use Atlassian's excellent
service.&lt;/p&gt;
&lt;p&gt;Of the four repos listed above, the "home" bin directory exists only on personal systems,
the "work" directory exists only on employer systems, and the "everywhere" directory is
shared on all systems.&lt;/p&gt;
&lt;p&gt;The environment directory includes such things as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tcsh config&lt;/li&gt;
&lt;li&gt;bash config (for systems on which tcsh is not available)&lt;/li&gt;
&lt;li&gt;ssh config&lt;/li&gt;
&lt;li&gt;screenrc&lt;/li&gt;
&lt;li&gt;vimrc&lt;/li&gt;
&lt;li&gt;a script to configure my environment on a new host&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I use three additional scripts in conjunction with the repos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;one to inform me when a sync is required&lt;/li&gt;
&lt;li&gt;one to perform the git sync&lt;/li&gt;
&lt;li&gt;one to copy an existing config to a new host (such as one that does not have git installed)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Obviously I can run "git push" and "git pull" manually, but since there are four
repos here, it was easier to script it.&lt;/p&gt;
&lt;p&gt;My "update_repos.sh" script looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Update my_env&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/.my_env
git&lt;span class="w"&gt; &lt;/span&gt;pull
git&lt;span class="w"&gt; &lt;/span&gt;push

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;~/bina&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Update bina&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/bina
&lt;span class="w"&gt;    &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;pull
&lt;span class="w"&gt;    &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;push
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;~/binh&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Update binh&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/binh
&lt;span class="w"&gt;    &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;pull
&lt;span class="w"&gt;    &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;push
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;~/binw&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Update binw&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/binw
&lt;span class="w"&gt;    &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;pull
&lt;span class="w"&gt;    &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;push
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I use symlinks from main files, into my environment directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;.bash_profile@&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;.my_env/tcsh/bash_profile
.bashrc@&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;.my_env/tcsh/bashrc
.cshrc@&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;.my_env/tcsh/cshrc
.login@&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;.my_env/tcsh/login
.logout@&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;.my_env/tcsh/logout
.ssh@&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;.my_env/ssh
.vimrc@&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;.my_env/vimrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To bootstrap a host, I check out the applicable repos on the host, then run my setup script, which looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
ln&lt;span class="w"&gt; &lt;/span&gt;-sf&lt;span class="w"&gt; &lt;/span&gt;.my_env/tcsh/bashrc&lt;span class="w"&gt;     &lt;/span&gt;~/.bashrc
ln&lt;span class="w"&gt; &lt;/span&gt;-sf&lt;span class="w"&gt; &lt;/span&gt;.my_env/tcsh/cshrc&lt;span class="w"&gt;      &lt;/span&gt;~/.cshrc
ln&lt;span class="w"&gt; &lt;/span&gt;-sf&lt;span class="w"&gt; &lt;/span&gt;.my_env/tcsh/login&lt;span class="w"&gt;      &lt;/span&gt;~/.login
ln&lt;span class="w"&gt; &lt;/span&gt;-sf&lt;span class="w"&gt; &lt;/span&gt;.my_env/tcsh/logout&lt;span class="w"&gt;     &lt;/span&gt;~/.logout
ln&lt;span class="w"&gt; &lt;/span&gt;-sf&lt;span class="w"&gt; &lt;/span&gt;.my_env/vimrc&lt;span class="w"&gt;           &lt;/span&gt;~/.vimrc
ln&lt;span class="w"&gt; &lt;/span&gt;-sf&lt;span class="w"&gt; &lt;/span&gt;.my_env/screenrc&lt;span class="w"&gt;        &lt;/span&gt;~/.screenrc
rm&lt;span class="w"&gt; &lt;/span&gt;~/.ssh
ln&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt;  &lt;/span&gt;.my_env/ssh&lt;span class="w"&gt;             &lt;/span&gt;~/.ssh
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/auto/downloads/Set up new host/ssh_config/id_rsa&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/auto/downloads/Set up new host/ssh_config/id_rsa&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/.ssh
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Two comments about this script:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;~/.ssh is not removed if it is a directory.  This does complicate matters on systems that already have a ~/.ssh
directory.  In those cases I blow away ~/.ssh and rebuild it as a link.&lt;/li&gt;
&lt;li&gt;/auto is where my NFS automounter lives.  /auto/downloads is on my NAS and in keeping with best-practices
my private key only exists on appropriate systems.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Comment below if you have any questions or comments about this setup.&lt;/p&gt;</content><category term="Unix"></category><category term="shell"></category><category term="git"></category></entry><entry><title>Welcome</title><link href="https://www.unixdude.net/posts/2017/Oct/26/welcome/" rel="alternate"></link><published>2017-10-26T10:21:00-04:00</published><updated>2017-10-26T10:21:00-04:00</updated><author><name>Daniel</name></author><id>tag:www.unixdude.net,2017-10-26:/posts/2017/Oct/26/welcome/</id><summary type="html">&lt;p&gt;A while ago, a friend suggested that I should start a blog.  Around that
same time, a coworker introduced me to DigitalOcean.  I quickly set up a
VM at DigitalOcean (that VM is serving this web page), and installed
FreeBSD 11.&lt;/p&gt;
&lt;p&gt;I looked at WordPress and other popular blogging tools &amp;#8230;&lt;a class="label label-primary read-more" href="/posts/2017/Oct/26/welcome/"&gt;&lt;span&gt;Continue reading&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;A while ago, a friend suggested that I should start a blog.  Around that
same time, a coworker introduced me to DigitalOcean.  I quickly set up a
VM at DigitalOcean (that VM is serving this web page), and installed
FreeBSD 11.&lt;/p&gt;
&lt;p&gt;I looked at WordPress and other popular blogging tools, but all were
overkill for what I want to do, and all would overtax the small VM I am
running.  I finally settled on Pelican, after a coworker showed me &lt;a href="http://blog.bradlab.tech/" target="_blank"&gt;his blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I played around with all of the Pelican themes, and wanted one that
would look good on all screen sizes, so it had to be a
&lt;a href="http://www.getbootstrap.com" target="_blank"&gt;Bootstrap&lt;/a&gt; derivative.&lt;/p&gt;
&lt;p&gt;I use a second FreeBSD system for the development version of this blog.
That system is a VM running on my ESXi server.  I develop and deploy
there, then I deploy the production version here via rsync.&lt;/p&gt;
&lt;p&gt;I won't get into the details of everything this VM does,
but it functions as a:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mail server, running Postfix + Dovecot + SpamAssassin + Sieve + Roundcube&lt;/li&gt;
&lt;li&gt;Web server, running Apache serving a dozen or so virtual hosts, all of which use &lt;a href="https://www.letsencrypt.org/" target="_blank"&gt;Let's Encrypt certificates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Website"></category></entry></feed>