<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Home on apalrd&#39;s adventures</title>
    <link>https://www.apalrd.net/</link>
    <description>Recent content in Home on apalrd&#39;s adventures</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <copyright>© 2023 apalrd</copyright>
    <lastBuildDate>Fri, 15 May 2026 01:00:05 -0300</lastBuildDate><atom:link href="https://www.apalrd.net/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Starting my Content Delivery Network</title>
      <link>https://www.apalrd.net/posts/2026/asn_cdn/</link>
      <pubDate>Fri, 15 May 2026 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2026/asn_cdn/</guid>
      <description>Today I&amp;rsquo;m finally starting to put my AS Number to use, rolling out my Content Delivery Network! Currently it&amp;rsquo;s actually not delivering anything useful, just some neat statistics, but it&amp;rsquo;s helping me learn how CDNs work and share that with all of you.
Here&amp;rsquo;s a neat visualizer which helps show how users end up at the CDN, when directed via DNS (geo-dns) and BGP (anycast).
AI disclaimer: The DNS server (github link) and my-ip page (link) were written without the use of any AI tools.</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m finally starting to put my AS Number to use, rolling out my Content Delivery Network! Currently it&amp;rsquo;s actually not delivering anything useful, just some neat statistics, but it&amp;rsquo;s helping me learn how CDNs work and share that with all of you.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a neat visualizer which helps show how users end up at the CDN, when directed via DNS (geo-dns) and BGP (anycast).&lt;/p&gt;
&lt;p&gt;AI disclaimer: The DNS server &lt;a href=&#34;https://github.com/apalrd/dnsprint&#34;&gt;(github link)&lt;/a&gt; and my-ip page &lt;a href=&#34;https://www.apalrd.net/myip/&#34;&gt;(link)&lt;/a&gt; were written without the use of any AI tools. The visualization on this page was made using Claude AI, since I am not that good at Javascript.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/LCJIQufZeeg&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2026/asn_cdn/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;style&gt;
    /* ── layout ── */
    .dashboard { max-width: 1400px; margin: 0 auto; padding: 2rem; }

    /* ── hero stats ── */
    .stats-row {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 2rem;
      margin-bottom: 1rem;
    }
    .stat-card {
      padding: 2.5rem 2rem 1.75rem;
      border-radius: 4px;
      text-align: center;
      position: relative;
      overflow: hidden;
    }
    .stat-card .stat-label {
      font-size: 0.75rem;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      opacity: 0.65;
      margin-bottom: 0.5rem;
    }
    .stat-card .stat-value {
      font-size: clamp(3rem, 7vw, 5.5rem);
      font-weight: 700;
      line-height: 1;
      letter-spacing: -0.02em;
    }
    .stat-card .stat-unit {
      font-size: 1.1rem;
      font-weight: 400;
      opacity: 0.5;
      margin-left: 0.25rem;
    }

    /* ── meta stats row ── */
    .meta-row {
      display: grid;
      grid-template-columns: repeat(5, 1fr);
      gap: 1rem;
      margin-bottom: 3rem;
    }
    .meta-card {
      padding: 0.9rem 1rem;
      border-radius: 4px;
      text-align: center;
      border: 1px solid rgba(128,128,128,0.15);
    }
    .meta-card .meta-value {
      font-size: 1.65rem;
      font-weight: 700;
      letter-spacing: -0.02em;
      line-height: 1.1;
    }
    .meta-card .meta-label {
      margin-top: 0.25rem;
      font-size: 0.68rem;
      letter-spacing: 0.14em;
      text-transform: uppercase;
      opacity: 0.45;
    }

    /* ── section titles ── */
    .section-title {
      font-size: 0.72rem;
      letter-spacing: 0.2em;
      text-transform: uppercase;
      opacity: 0.4;
      margin: 0 0 1rem 0;
      padding-bottom: 0.5rem;
      border-bottom: 1px solid rgba(128,128,128,0.2);
    }
    .section { margin-bottom: 3rem; }

    /* ── chart controls ── */
    .chart-controls {
      display: flex;
      gap: 1.25rem;
      margin-bottom: 1rem;
      align-items: center;
      flex-wrap: wrap;
    }
    .chart-controls label {
      font-size: 0.75rem;
      opacity: 0.6;
      display: flex;
      align-items: center;
      gap: 0.4rem;
    }
    .chart-controls select {
      padding: 0.28rem 0.55rem;
      border-radius: 3px;
      border: 1px solid rgba(128,128,128,0.25);
      background: transparent;
      font-size: 0.8rem;
      color: inherit;
      cursor: pointer;
    }
    .controls-right { margin-left: auto; }

    /* ── bar charts ── */
    .bar-chart { display: flex; flex-direction: column; gap: 0.6rem; }

    /* dual bar row (latency chart) */
    .dual-bar-row {
      display: grid;
      grid-template-columns: 16ch 1fr;
      gap: 0.75rem;
      align-items: center;
      font-size: 0.82rem;
    }
    .dual-bar-row .bar-label { text-align: right; opacity: 0.7; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .dual-tracks { display: flex; flex-direction: column; gap: 3px; cursor: default; }
    .dual-tracks .bar-track { height: 14px; }

    /* single bar row (diff chart) */
    .bar-row {
      display: grid;
      grid-template-columns: 16ch 1fr 7ch;
      gap: 0.75rem;
      align-items: center;
      font-size: 0.82rem;
    }
    .bar-row .bar-label { text-align: right; opacity: 0.7; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

    .bar-track {
      height: 22px;
      border-radius: 2px;
      overflow: hidden;
      background: rgba(128,128,128,0.12);
      position: relative;
      cursor: default;
    }
    .bar-fill {
      height: 100%;
      border-radius: 2px;
      transition: width 0.55s cubic-bezier(0.4,0,0.2,1);
    }
    .bar-fill.dns      { background: #3b82f6; }
    .bar-fill.bgp      { background: #f59e0b; }
    .bar-fill.diff-pos { background: #10b981; }
    .bar-fill.diff-neg { background: #ef4444; }
    .bar-val { opacity: 0.7; font-variant-numeric: tabular-nums; font-size: 0.78rem; }
    .diff-pos-text { color: #10b981; }
    .diff-neg-text { color: #ef4444; }

    /* ── legend ── */
    .legend { display: flex; gap: 1.5rem; font-size: 0.78rem; align-items: center; }
    .legend-dot { width: 10px; height: 10px; border-radius: 2px; display: inline-block; margin-right: 0.35em; }

    /* ── loading / error ── */
    .state-msg { padding: 2rem; text-align: center; opacity: 0.45; font-size: 0.85rem; letter-spacing: 0.05em; }
    .error-msg { color: #ef4444; opacity: 1; }

    /* ── tooltip ── */
    #tt {
      position: fixed;
      z-index: 9999;
      pointer-events: none;
      display: none;
      background: rgba(12,12,16,0.95);
      border: 1px solid rgba(255,255,255,0.1);
      border-radius: 5px;
      padding: 0.65rem 0.9rem;
      font-size: 0.76rem;
      line-height: 1.5;
      min-width: 240px;
      box-shadow: 0 6px 24px rgba(0,0,0,0.5);
      color: #eaeaea;
    }
    #tt .tt-title {
      font-weight: 700;
      font-size: 0.83rem;
      margin-bottom: 0.45rem;
      white-space: nowrap;
      opacity: 0.95;
    }
    /* section label, e.g. &#34;DNS&#34; / &#34;BGP&#34; / &#34;Difference&#34; */
    #tt .tt-section {
      font-size: 0.68rem;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      opacity: 0.4;
      margin-top: 0.45rem;
      margin-bottom: 0.15rem;
    }
    /* 4-column stat grid: label | min | mean | median | max */
    #tt .tt-grid {
      display: grid;
      grid-template-columns: 3.5ch 1fr 1fr 1fr 1fr;
      gap: 0 0.5rem;
      font-variant-numeric: tabular-nums;
    }
    #tt .tt-grid .hdr {
      font-size: 0.65rem;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      opacity: 0.38;
      text-align: right;
    }
    #tt .tt-grid .lbl { opacity: 0.5; }
    #tt .tt-grid .val { text-align: right; font-weight: 500; }
    #tt .tt-verdict {
      margin-top: 0.45rem;
      padding-top: 0.35rem;
      border-top: 1px solid rgba(255,255,255,0.08);
      font-size: 0.75rem;
      font-weight: 600;
    }
    #tt .c-dns { color: #3b82f6; }
    #tt .c-bgp { color: #f59e0b; }
    #tt .c-pos { color: #10b981; }
    #tt .c-neg { color: #ef4444; }
    #tt .c-gen { color: #eaeaea; }
  &lt;/style&gt;
&lt;div id=&#34;tt&#34;&gt;&lt;/div&gt;
&lt;div class=&#34;dashboard&#34;&gt;
  &lt;!-- ── Hero Stats ── --&gt;
  &lt;div class=&#34;stats-row&#34;&gt;
    &lt;div class=&#34;stat-card&#34;&gt;
      &lt;div class=&#34;stat-label&#34;&gt;Med DNS Latency&lt;/div&gt;
      &lt;div class=&#34;stat-value&#34; id=&#34;med-dns&#34;&gt;—&lt;span class=&#34;stat-unit&#34;&gt;ms&lt;/span&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&#34;stat-card&#34;&gt;
      &lt;div class=&#34;stat-label&#34;&gt;Med BGP Latency&lt;/div&gt;
      &lt;div class=&#34;stat-value&#34; id=&#34;med-bgp&#34;&gt;—&lt;span class=&#34;stat-unit&#34;&gt;ms&lt;/span&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;!-- ── Meta Stats ── --&gt;
  &lt;div class=&#34;meta-row&#34;&gt;
    &lt;div class=&#34;meta-card&#34;&gt;
      &lt;div class=&#34;meta-value&#34; id=&#34;meta-records&#34;&gt;—&lt;/div&gt;
      &lt;div class=&#34;meta-label&#34;&gt;Total Records&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&#34;meta-card&#34;&gt;
      &lt;div class=&#34;meta-value&#34; id=&#34;meta-countries&#34;&gt;—&lt;/div&gt;
      &lt;div class=&#34;meta-label&#34;&gt;Countries&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&#34;meta-card&#34;&gt;
      &lt;div class=&#34;meta-value&#34; id=&#34;meta-ases&#34;&gt;—&lt;/div&gt;
      &lt;div class=&#34;meta-label&#34;&gt;Autonomous Systems&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&#34;meta-card&#34;&gt;
      &lt;div class=&#34;meta-value&#34; id=&#34;meta-non-isp&#34;&gt;—&lt;/div&gt;
      &lt;div class=&#34;meta-label&#34;&gt;Non-ISP Resolver&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&#34;meta-card&#34;&gt;
      &lt;div class=&#34;meta-value&#34; id=&#34;meta-ecs&#34;&gt;—&lt;/div&gt;
      &lt;div class=&#34;meta-label&#34;&gt;ECS Supported&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;!-- ── Latency Chart ── --&gt;
  &lt;div class=&#34;section&#34;&gt;
    &lt;h2 class=&#34;section-title&#34;&gt;Latency (median)&lt;/h2&gt;
    &lt;div class=&#34;chart-controls&#34;&gt;
      &lt;label&gt;Group by
        &lt;select id=&#34;latency-group&#34;&gt;
          &lt;option value=&#34;country&#34;&gt;Country&lt;/option&gt;
          &lt;option value=&#34;asn&#34;&gt;ASN&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;
      &lt;label&gt;Continent
        &lt;select id=&#34;latency-continent&#34;&gt;&lt;option value=&#34;&#34;&gt;All&lt;/option&gt;&lt;/select&gt;
      &lt;/label&gt;
      &lt;label id=&#34;latency-count&#34;&gt;-&lt;/label&gt;
      &lt;div class=&#34;controls-right legend&#34;&gt;
        &lt;span&gt;&lt;span class=&#34;legend-dot&#34; style=&#34;background:#3b82f6&#34;&gt;&lt;/span&gt;DNS&lt;/span&gt;
        &lt;span&gt;&lt;span class=&#34;legend-dot&#34; style=&#34;background:#f59e0b&#34;&gt;&lt;/span&gt;BGP&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div id=&#34;latency-chart&#34; class=&#34;bar-chart&#34;&gt;&lt;div class=&#34;state-msg&#34;&gt;Loading…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;!-- ── Difference Chart ── --&gt;
  &lt;div class=&#34;section&#34;&gt;
    &lt;h2 class=&#34;section-title&#34;&gt;BGP − DNS Difference (Median)&lt;/h2&gt;
    &lt;div class=&#34;chart-controls&#34;&gt;
      &lt;label&gt;Group by
        &lt;select id=&#34;diff-group&#34;&gt;
          &lt;option value=&#34;country&#34;&gt;Country&lt;/option&gt;
          &lt;option value=&#34;asn&#34;&gt;ASN&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;
      &lt;label&gt;Continent
        &lt;select id=&#34;diff-continent&#34;&gt;&lt;option value=&#34;&#34;&gt;All&lt;/option&gt;&lt;/select&gt;
      &lt;/label&gt;
      &lt;label id=&#34;diff-count&#34;&gt;-&lt;/label&gt;
      &lt;div class=&#34;controls-right legend&#34;&gt;
        &lt;span&gt;&lt;span class=&#34;legend-dot&#34; style=&#34;background:#ef4444&#34;&gt;&lt;/span&gt;BGP faster&lt;/span&gt;
        &lt;span&gt;&lt;span class=&#34;legend-dot&#34; style=&#34;background:#10b981&#34;&gt;&lt;/span&gt;DNS faster&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div id=&#34;diff-chart&#34; class=&#34;bar-chart&#34;&gt;&lt;div class=&#34;state-msg&#34;&gt;Loading…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
// ── Config ────────────────────────────────────────────────────────────────────
const CSV_URL = &#39;data.csv&#39;; // ← update to your endpoint
const ASN_URL = &#39;asn.csv&#39;;

// ── Column indices (0-based, no header row) ───────────────────────────────────
const COL = {
  continent: 0, country: 1, asn: 2, dnsRule: 3,
  dnsCont: 4, dnsCountry: 5, dnsAsn: 6, dnsEcs: 7,
  dnsHost: 8, dnsLatency: 9,
  bgpHost: 10, bgpLatency: 11
};

// ── Country code → display name ───────────────────────────────────────────────
// Add entries here; codes not listed fall back to showing the raw code.
const COUNTRY_NAMES = {
AF: &#34;Afghanistan&#34;,
AX: &#34;Åland Islands&#34;,
AL: &#34;Albania&#34;,
DZ: &#34;Algeria&#34;,
AS: &#34;American Samoa&#34;,
AD: &#34;Andorra&#34;,
AO: &#34;Angola&#34;,
AI: &#34;Anguilla&#34;,
AQ: &#34;Antarctica&#34;,
AG: &#34;Antigua and Barbuda&#34;,
AR: &#34;Argentina&#34;,
AM: &#34;Armenia&#34;,
AW: &#34;Aruba&#34;,
AU: &#34;Australia&#34;,
AT: &#34;Austria&#34;,
AZ: &#34;Azerbaijan&#34;,
BS: &#34;Bahamas&#34;,
BH: &#34;Bahrain&#34;,
BD: &#34;Bangladesh&#34;,
BB: &#34;Barbados&#34;,
BY: &#34;Belarus&#34;,
BE: &#34;Belgium&#34;,
BZ: &#34;Belize&#34;,
BJ: &#34;Benin&#34;,
BM: &#34;Bermuda&#34;,
BT: &#34;Bhutan&#34;,
BO: &#34;Bolivia, Plurinational State of&#34;,
BQ: &#34;Bonaire, Sint Eustatius and Saba&#34;,
BA: &#34;Bosnia and Herzegovina&#34;,
BW: &#34;Botswana&#34;,
BV: &#34;Bouvet Island&#34;,
BR: &#34;Brazil&#34;,
IO: &#34;British Indian Ocean Territory&#34;,
BN: &#34;Brunei Darussalam&#34;,
BG: &#34;Bulgaria&#34;,
BF: &#34;Burkina Faso&#34;,
BI: &#34;Burundi&#34;,
CV: &#34;Cabo Verde&#34;,
KH: &#34;Cambodia&#34;,
CM: &#34;Cameroon&#34;,
CA: &#34;Canada&#34;,
KY: &#34;Cayman Islands&#34;,
CF: &#34;Central African Republic&#34;,
TD: &#34;Chad&#34;,
CL: &#34;Chile&#34;,
CN: &#34;China&#34;,
CX: &#34;Christmas Island&#34;,
CC: &#34;Cocos (Keeling) Islands&#34;,
CO: &#34;Colombia&#34;,
KM: &#34;Comoros&#34;,
CG: &#34;Congo&#34;,
CD: &#34;Congo, Democratic Republic of the&#34;,
CK: &#34;Cook Islands&#34;,
CR: &#34;Costa Rica&#34;,
CI: &#34;Côte d`Ivoire&#34;,
HR: &#34;Croatia&#34;,
CU: &#34;Cuba&#34;,
CW: &#34;Curaçao&#34;,
CY: &#34;Cyprus&#34;,
CZ: &#34;Czechia&#34;,
DK: &#34;Denmark&#34;,
DJ: &#34;Djibouti&#34;,
DM: &#34;Dominica&#34;,
DO: &#34;Dominican Republic&#34;,
EC: &#34;Ecuador&#34;,
EG: &#34;Egypt&#34;,
SV: &#34;El Salvador&#34;,
GQ: &#34;Equatorial Guinea&#34;,
ER: &#34;Eritrea&#34;,
EE: &#34;Estonia&#34;,
SZ: &#34;Eswatini&#34;,
ET: &#34;Ethiopia&#34;,
FK: &#34;Falkland Islands (Malvinas)&#34;,
FO: &#34;Faroe Islands&#34;,
FJ: &#34;Fiji&#34;,
FI: &#34;Finland&#34;,
FR: &#34;France&#34;,
GF: &#34;French Guiana&#34;,
PF: &#34;French Polynesia&#34;,
TF: &#34;French Southern Territories&#34;,
GA: &#34;Gabon&#34;,
GM: &#34;Gambia&#34;,
GE: &#34;Georgia&#34;,
DE: &#34;Germany&#34;,
GH: &#34;Ghana&#34;,
GI: &#34;Gibraltar&#34;,
GR: &#34;Greece&#34;,
GL: &#34;Greenland&#34;,
GD: &#34;Grenada&#34;,
GP: &#34;Guadeloupe&#34;,
GU: &#34;Guam&#34;,
GT: &#34;Guatemala&#34;,
GG: &#34;Guernsey&#34;,
GN: &#34;Guinea&#34;,
GW: &#34;Guinea-Bissau&#34;,
GY: &#34;Guyana&#34;,
HT: &#34;Haiti&#34;,
HM: &#34;Heard Island and McDonald Islands&#34;,
VA: &#34;Holy See&#34;,
HN: &#34;Honduras&#34;,
HK: &#34;Hong Kong&#34;,
HU: &#34;Hungary&#34;,
IS: &#34;Iceland&#34;,
IN: &#34;India&#34;,
ID: &#34;Indonesia&#34;,
IR: &#34;Iran, Islamic Republic of&#34;,
IQ: &#34;Iraq&#34;,
IE: &#34;Ireland&#34;,
IM: &#34;Isle of Man&#34;,
IL: &#34;Israel&#34;,
IT: &#34;Italy&#34;,
JM: &#34;Jamaica&#34;,
JP: &#34;Japan&#34;,
JE: &#34;Jersey&#34;,
JO: &#34;Jordan&#34;,
KZ: &#34;Kazakhstan&#34;,
KE: &#34;Kenya&#34;,
KI: &#34;Kiribati&#34;,
KP: &#34;Korea, Democratic People&#39;s Republic of&#34;,
KR: &#34;Korea, Republic of&#34;,
KW: &#34;Kuwait&#34;,
KG: &#34;Kyrgyzstan&#34;,
LA: &#34;Lao People&#39;s Democratic Republic&#34;,
LV: &#34;Latvia&#34;,
LB: &#34;Lebanon&#34;,
LS: &#34;Lesotho&#34;,
LR: &#34;Liberia&#34;,
LY: &#34;Libya&#34;,
LI: &#34;Liechtenstein&#34;,
LT: &#34;Lithuania&#34;,
LU: &#34;Luxembourg&#34;,
MO: &#34;Macao&#34;,
MG: &#34;Madagascar&#34;,
MW: &#34;Malawi&#34;,
MY: &#34;Malaysia&#34;,
MV: &#34;Maldives&#34;,
ML: &#34;Mali&#34;,
MT: &#34;Malta&#34;,
MH: &#34;Marshall Islands&#34;,
MQ: &#34;Martinique&#34;,
MR: &#34;Mauritania&#34;,
MU: &#34;Mauritius&#34;,
YT: &#34;Mayotte&#34;,
MX: &#34;Mexico&#34;,
FM: &#34;Micronesia, Federated States of&#34;,
MD: &#34;Moldova, Republic of&#34;,
MC: &#34;Monaco&#34;,
MN: &#34;Mongolia&#34;,
ME: &#34;Montenegro&#34;,
MS: &#34;Montserrat&#34;,
MA: &#34;Morocco&#34;,
MZ: &#34;Mozambique&#34;,
MM: &#34;Myanmar&#34;,
NA: &#34;Namibia&#34;,
NR: &#34;Nauru&#34;,
NP: &#34;Nepal&#34;,
NL: &#34;Netherlands&#34;,
NC: &#34;New Caledonia&#34;,
NZ: &#34;New Zealand&#34;,
NI: &#34;Nicaragua&#34;,
NE: &#34;Niger&#34;,
NG: &#34;Nigeria&#34;,
NU: &#34;Niue&#34;,
NF: &#34;Norfolk Island&#34;,
MK: &#34;North Macedonia&#34;,
MP: &#34;Northern Mariana Islands&#34;,
NO: &#34;Norway&#34;,
OM: &#34;Oman&#34;,
PK: &#34;Pakistan&#34;,
PW: &#34;Palau&#34;,
PS: &#34;Palestine, State of&#34;,
PA: &#34;Panama&#34;,
PG: &#34;Papua New Guinea&#34;,
PY: &#34;Paraguay&#34;,
PE: &#34;Peru&#34;,
PH: &#34;Philippines&#34;,
PN: &#34;Pitcairn&#34;,
PL: &#34;Poland&#34;,
PT: &#34;Portugal&#34;,
PR: &#34;Puerto Rico&#34;,
QA: &#34;Qatar&#34;,
RE: &#34;Réunion&#34;,
RO: &#34;Romania&#34;,
RU: &#34;Russian Federation&#34;,
RW: &#34;Rwanda&#34;,
BL: &#34;Saint Barthélemy&#34;,
SH: &#34;Saint Helena, Ascension and Tristan da Cunha&#34;,
KN: &#34;Saint Kitts and Nevis&#34;,
LC: &#34;Saint Lucia&#34;,
MF: &#34;Saint Martin (French part)&#34;,
PM: &#34;Saint Pierre and Miquelon&#34;,
VC: &#34;Saint Vincent and the Grenadines&#34;,
WS: &#34;Samoa&#34;,
SM: &#34;San Marino&#34;,
ST: &#34;Sao Tome and Principe&#34;,
SA: &#34;Saudi Arabia&#34;,
SN: &#34;Senegal&#34;,
RS: &#34;Serbia&#34;,
SC: &#34;Seychelles&#34;,
SL: &#34;Sierra Leone&#34;,
SG: &#34;Singapore&#34;,
SX: &#34;Sint Maarten (Dutch part)&#34;,
SK: &#34;Slovakia&#34;,
SI: &#34;Slovenia&#34;,
SB: &#34;Solomon Islands&#34;,
SO: &#34;Somalia&#34;,
ZA: &#34;South Africa&#34;,
GS: &#34;South Georgia and the South Sandwich Islands&#34;,
SS: &#34;South Sudan&#34;,
ES: &#34;Spain&#34;,
LK: &#34;Sri Lanka&#34;,
SD: &#34;Sudan&#34;,
SR: &#34;Suriname&#34;,
SJ: &#34;Svalbard and Jan Mayen&#34;,
SE: &#34;Sweden&#34;,
CH: &#34;Switzerland&#34;,
SY: &#34;Syrian Arab Republic&#34;,
TW: &#34;Taiwan, Province of China&#34;,
TJ: &#34;Tajikistan&#34;,
TZ: &#34;Tanzania, United Republic of&#34;,
TH: &#34;Thailand&#34;,
TL: &#34;Timor-Leste&#34;,
TG: &#34;Togo&#34;,
TK: &#34;Tokelau&#34;,
TO: &#34;Tonga&#34;,
TT: &#34;Trinidad and Tobago&#34;,
TN: &#34;Tunisia&#34;,
TR: &#34;Türkiye&#34;,
TM: &#34;Turkmenistan&#34;,
TC: &#34;Turks and Caicos Islands&#34;,
TV: &#34;Tuvalu&#34;,
UG: &#34;Uganda&#34;,
UA: &#34;Ukraine&#34;,
AE: &#34;United Arab Emirates&#34;,
GB: &#34;United Kingdom of Great Britain and Northern Ireland&#34;,
US: &#34;United States of America&#34;,
UM: &#34;United States Minor Outlying Islands&#34;,
UY: &#34;Uruguay&#34;,
UZ: &#34;Uzbekistan&#34;,
VU: &#34;Vanuatu&#34;,
VE: &#34;Venezuela, Bolivarian Republic of&#34;,
VN: &#34;Viet Nam&#34;,
VG: &#34;Virgin Islands (British)&#34;,
VI: &#34;Virgin Islands (U.S.)&#34;,
WF: &#34;Wallis and Futuna&#34;,
EH: &#34;Western Sahara&#34;,
YE: &#34;Yemen&#34;,
ZM: &#34;Z,ambia&#34;,
ZW: &#34;Zimbabwe&#34;,
};
function countryName(code) { return COUNTRY_NAMES[code] || code; }

function asnName(asn) {
    if (!(asn in allASNs)) {
        return &#39;AS&#39;+asn+&#39; [UNK]&lt;br&gt;Not in database&#39;;
    }
    return &#39;AS&#39;+asn+&#39; [&#39;+(allASNs[asn].CCode)+&#39;]&lt;br&gt;&#39;+(allASNs[asn].Name); }

// ── State ─────────────────────────────────────────────────────────────────────
let allRows = [];
let allASNs = {};

// Fetch &amp; parse ASN data
async function loadASNs() {
    try {
    const res = await fetch(ASN_URL);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const text = await res.text();
    const lines = text.trim().split(&#39;\n&#39;).filter(l =&gt; l.trim());
    for (const line of lines) {
        const cols = parseCSVLine(line);
        //strip &#39;AS&#39; from string
        const asn = cols[0]?.trim().split(&#39;AS&#39;)
        allASNs[asn[1]] = {}
        allASNs[asn[1]].Name = cols[1]?.trim();
        allASNs[asn[1]].CCode = cols[3]?.trim();
    }
  } catch (e) {
    console.log(&#34;Failed to load ASNs&#34;+e);
  }
}

function parseCSVLine(line) {
    return line.match(/(&#34;.*?&#34;|[^&#34;,]+)(?=\s*,|\s*$)/g)
        ?.map(v =&gt; v.replace(/^&#34;|&#34;$/g, &#39;&#39;).replace(/&#34;&#34;/g, &#39;&#34;&#39;)) || [];
}

// ── CSV fetch &amp; parse ─────────────────────────────────────────────────────────
async function loadData() {
  await loadASNs();
  try {
    const res = await fetch(CSV_URL);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const text = await res.text();
    allRows = parseCSV(text);
    init();
  } catch (e) {
    document.querySelectorAll(&#39;.state-msg&#39;).forEach(el =&gt; {
      el.textContent = &#39;Failed to load data: &#39; + e.message;
      el.classList.add(&#39;error-msg&#39;);
    });
  }
}

function parseCSV(text) {
  const lines = text.trim().split(&#39;\n&#39;).filter(l =&gt; l.trim());
  const rows  = [];
  for (const line of lines) {
    const cols = line.split(&#39;,&#39;);
    const dns  = parseFloat(cols[COL.dnsLatency]);
    const bgp  = parseFloat(cols[COL.bgpLatency]);
    if (isNaN(dns) || isNaN(bgp)) continue; // skip header or malformed
    rows.push({
      continent:  cols[COL.continent]?.trim(),
      country:    cols[COL.country]?.trim(),
      asn:        cols[COL.asn]?.trim(),
      dnsEcs:     cols[COL.dnsEcs]?.trim(),
      dnsHost:    cols[COL.dnsHost]?.trim(),
      dnsAsn:     cols[COL.dnsAsn]?.trim(),
      dnsLatency: dns,
      bgpHost:    cols[COL.bgpHost]?.trim(),
      bgpLatency: bgp,
      diff:       bgp - dns,
    });
  }
  return rows;
}

// ── Init ──────────────────────────────────────────────────────────────────────
function init() {
  // Populate both continent dropdowns from data
  const continents = unique(allRows, &#39;continent&#39;).sort();
  [&#39;latency-continent&#39;, &#39;diff-continent&#39;].forEach(id =&gt; {
    const sel = document.getElementById(id);
    continents.forEach(c =&gt; {
      const o   = document.createElement(&#39;option&#39;);
      o.value   = c;
      o.textContent = c;
      sel.appendChild(o);
    });
  });

  // Wire controls
  [&#39;latency-group&#39;, &#39;latency-continent&#39;].forEach(id =&gt;
    document.getElementById(id).addEventListener(&#39;change&#39;, renderLatencyChart));
  [&#39;diff-group&#39;, &#39;diff-continent&#39;].forEach(id =&gt;
    document.getElementById(id).addEventListener(&#39;change&#39;, renderDiffChart));

  renderStats();
  renderLatencyChart();
  renderDiffChart();
  initTooltip();
}

// ── Hero + meta stats (always use full dataset) ───────────────────────────────
function renderStats() {
  const rows = allRows;
  if (!rows.length) return;

  const avgDns = median(rows, &#39;dnsLatency&#39;);
  const avgBgp = median(rows, &#39;bgpLatency&#39;);

  document.getElementById(&#39;med-dns&#39;).innerHTML =
    fmt(avgDns) + &#39;&lt;span class=&#34;stat-unit&#34;&gt;ms&lt;/span&gt;&#39;;
  document.getElementById(&#39;med-bgp&#39;).innerHTML =
    fmt(avgBgp) + &#39;&lt;span class=&#34;stat-unit&#34;&gt;ms&lt;/span&gt;&#39;;

  //how many have ECS?
  const ecsCount = rows.filter(r =&gt; r.dnsEcs &amp;&amp; r.dnsEcs.toUpperCase() === &#39;TRUE&#39;).length;
  const ecsPct   = Math.round(ecsCount / rows.length * 100);

  //how many does the http asn match dns asn?
  const dnsIspCount = rows.filter(r =&gt; r.asn &amp;&amp; r.dnsAsn &amp;&amp; r.asn != r.dnsAsn).length;
  const dnsIspPct = Math.round(dnsIspCount / rows.length * 100);


  document.getElementById(&#39;meta-records&#39;).textContent   = rows.length.toLocaleString();
  document.getElementById(&#39;meta-countries&#39;).textContent = unique(rows, &#39;country&#39;).length;
  document.getElementById(&#39;meta-ases&#39;).textContent      = unique(rows, &#39;asn&#39;).length;
  document.getElementById(&#39;meta-non-isp&#39;).textContent   = dnsIspPct + &#39;%&#39;;
  document.getElementById(&#39;meta-ecs&#39;).textContent       = ecsPct + &#39;%&#39;;
}

// ── Latency chart ─────────────────────────────────────────────────────────────
function renderLatencyChart() {
  const el       = document.getElementById(&#39;latency-chart&#39;);
  const groupKey = document.getElementById(&#39;latency-group&#39;).value;
  const rows     = filteredRows(&#39;latency-continent&#39;);

  if (!rows.length) { el.innerHTML = &#39;&lt;div class=&#34;state-msg&#34;&gt;No data&lt;/div&gt;&#39;; return; }

  const lc      = document.getElementById(&#39;latency-count&#39;);
  lc.textContent = `${rows.length} total`;
  const map    = groupByKey(rows, groupKey);
  const keys   = Object.keys(map).sort((b, a) =&gt; median(map[b], &#39;dnsLatency&#39;)+median(map[b],&#39;bgpLatency&#39;) - median(map[a], &#39;dnsLatency&#39;)-median(map[a], &#39;bgpLatency&#39;));
  const maxVal = Math.max(...keys.flatMap(k =&gt; [median(map[k], &#39;dnsLatency&#39;), median(map[k], &#39;bgpLatency&#39;)]));

  el.innerHTML = keys.map(k =&gt; {
    const dStats = stats(map[k], &#39;dnsLatency&#39;);
    const bStats = stats(map[k], &#39;bgpLatency&#39;);
    const diffStats = stats(map[k], &#39;diff&#39;);
    const dPct   = fmtPct(dStats.median, maxVal);
    const bPct   = fmtPct(bStats.median, maxVal);
    const label  = groupKey === &#39;country&#39; ? countryName(k) : asnName(k);
    const count = map[k].length;
    const ttData = JSON.stringify({ label, dns: dStats, bgp: bStats, diff: diffStats, count});
    return `
      &lt;div class=&#34;dual-bar-row&#34;&gt;
        &lt;div class=&#34;bar-label&#34;&gt;${label}&lt;/div&gt;
        &lt;div class=&#34;dual-tracks&#34; data-tt=&#39;${ttData}&#39;&gt;
          &lt;div class=&#34;bar-track&#34;&gt;&lt;div class=&#34;bar-fill dns&#34; style=&#34;width:${dPct}%&#34;&gt;&lt;/div&gt;&lt;/div&gt;
          &lt;div class=&#34;bar-track&#34;&gt;&lt;div class=&#34;bar-fill bgp&#34; style=&#34;width:${bPct}%&#34;&gt;&lt;/div&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;`;
  }).join(&#39;&#39;);
}

// ── Diff chart ────────────────────────────────────────────────────────────────
function renderDiffChart() {
  const el       = document.getElementById(&#39;diff-chart&#39;);
  const groupKey = document.getElementById(&#39;diff-group&#39;).value;
  const rows     = filteredRows(&#39;diff-continent&#39;);

  if (!rows.length) { el.innerHTML = &#39;&lt;div class=&#34;state-msg&#34;&gt;No data&lt;/div&gt;&#39;; return; }

  const dc      = document.getElementById(&#39;diff-count&#39;);
  dc.textContent = `${rows.length} total`;
  const map    = groupByKey(rows, groupKey);
  const keys   = Object.keys(map).sort((a, b) =&gt; median(map[b], &#39;diff&#39;) - median(map[a], &#39;diff&#39;));
  const maxAbs = Math.max(...keys.map(k =&gt; Math.abs(median(map[k], &#39;diff&#39;)))) || 1;

  el.innerHTML = keys.map(k =&gt; {
    const dStats = stats(map[k], &#39;dnsLatency&#39;);
    const bStats = stats(map[k], &#39;bgpLatency&#39;);
    const diffStats = stats(map[k], &#39;diff&#39;);
    const d      = diffStats.median;
    const pct    = (Math.abs(d) / maxAbs * 100).toFixed(1);
    const cls    = d &gt;= 0 ? &#39;diff-pos&#39; : &#39;diff-neg&#39;;
    const sign   = d &gt;= 0 ? &#39;+&#39; : &#39;&#39;;
    const label  = groupKey === &#39;country&#39; ? countryName(k) : asnName(k);
    const count = map[k].length;
    const ttData = JSON.stringify({ label, dns: dStats, bgp: bStats, diff: diffStats, count });
    return `
      &lt;div class=&#34;bar-row&#34;&gt;
        &lt;div class=&#34;bar-label&#34;&gt;${label}&lt;/div&gt;
        &lt;div class=&#34;bar-track&#34; data-tt=&#39;${ttData}&#39;&gt;
          &lt;div class=&#34;bar-fill ${cls}&#34; style=&#34;width:${pct}%&#34;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&#34;bar-val ${d &gt;= 0 ? &#39;diff-pos-text&#39; : &#39;diff-neg-text&#39;}&#34;&gt;${sign}${fmt(d)}&lt;/div&gt;
      &lt;/div&gt;`;
  }).join(&#39;&#39;);
}

// ── Tooltip ───────────────────────────────────────────────────────────────────
function initTooltip() {
  const tt = document.getElementById(&#39;tt&#39;);

  document.addEventListener(&#39;mousemove&#39;, e =&gt; {
    const target = e.target.closest(&#39;[data-tt]&#39;);
    if (!target) { tt.style.display = &#39;none&#39;; return; }

    const data = JSON.parse(target.dataset.tt);
    tt.style.display = &#39;block&#39;;

    //show all data in the tooltip, not just latency / difference
    const medDiff = data.diff.median;
    const cls     = medDiff &gt;= 0 ? &#39;c-pos&#39; : &#39;c-neg&#39;;
    const verdict = medDiff &gt;= 0 ? &#39;DNS faster (median)&#39; : &#39;BGP faster (median)&#39;;
    tt.innerHTML = `
    &lt;div class=&#34;tt-title&#34;&gt;${data.label}&lt;/div&gt;
    &lt;div class=&#34;tt-section c-gen&#34;&gt;${data.count} records&lt;/div&gt;
    &lt;div class=&#34;tt-section c-dns&#34;&gt;DNS&lt;/div&gt;
    ${statGrid(data.dns, &#39;c-dns&#39;, &#39;c-dns&#39;)}
    &lt;div class=&#34;tt-section c-bgp&#34;&gt;BGP&lt;/div&gt;
    ${statGrid(data.bgp, &#39;c-bgp&#39;, &#39;c-bgp&#39;)}
    &lt;div class=&#34;tt-section&#34;&gt;Difference (BGP − DNS)&lt;/div&gt;
    ${statGrid(data.diff, &#39;c-pos&#39;, &#39;c-neg&#39;)}
    &lt;div class=&#34;tt-verdict ${cls}&#34;&gt;${verdict}&lt;/div&gt;`;

    // Keep tooltip on screen
    const pad = 14;
    let x = e.clientX + pad;
    let y = e.clientY + pad;
    if (x + 260 &gt; window.innerWidth)  x = e.clientX - 260 - pad;
    if (y + 200 &gt; window.innerHeight) y = e.clientY - 200 - pad;
    tt.style.left = x + &#39;px&#39;;
    tt.style.top  = y + &#39;px&#39;;
  });
}

// ── Helpers ───────────────────────────────────────────────────────────────────
function filteredRows(continentSelectId) {
  const cont = document.getElementById(continentSelectId).value;
  return cont ? allRows.filter(r =&gt; r.continent === cont) : allRows;
}
function median(rows, key) {
  if (!rows.length) return 0;

  const values = rows
    .map(r =&gt; r[key])
    .sort((a, b) =&gt; a - b);

  const mid = Math.floor(values.length / 2);

  return values.length % 2 === 0
    ? (values[mid - 1] + values[mid]) / 2
    : values[mid];
}
function groupByKey(rows, key) {
  return rows.reduce((acc, r) =&gt; {
    const k = r[key] || &#39;(unknown)&#39;;
    (acc[k] = acc[k] || []).push(r);
    return acc;
  }, {});
}
function unique(rows, key) {
  return [...new Set(rows.map(r =&gt; r[key]).filter(Boolean))];
}
function fmt(n)           { return Number(n).toFixed(2); }
function fmtPct(val, max) { return max ? (val / max * 100).toFixed(1) : 0; }

function stats(rows, key) {
  const vals = rows.map(r =&gt; r[key]).sort((a, b) =&gt; a - b);
  const n    = vals.length;
  const mean = vals.reduce((s, v) =&gt; s + v, 0) / n;
  const mid  = Math.floor(n / 2);
  const median = n % 2 === 0 ? (vals[mid - 1] + vals[mid]) / 2 : vals[mid];
  return { min: vals[0], mean, median, max: vals[n - 1] };
}

function statGrid(s, colorClsPos, colorClsNeg) {
  const sign = k =&gt; (k === &#39;diff&#39; || s[k] &lt; 0) ? &#39;&#39; : &#39;&#39;;
  const sf = v =&gt; {
    const str = fmt(Math.abs(v));
    return (v &lt; 0 ? &#39;−&#39; : &#39;&#39;) + str;
  };
  const colorClsMin = s.min &gt; 0 ? colorClsPos : colorClsNeg;
  const colorClsMean = s.mean &gt; 0 ? colorClsPos : colorClsNeg;
  const colorClsMed = s.median &gt; 0 ? colorClsPos : colorClsNeg;
  const colorClsMax = s.max &gt; 0 ? colorClsPos : colorClsNeg;
  return `
    &lt;div class=&#34;tt-grid&#34;&gt;
      &lt;span class=&#34;hdr lbl&#34;&gt;&lt;/span&gt;
      &lt;span class=&#34;hdr&#34;&gt;min&lt;/span&gt;
      &lt;span class=&#34;hdr&#34;&gt;mean&lt;/span&gt;
      &lt;span class=&#34;hdr&#34;&gt;med&lt;/span&gt;
      &lt;span class=&#34;hdr&#34;&gt;max&lt;/span&gt;
      &lt;span class=&#34;lbl&#34;&gt;ms&lt;/span&gt;
      &lt;span class=&#34;val ${colorClsMin}&#34;&gt;${sf(s.min)}&lt;/span&gt;
      &lt;span class=&#34;val ${colorClsMean}&#34;&gt;${sf(s.mean)}&lt;/span&gt;
      &lt;span class=&#34;val ${colorClsMed}&#34;&gt;${sf(s.median)}&lt;/span&gt;
      &lt;span class=&#34;val ${colorClsMax}&#34;&gt;${sf(s.max)}&lt;/span&gt;
    &lt;/div&gt;`;
}

// ── Boot ──────────────────────────────────────────────────────────────────────
loadData();
&lt;/script&gt;</content>
    </item>
    
    <item>
      <title>Why I Don&#39;t Link DHCP &#43; DNS (3 ways to update DNS)</title>
      <link>https://www.apalrd.net/posts/2026/network_dhcp/</link>
      <pubDate>Mon, 13 Apr 2026 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2026/network_dhcp/</guid>
      <description>Today I&amp;rsquo;m tackling an issue that gets a lot of network engineers really hung up - in the old days, pushing DHCP data into DNS seemed like a good idea, but now it&amp;rsquo;s just garbage all around. What are some solutions you can use instead? Today I have three solutions - mDNS (multicast DNS), pushing DNS configs as part of automation (Ansible example), and pushing DNS from the host itself using the DNS protocol (nsupdate).</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m tackling an issue that gets a lot of network engineers really hung up - in the old days, pushing DHCP data into DNS seemed like a good idea, but now it&amp;rsquo;s just garbage all around. What are some solutions you can use instead? Today I have three solutions - mDNS (multicast DNS), pushing DNS configs as part of automation (Ansible example), and pushing DNS from the host itself using the DNS protocol (nsupdate).&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2026/network_dhcp/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2026/network_dhcp/#multicast-dns&#34;&gt;Multicast DNS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2026/network_dhcp/#ansible-node-provisioning&#34;&gt;Ansible Node Provisioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2026/network_dhcp/#dynamic-dns-nsupdate&#34;&gt;Dynamic DNS (nsupdate)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/jTHx0MNADhM&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2026/network_dhcp/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;multicast-dns&#34;&gt;Multicast DNS&lt;/h2&gt;
&lt;p&gt;This method is the easiest, and everyone with a small network should be using this method. It&amp;rsquo;s installed by default on most clients, but on Debian / Proxmox VE, here&amp;rsquo;s what you need to do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install avahi-daemon -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You also need to edit &lt;code&gt;/etc/nsswitch.conf&lt;/code&gt; to fix IPv6 not being resolved (remove &amp;lsquo;4&amp;rsquo; from &amp;lsquo;mdns4_minimal&amp;rsquo;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;--- a/etc/nsswitch.conf.bak
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+++ b/etc/nsswitch.conf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -9,7 +9,7 @@ group:          files systemd
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; shadow:         files systemd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; gshadow:        files systemd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-hosts:          files mdns4_minimal [NOTFOUND=return] dns
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+hosts:          files mdns_minimal [NOTFOUND=return] dns
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; networks:       files
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;ansible-node-provisioning&#34;&gt;Ansible Node Provisioning&lt;/h2&gt;
&lt;p&gt;Once your business gets big enough to have your own servers (on-prem or virtual), not just SaaS solutions, you are probably ready to graduate from flat network mDNS to running your own DNS server. I like to push my server configs to DNS as part of the provisioning process. Here&amp;rsquo;s a basic Ansible playbook that I wrote which does exactly that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Provision Proxmox VM and register IPv6 DNS record&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;hosts&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;localhost&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# proxmox host, api keys, .. go in a vars file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# or group vars if you prefer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;vars_files&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;vars.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;connection&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;gather_facts&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;vars&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# config of the new VM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;template_vmid&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;903&lt;/span&gt;          &lt;span style=&#34;color:#75715e&#34;&gt;#This is a VM template using cloud-init and already configured&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;new_hostname&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;new_cores&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;new_memory&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2048&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;boot_disk_size&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;64G&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;boot_disk_device&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;scsi0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# IPv6 prefix of the network the VM is on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ipv6_prefix&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2a0f:b240:1001:67&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;tasks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Get next available VMID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Get next available VMID from Proxmox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.uri&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://{{ proxmox_host }}:8006/api2/json/cluster/nextid&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;method&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;GET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;headers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;Authorization&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PVEAPIToken={{ proxmox_user }}!{{ proxmox_token_id }}={{ vault_proxmox_password }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;validate_certs&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ proxmox_verify_ssl }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;status_code&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;register&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nextid_result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Set new_vmid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.set_fact&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;new_vmid&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ nextid_result.json.data | int }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Show allocated VMID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.debug&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;msg&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Proxmox allocated VMID: {{ new_vmid }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Clone template vmid to new vmid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Clone VM {{ template_vmid }} to {{ new_vmid }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.uri&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://{{ proxmox_host }}:8006/api2/json/nodes/{{ proxmox_node }}/qemu/{{ template_vmid }}/clone&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;method&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;POST&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;headers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;Authorization&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PVEAPIToken={{ proxmox_user }}!{{ proxmox_token_id }}={{ proxmox_password }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;body_format&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;body&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;newid&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ new_vmid }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ new_hostname }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;full&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;validate_certs&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ proxmox_verify_ssl }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;status_code&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;register&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;clone_result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Wait for clone task to complete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.uri&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://{{ proxmox_host }}:8006/api2/json/nodes/{{ proxmox_node }}/tasks/{{ clone_result.json.data }}/status&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;method&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;GET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;headers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;Authorization&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PVEAPIToken={{ proxmox_user }}!{{ proxmox_token_id }}={{ proxmox_password }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;validate_certs&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ proxmox_verify_ssl }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;register&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;task_status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;until&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;task_status.json.data.status == &amp;#39;stopped&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;retries&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;delay&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Get VM&amp;#39;s MAC address to compute EUI64, add prefix, add to DNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# net0 will look like:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# virtio=AA:BB:CC:DD:EE:FF,bridge=vmbr0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Fetch VM config from Proxmox API&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.uri&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://{{ proxmox_host }}:8006/api2/json/nodes/{{ proxmox_node }}/qemu/{{ new_vmid }}/config&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;method&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;GET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;headers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;Authorization&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PVEAPIToken={{ proxmox_user }}!{{ proxmox_token_id }}={{ vault_proxmox_password }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;validate_certs&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ proxmox_verify_ssl }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;return_content&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;status_code&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;register&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;vm_config_raw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Parse MAC address from net0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.set_fact&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mac_address&lt;/span&gt;: &amp;gt;-&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          {{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            vm_config_raw.json.data.net0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            | regex_search(&amp;#39;([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})&amp;#39;, &amp;#39;\1&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            | first
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            | upper
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          }}&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Show extracted MAC address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.debug&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;msg&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MAC address: {{ mac_address }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# We need to flip a bit to go from MAC to EUI64, and that&amp;#39;s actually&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# surprisingly hard to do in Jinja&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# so here&amp;#39;s a filter plugin I found, we just need bitwise xor here:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# https://eengstrom.github.io/musings/add-bitwise-operations-to-ansible-jinja2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Compute EUI-64 IPv6 address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.set_fact&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;ipv6_addr&lt;/span&gt;: &amp;gt;-&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          {{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              ipv6_prefix ~ &amp;#39;:&amp;#39; ~
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              (&amp;#39;%02X&amp;#39; % (mac_octets[0] | int(base=16) | bitwise_xor(0x02))) ~ mac_octets[1] ~ &amp;#39;:&amp;#39; ~
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              mac_octets[2] ~ &amp;#39;ff:&amp;#39; ~
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              &amp;#39;fe&amp;#39; ~ mac_octets[3] ~ &amp;#39;:&amp;#39; ~
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              mac_octets[4] ~ mac_octets[5]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            ) | ansible.utils.ipaddr(&amp;#39;address&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          }}&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;vars&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mac_octets&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ mac_address.split(&amp;#39;:&amp;#39;) }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Show computed IPv6 address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.debug&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;msg&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EUI-64 IPv6: {{ ipv6_addr }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Add AAAA record to DNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.uri&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ technitium_url }}/api/zones/records/add&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;method&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;POST&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;headers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;Content-Type&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;application/x-www-form-urlencoded&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;body_format&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;form-urlencoded&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;body&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;token&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ technitium_token }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;domain&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ new_hostname }}.{{ dns_zone }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;zone&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ dns_zone }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;AAAA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ipAddress&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ ipv6_addr }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ttl&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ dns_ttl }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;overwrite&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ptr&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;status_code&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;validate_certs&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ technitium_verify_ssl }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;register&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;dns_result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Show DNS API response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.debug&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;msg&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ dns_result.json }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Write out everything we just did&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Provisioning complete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.debug&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;msg&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;VM {{ new_vmid }} ({{ new_hostname }}) created on node {{ proxmox_node }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MAC: {{ mac_address }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;IPv6 (EUI-64): {{ ipv6_addr }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DNS AAAA record: {{ new_hostname }}.{{ dns_zone }} → {{ ipv6_addr }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You also need a &lt;code&gt;vars.yml&lt;/code&gt; (and possibly &lt;code&gt;vault.yml&lt;/code&gt;) to store these commonly used constants like the Proxmox host, usernames, passwords, &amp;hellip; but that&amp;rsquo;s beyond the scope of this tutorial&lt;/p&gt;
&lt;h2 id=&#34;dynamic-dns-nsupdate&#34;&gt;Dynamic DNS (nsupdate)&lt;/h2&gt;
&lt;p&gt;Third option is to let hosts push their own updates to DNS, using nsupdate (RFC 2136). Again, I&amp;rsquo;m using Debian as my example OS here.&lt;/p&gt;
&lt;p&gt;The update process for rfc 2136 is basically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Host does a DNS command to update its own records (this runs over normal DNS - port 53 - nothing special)&lt;/li&gt;
&lt;li&gt;Host signs its command with a unique transaction signature (TSIG), which is a shared secret - we need a unique secret PER HOST if we want this to be secure and not let any host change any other host&amp;rsquo;s DNS name&lt;/li&gt;
&lt;li&gt;DNS server validates that the TSIG is correct&lt;/li&gt;
&lt;li&gt;DNS server validates that this TSIG is allowed to access these records&lt;/li&gt;
&lt;li&gt;DNS server commits update&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, we first need to add a new TSIG in Technitium. In the web UI it&amp;rsquo;s under Settings -&amp;gt; TSIG -&amp;gt; Add, if you leave the key blank it will generate a random value. Create a new key with the name of your specific host here.&lt;/p&gt;
&lt;p&gt;Now, we need to create a key file as root (I used &lt;code&gt;/etc/tsig.key&lt;/code&gt; for this) - obviously use your own secret here and your own key name!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;host-testing&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;algorithm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hmac&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sha256&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;secret&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OCop85LAjLvdkf7J+3mar+uvTjufHQtiZozRp7z8VIg=&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we need to setup the system. We need to install &lt;code&gt;bind9-dnsutils&lt;/code&gt; on Debian, which gets us the &lt;code&gt;nsupdate&lt;/code&gt; utility. The utility is actually not very useful at all on its own, so I wrote a script in Bash which gets all of the local IPs with &lt;code&gt;hostname -I&lt;/code&gt;, splits them into A and AAAA records, and builds the list of commands for &lt;code&gt;nsupdate&lt;/code&gt;. Put this script in &lt;code&gt;/usr/local/bin/ddns&lt;/code&gt; and don&amp;rsquo;t forget to &lt;code&gt;chmod +x&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;HOST&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;hostname&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FQDN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$HOST&lt;span style=&#34;color:#e6db74&#34;&gt;.apalrd.fi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Update your server and zone here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;server polaris.apalrd.fi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;zone apalrd.fi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Remove existing records&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;update delete &lt;/span&gt;$FQDN&lt;span style=&#34;color:#e6db74&#34;&gt; A&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;update delete &lt;/span&gt;$FQDN&lt;span style=&#34;color:#e6db74&#34;&gt; AAAA&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Add all IPv4 addresses (skip loopback)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; ip in &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;hostname -I&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$ip&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; !&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; *:* &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$ip&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; !&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 127.* &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;update add &lt;/span&gt;$FQDN&lt;span style=&#34;color:#e6db74&#34;&gt; 300 A &lt;/span&gt;$ip&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Add all IPv6 addresses (skip loopback + link-local)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; ip in &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;hostname -I&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$ip&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; *:* &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$ip&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; !&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ::1 &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$ip&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; !&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; fe80::* &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;update add &lt;/span&gt;$FQDN&lt;span style=&#34;color:#e6db74&#34;&gt; 300 AAAA &lt;/span&gt;$ip&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#it will send this all as one dns packet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;send&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; | nsupdate -k /etc/tsig.key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we just need to call this periodically. I&amp;rsquo;ve set it up with a systemd timer that runs hourly, plus every time the system starts up.&lt;/p&gt;
&lt;p&gt;First, the systemd service (which actually does the updating) - put this in &lt;code&gt;/etc/systemd/system/ddns.service&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;[Unit]
Description=Update dynamic DNS via nsupdate

[Service]
Type=oneshot
ExecStart=/usr/local/bin/ddns
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Second, the timer (which calls the service periodically) - put this in &lt;code&gt;/etc/systemd/system/ddns.timer&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;[Unit]
Description=Run dynamic dns periodically

[Timer]
#Just after boot
OnBootSec=2min
#Every 15mins after that
OnUnitActiveSec=15min
Persistent=true

[Install]
WantedBy=timers.target
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And enable the timer (but not the service!):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now ddns.timer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There may be a better way to integrate with the network events, but this is the simplest thing I have to show&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>How I Automated my Network with Ansible</title>
      <link>https://www.apalrd.net/posts/2026/asn_ansible/</link>
      <pubDate>Wed, 18 Mar 2026 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2026/asn_ansible/</guid>
      <description>Today, in the next eposide on my Personal AS series, I have added a third POP / fourth router, and that means I need to configure the POP all over again. That&amp;rsquo;s a lot of work, so I automated it with Ansible! Also follow along to see my first use of Netbox for automation
Contents Video Ansible - Inventory Ansible - Software Setup Ansible - Network Config Ansible - Routing Config Video Ansible Inventory Here&amp;rsquo;s the final version of my Ansible inventory/hosts.</description>
      <content>&lt;p&gt;Today, in the next eposide on my Personal AS series, I have added a third POP / fourth router, and that means I need to configure the POP all over again. That&amp;rsquo;s a lot of work, so I automated it with Ansible! Also follow along to see my first use of Netbox for automation&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2026/asn_ansible/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2026/asn_ansible/#ansible-inventory&#34;&gt;Ansible - Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2026/asn_ansible/#ansible-software-setup&#34;&gt;Ansible - Software Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2026/asn_ansible/#ansible-network-conf&#34;&gt;Ansible - Network Config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2026/asn_ansible/#ansible-routing-conf&#34;&gt;Ansible - Routing Config&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/Oqp5o2RG5MM&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2026/asn_ansible/1.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;ansible-inventory&#34;&gt;Ansible Inventory&lt;/h1&gt;
&lt;p&gt;Here&amp;rsquo;s the final version of my Ansible &lt;code&gt;inventory/hosts.yml&lt;/code&gt; file. Long term, ideally I can move all of these attributes to custom attributes in Netbox, or even pulling the whole inventory from Netbox, instead of maintaining this file separately.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;routers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;hosts&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;waw-pe1.apalrd.fi&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;router_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;waw-pe1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;nat64&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;pop&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;waw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;backup&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;peers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;lax-pe1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;sjy-p1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;grr-e1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;lax-pe1.apalrd.fi&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;router_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;lax-pe1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;nat64&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;pop&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;lax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;backup&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;peers&lt;/span&gt;: 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;waw-pe1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;sjy-p1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;grr-e1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;sjy-p1.apalrd.fi&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;router_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;sjy-p1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;peers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;waw-pe1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;lax-pe1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;grr-e1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;grr-e1.apalrd.fi&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;router_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;grr-e1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;nat64&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;pop&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;grr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;backup&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;peers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;sjy-p1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;waw-pe1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;lax-pe1.apalrd.fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;ansible-software-setup&#34;&gt;Ansible Software Setup&lt;/h1&gt;
&lt;p&gt;This is the script that installs all of the software (and running it again will update it!), enables backups, etc.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;hosts&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;tasks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Global package update&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;apt upgrade&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;apt&lt;/span&gt;: 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;update_cache&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;upgrade&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Packages required to install package repos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Pre required packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.apt&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;pkg&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#ae81ff&#34;&gt;apt-transport-https &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#ae81ff&#34;&gt;ca-certificates&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#ae81ff&#34;&gt;gpg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup to PBS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Proxmox apt key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.get_url&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;https://enterprise.proxmox.com/debian/proxmox-archive-keyring-trixie.gpg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/usr/share/keyrings/proxmox-archive-keyring.gpg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;backup is defined and backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Proxmox client repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.apt_repository&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;repo&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb [arch=amd64 signed-by=/usr/share/keyrings/proxmox-archive-keyring.gpg] http://download.proxmox.com/debian/pbs-client {{ ansible_distribution_release }} main&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;present&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;backup is defined and backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Proxmox Backup Client install from packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.apt&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;update_cache&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;proxmox-backup-client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;backup is defined and backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Copy Proxmox Backup Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;proxmox-backup.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/systemd/system/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;backup is defined and backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Copy Proxmox Backup Timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;proxmox-backup.timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/systemd/system/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;backup is defined and backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Enable backup timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.systemd_service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;proxmox-backup.timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;enabled&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ backup | default(false)}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;daemon-reload&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Configuration for bird3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bird3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;block&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;#Package install steps&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bird3 apt key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.get_url&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;https://pkg.labs.nic.cz/gpg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/usr/share/keyrings/cznic-labs-pkg.gpg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bird3 repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.apt_repository&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;repo&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb [signed-by=/usr/share/keyrings/cznic-labs-pkg.gpg] https://pkg.labs.nic.cz/bird3 {{ ansible_distribution_release }} main&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;present&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Bird3 install from packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.apt&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;update_cache&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bird3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Tayga&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Tayga&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nat64 is defined and nat64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;block&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tayga required packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.apt&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;pkg&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              - &lt;span style=&#34;color:#ae81ff&#34;&gt;build-essential&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              - &lt;span style=&#34;color:#ae81ff&#34;&gt;git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Git checkout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.git&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;repo&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://github.com/apalrd/tayga&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/root/tayga&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;force&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Compile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.shell&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;chdir&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/root/tayga&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;cmd&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;make &amp;amp;&amp;amp; make install WITH_SYSTEMD=1 LIVE=1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Disable default nat64 instance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.systemd_service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tayga@default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;enabled&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;stopped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Tayga local service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.systemd_service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tayga@local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;enabled&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;started&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Tayga wkpf service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.systemd_service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tayga@wkpf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;enabled&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;started&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s my Proxmox Backup systemd service/timer, in case you want to use those too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#/etc/systemd/system/proxmox-backup.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Description=Run Backup to Proxmox Backup Server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;After=network-online.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Environment=PBS_PASSWORD=your-api-key-nere&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Environment=PBS_REPOSITORY=user@pbs!apikey@pbs.apalrd.fi:repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Type=oneshot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ExecStart=proxmox-backup-client backup root.pxar:/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;WantedBy=default.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#/etc/systemd/system/proxmox-backup.timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Description=Backup System Daily&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;RefuseManualStart=no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;RefuseManualStop=no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Timer]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run 540 seconds after boot for the first time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;OnBootSec=540&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run at midnight UTC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;OnCalendar=*-*-* 00:00:00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Unit=proxmox-backup.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;ansible-network-conf&#34;&gt;Ansible Network Conf&lt;/h1&gt;
&lt;p&gt;Here&amp;rsquo;s the two Ansible playbooks to configure systemd networkd:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#pop_conf_net.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;hosts&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;collections&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;netbox.netbox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;ansible.utils&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;vars&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;netbox_url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://docs.peach.apalrd.fi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;netbox_token&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0DjI3ZTMQdQPEbti07i6KYnan8jOi0f2K9XS0Qm2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;tasks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Query peer primary addresses&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Build peer_hosts list from inventory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;set_fact&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;peer_hosts&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ peer_hosts | default([]) + [hostvars[item].host] }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;loop&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ peers }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;hostvars[item].host is defined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Query potential peers from Netbox VM list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;set_fact&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;all_vms&lt;/span&gt;: &amp;gt;-&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          {{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            lookup(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              &amp;#39;netbox.netbox.nb_lookup&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              &amp;#39;virtual-machines&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              api_endpoint=netbox_url,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              token=netbox_token,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              validate_certs=False
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          }}&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Build IPv6 map for requested VMs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;set_fact&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;peer_ipv6_map&lt;/span&gt;: &amp;gt;-&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          {{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            peer_ipv6_map | default({}) |
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            combine({
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              item.value.name:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                item.value.primary_ip6.address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                | ansible.utils.ipaddr(&amp;#39;address&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            })
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          }}&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;loop&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ all_vms }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;no_log&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;item.value.name in peer_hosts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;item.value.primary_ip6 is defined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Fail if any peer is missing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;fail&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;msg&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;No primary IPv6 found in NetBox for: {{ peer_hosts | difference(peer_ipv6_map.keys() | list) }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;peer_hosts | difference(peer_ipv6_map.keys() | list) | length &amp;gt; 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Show peer IPv6 addresses&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;debug&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;msg&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Primary IPv6 for {{ item }} is {{ peer_ipv6_map[item] }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;loop&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{peer_hosts}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Get my own IPv6 address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;set_fact&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;my_ip&lt;/span&gt;: &amp;gt;-&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          {{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            (all_vms | selectattr(&amp;#39;value.name&amp;#39;,&amp;#39;equalto&amp;#39;,host) | list)[0].value.primary_ip6.address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            | ansible.utils.ipaddr(&amp;#39;address&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          }}&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Show my own IPv6 address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;debug&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;msg&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;My IP is {{my_ip}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Configuration for Tunnel Interfaces&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Tunnel Interfaces&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.include_tasks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;file&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pop_conf_net_tunnel.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;loop&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{{ peers }}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;loop_control&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;loop_var&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;peer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Configuration for Loopback Interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Loopback Addresses&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;notify&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reload Networkd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;loopback.network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/systemd/network/loopback.network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Restart handlers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;handlers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reload Networkd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.shell&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;cmd&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;networkctl reload&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a sub-playbook to setup a singular tunnel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#pop_conf_net_tunnel.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Ansible script to manage one tunnel interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Tunnel to {{peer}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;block&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Interface Template Netdev to {{peer}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;notify&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reload Networkd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tunnel.netdev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/systemd/network/tun_{{hostvars[peer][&amp;#39;host&amp;#39;]|replace(&amp;#34;-&amp;#34;, &amp;#34;_&amp;#34;)}}.netdev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Interface Template Network to {{peer}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;notify&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reload Networkd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tunnel.network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/systemd/network/tun_{{hostvars[peer][&amp;#39;host&amp;#39;]|replace(&amp;#34;-&amp;#34;, &amp;#34;_&amp;#34;)}}.network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;They also rely on two template files, for netdev and network:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#tunnel.netdev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Tunnel to {{peer}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;NetDev]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Name=tun_{{hostvars[peer][&amp;#39;host&amp;#39;]|replace(&amp;#34;-&amp;#34;, &amp;#34;_&amp;#34;)}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Kind=ip6tnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Tunnel]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Mode=ip6ip6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Local={{ my_ip }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Remote={{ peer_ipv6_map[hostvars[peer][&amp;#39;host&amp;#39;]] }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;TTL=64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Independent=True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#tunnel.network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Tunnel to {{peer}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Match]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Name=tun_{{hostvars[peer][&amp;#39;host&amp;#39;]|replace(&amp;#34;-&amp;#34;, &amp;#34;_&amp;#34;)}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Network]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Address=fe80::{{router_id}}/64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ConfigureWithoutCarrier=yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;ansible-routing-conf&#34;&gt;Ansible Routing Conf&lt;/h1&gt;
&lt;p&gt;Here&amp;rsquo;s what my templated BIRD conf looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;hosts&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;collections&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;netbox.netbox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;ansible.utils&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;vars&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;netbox_url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://docs.peach.apalrd.fi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;netbox_token&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0DjI3ZTMQdQPEbti07i6KYnan8jOi0f2K9XS0Qm2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;netbox_validate_certs&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;tasks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Build prefix lists&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Query NetBox for bgp-adv-dfz-ac prefixes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;set_fact&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dfz_ac_prefixes&lt;/span&gt;: &amp;gt;-&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          {{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            query(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              &amp;#39;netbox.netbox.nb_lookup&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              &amp;#39;prefixes&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              api_endpoint=netbox_url,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              token=netbox_token,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              validate_certs=netbox_validate_certs | default(true),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              api_filter=&amp;#34;tag=bgp-adv-dfz-ac&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            | map(attribute=&amp;#39;value&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            | map(attribute=&amp;#39;prefix&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            | list
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          }}&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pop is defined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Show prefixes for AC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;debug&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;msg&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Prefix for AC: {{ item }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;loop&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{dfz_ac_prefixes}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pop is defined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Query NetBox for pop specific prefixes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;set_fact&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dfz_pop_prefixes&lt;/span&gt;: &amp;gt;-&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          {{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            query(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              &amp;#39;netbox.netbox.nb_lookup&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              &amp;#39;prefixes&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              api_endpoint=netbox_url,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              token=netbox_token,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              validate_certs=netbox_validate_certs | default(true),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              api_filter=&amp;#34;tag=bgp-adv-dfz-&amp;#34; ~ pop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            | map(attribute=&amp;#39;value&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            | map(attribute=&amp;#39;prefix&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            | list
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          }}&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pop is defined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Show prefixes for POP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;debug&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;msg&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Prefix for POP: {{ item }}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;loop&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{dfz_pop_prefixes}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pop is defined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Configuration for bird3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Bird3 copy common defs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;notify&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reload Bird&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bird-defs.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/bird/defs.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Bird3 template IGP peers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;notify&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reload Bird&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bird-igp.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/bird/igp.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Bird3 template iBGP peers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;notify&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reload Bird&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bird-ibgp.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/bird/ibgp.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Bird3 template exports&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;notify&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reload Bird&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bird-exports.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/bird/exports.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Bird3 node-specific file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;notify&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reload Bird&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.copy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bird-{{host}}.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/bird/bird.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Configuration for Tayga&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Tayga configuration for local nat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;notify&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Restart Tayga Local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nat64 is defined and nat64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tayga_local.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/tayga/local.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Tayga configuration for wkpf nat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;notify&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Restart Tayga Wkpf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nat64 is defined and nat64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;src&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tayga_wkpf.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dest&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/tayga/wkpf.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;owner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0644&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Restart handlers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;handlers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Reload Bird&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.shell&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;cmd&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;birdc configure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Restart Tayga Local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.systemd_service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tayga@local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;restarted&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Restart Tayga Wkpf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ansible.builtin.systemd_service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tayga@wkpf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;restarted&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It depends on a bunch of other files, which are templated (with Jinja):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bird&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;defs&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;My&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;201726&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IP&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;addresses&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;routers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IP_MINE&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a0f&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b240&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;{{&lt;span style=&#34;color:#a6e22e&#34;&gt;router_id&lt;/span&gt;}};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IP_WAW_PE1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a0f&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b240&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IP_LAX_PE1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a0f&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b240&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IP_SJW_P1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a0f&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b240&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IP_GRR_E1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a0f&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b240&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Where&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;route&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;entered&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_ENTER_MINE&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;, {{&lt;span style=&#34;color:#a6e22e&#34;&gt;router_id&lt;/span&gt;}});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_ENTER_WAW&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_ENTER_LAX&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_ENTER_SJW&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_ENTER_GRR&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Redistribute&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;route&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DFZ&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_DFZ_MINE&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;, {{ &lt;span style=&#34;color:#ae81ff&#34;&gt;420&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;router_id&lt;/span&gt; }});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_DFZ_ALL&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;420&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_DFZ_WAW&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;421&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_DFZ_LAX&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;422&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_DFZ_GRR&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;424&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IGP&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;related&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_IGP&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;667&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_HELL&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;666&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;This&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;route&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;via&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nat64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;define&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_NAT64&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bird&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;exports&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;This&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;generated&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;by&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;template&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Routes&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;export&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;adv_v6&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ipv6&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;My&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;own&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;loopback&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;address&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;goes&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;into&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IGP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;route&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a0f&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b240&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;{{&lt;span style=&#34;color:#a6e22e&#34;&gt;router_id&lt;/span&gt;}}&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;128&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;via&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;lo&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_ext_community&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_IGP&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pop&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;defined&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;prefix&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dfz_ac_prefixes&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Routes&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;which&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;will&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;be&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;advertised&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;anycast&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;route&lt;/span&gt; {{&lt;span style=&#34;color:#a6e22e&#34;&gt;prefix&lt;/span&gt;}} &lt;span style=&#34;color:#a6e22e&#34;&gt;blackhole&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_ext_community&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_DFZ_ALL&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_ext_community&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_ENTER_MINE&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;endfor&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Routes&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;which&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;will&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;be&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;advertised&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;prefix&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dfz_pop_prefixes&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;route&lt;/span&gt; {{&lt;span style=&#34;color:#a6e22e&#34;&gt;prefix&lt;/span&gt;}} &lt;span style=&#34;color:#a6e22e&#34;&gt;blackhole&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_ext_community&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_DFZ_MINE&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_ext_community&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_ENTER_MINE&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;endfor&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;endif&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nat64&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;defined&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nat64&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Routes&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nat64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;route&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ff9b&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;{{&lt;span style=&#34;color:#a6e22e&#34;&gt;router_id&lt;/span&gt;}}&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/64 via &amp;#34;nat64&amp;#34; {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_ext_community&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_NAT64&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_ext_community&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_ENTER_MINE&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;route&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ff9b&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/64 via &amp;#34;nat64wkpf&amp;#34; {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_ext_community&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_NAT64&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_ext_community&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_ENTER_MINE&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;endif&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bird&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;igp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;This&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;generated&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;by&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;template&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;It&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;configures&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IGP&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;OSPFv3&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;functionality&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;given&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ospf&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v3&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ospf6&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ipv6&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;all&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;filter&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;only&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;routes&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;which&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;we&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;specifically&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;want&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;going&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;into&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IGP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;which&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;are&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;routes&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;router&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;via&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;iBGP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;proto&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;adv_v6&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_ext_community&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;~&lt;/span&gt; [ &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP_TO_IGP&lt;/span&gt; ]) &lt;span style=&#34;color:#a6e22e&#34;&gt;then&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;accept&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;reject&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;All&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;OSPF&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;area&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;zero&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;area&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;peer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;peers&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Interface&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;neighbor&lt;/span&gt; {{&lt;span style=&#34;color:#a6e22e&#34;&gt;peer&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tun_{{hostvars[peer][&amp;#39;host&amp;#39;]|replace(&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;)}}&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ptmp&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;check&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;no&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;cost&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;hello&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;dead&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;neighbors&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;fe80&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;{{&lt;span style=&#34;color:#a6e22e&#34;&gt;hostvars&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;peer&lt;/span&gt;][&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;router_id&amp;#39;&lt;/span&gt;]}};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;endfor&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bird&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ibgp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;This&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;generated&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;by&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;template&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;It&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;configures&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;iBGP&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;peerings&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;given&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;node&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;full&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mesh&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BGP&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;locally&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;within&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;filter&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;to_bgp_local&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;For&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;routes&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;which&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;we&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;advertised&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;proto&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;adv_v6&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;then&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_origin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ORIGIN_INCOMPLETE&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_local_pref&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_next_hop&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IP_MINE&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;accept&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;For&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;routes&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;which&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;came&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DFZ&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;set&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;our&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;own&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nexthop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;proto&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dfz_v6&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;proto&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dfz_v4&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;then&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_med&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_next_hop&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IP_MINE&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;accept&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;For&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;routes&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;which&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;came&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;anywhere&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;redistribute&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;as&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;is&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;accept&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;peer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;peers&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bgp_local_&lt;/span&gt;{{&lt;span style=&#34;color:#a6e22e&#34;&gt;hostvars&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;peer&lt;/span&gt;][&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;host&amp;#39;&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;replace&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;_&amp;#34;&lt;/span&gt;)}} {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;neighbor&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a0f&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b240&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;{{&lt;span style=&#34;color:#a6e22e&#34;&gt;hostvars&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;peer&lt;/span&gt;][&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;router_id&amp;#39;&lt;/span&gt;]}} &lt;span style=&#34;color:#a6e22e&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MY_AS&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;multihop&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;address&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a0f&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b240&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;{{&lt;span style=&#34;color:#a6e22e&#34;&gt;router_id&lt;/span&gt;}};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ipv6&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;filter&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from_bgp_local&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;filter&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;to_bgp_local&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;endfor&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also use Tayga, and here is one of the Tayga configs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#tun device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;tun-device nat64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#prefix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;prefix 64:ff9b:1:{{router_id}}::/96&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ipv4-addr 192.0.0.8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#dynamic pool is apipa space&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;dynamic-pool 169.254.0.0/20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;udp-cksum-mode fwd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;log drop reject icmp self dyn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;tun-up yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;tun-route 169.254.0.0/20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;tun-route 64:ff9b:1:{{router_id}}::/64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>SMART SFP - Mini Linux System on a Stick (Literally)</title>
      <link>https://www.apalrd.net/posts/2025/network_smartsfp/</link>
      <pubDate>Tue, 18 Nov 2025 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2025/network_smartsfp/</guid>
      <description>Today I&amp;rsquo;m taking a look at the Plumspace Smart SFP - a dual core ARM Cortex A53 stuffed inside a 1310nm SFP optical transceiver, which can deal with packet flows at line rate*. Quite a neat little thing, with plenty of use cases.
Plumspace Smart SFPs: Link
Contents Video Bridging Bridging - Ntopng Routing Routing - NAT44 Routing - NAT46 (CLAT) Wireguard OpenSSL Bench Video Bridging Kernel defaults for br0, configured using /etc/network/interfaces:</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m taking a look at the Plumspace Smart SFP - a dual core ARM Cortex A53 stuffed inside a 1310nm SFP optical transceiver, which can deal with packet flows at line rate*. Quite a neat little thing, with plenty of use cases.&lt;/p&gt;
&lt;p&gt;Plumspace Smart SFPs: &lt;a href=&#34;https://plumspace.com/products/smart-sfp/&#34;&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_smartsfp/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_smartsfp/#bridging&#34;&gt;Bridging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_smartsfp/#bridging-ntopng&#34;&gt;Bridging - Ntopng&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_smartsfp/#routing&#34;&gt;Routing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_smartsfp/#routing-nat44&#34;&gt;Routing - NAT44&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_smartsfp/#routing-nat46&#34;&gt;Routing - NAT46 (CLAT)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_smartsfp/#wireguard-vpn&#34;&gt;Wireguard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_smartsfp/#openssl-bench&#34;&gt;OpenSSL Bench&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/_V2ST_Eiiek&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2025/network_smartsfp/1.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;bridging&#34;&gt;Bridging&lt;/h1&gt;
&lt;p&gt;Kernel defaults for br0, configured using &lt;code&gt;/etc/network/interfaces&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;auto gbe0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;allow-hotplug gbe0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;iface gbe0 inet manual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;auto gbe1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;allow-hotplug gbe1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;iface gbe1 inet manual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;auto br0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;allow-hotplug br0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;iface br0 inet6 auto&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;bridge_ports gbe0 gbe1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also installed &lt;code&gt;avahi-daemon&lt;/code&gt; which I&amp;rsquo;m using to discover it (&lt;code&gt;smart-sfp.local&lt;/code&gt;). You can use a static IP if you&amp;rsquo;d rather.&lt;/p&gt;
&lt;h2 id=&#34;iperf3&#34;&gt;Iperf3&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Connecting to host 172.27.15.180, port 5201&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;] &lt;span style=&#34;color:#ae81ff&#34;&gt;local 172.27.15.181 port 44144 connected to 172.27.15.180 port 5201&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ &lt;span style=&#34;color:#ae81ff&#34;&gt;ID] Interval           Transfer     Bitrate         Retr  Cwnd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-1.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  85.8 MBytes   719 Mbits/sec  443   2.56 MBytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;1.00-2.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  85.5 MBytes   717 Mbits/sec  252    693 KBytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;2.00-3.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   111 MBytes   934 Mbits/sec   27    785 KBytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;3.00-4.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   935 Mbits/sec  152    870 KBytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;4.00-5.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   941 Mbits/sec  100    684 KBytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;5.00-6.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   941 Mbits/sec    0    802 KBytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;6.00-7.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   941 Mbits/sec   27    899 KBytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;7.00-8.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   938 Mbits/sec   28    713 KBytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;8.00-9.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   936 Mbits/sec    6    820 KBytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;9.00-10.00&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   113 MBytes   945 Mbits/sec    0    922 KBytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- - - - - - - - - - - - - - - - - - - - - - - - -
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ &lt;span style=&#34;color:#ae81ff&#34;&gt;ID] Interval           Transfer     Bitrate         Retr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-10.00&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  1.04 GBytes   895 Mbits/sec  1035            sender&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-10.01&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  1.04 GBytes   892 Mbits/sec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;connections-per-second-cyperf&#34;&gt;Connections Per Second (Cyperf)&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test Result Summary                                      &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test duration         41 seconds                                             &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Connections                                              &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total succeeded       283790                             &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total failed          0                                  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average rate          6921.000000 connections per second&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average latency       564 µs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;bridging-ntopng&#34;&gt;Bridging Ntopng&lt;/h1&gt;
&lt;p&gt;Disabled segment offloading, running ntopng installed via apt packages&lt;/p&gt;
&lt;h2 id=&#34;throughput-test-cyperf&#34;&gt;Throughput Test (Cyperf)&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test Result Summary                                   &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test duration         27 seconds                      &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Throughput                                            &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average TX &amp;amp; RX       546.294224 Mb/s                 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average TX            543.728808 Mb/s                 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average RX            2.565416 Mb/s                   &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;TCP Data                                              &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total transferred     1.713713 GB                     &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total sent            1.713713 GB                     &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total received        0.000000 GB                     &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;connections-per-second-cyperf-1&#34;&gt;Connections Per Second (Cyperf)&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test Result Summary                                      &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test duration         32 seconds                                                                           &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Connections                                              &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total succeeded       193386                             &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total failed          0                                  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average rate          6043.000000 connections per second &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average latency       650 µs  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;routing&#34;&gt;Routing&lt;/h1&gt;
&lt;p&gt;Configured using &lt;code&gt;/etc/network/interfaces&lt;/code&gt; (and using IPv4 for cyperf):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;auto gbe0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;allow-hotplug gbe0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iface gbe0 inet static
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    address 192.0.0.1/29
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;auto gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;allow-hotplug gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iface gbe1 inet dhcp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iface gbe1 inet6 auto
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will add a default route via dhcp. Added return route on test server: &lt;code&gt;ip route add 192.0.0.0/29 via 172.27.15.182&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;iperf&#34;&gt;IPerf&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Connecting to host 172.27.15.180, port 5201&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;] &lt;span style=&#34;color:#ae81ff&#34;&gt;local 192.0.0.5 port 59314 connected to 172.27.15.180 port 5201&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ &lt;span style=&#34;color:#ae81ff&#34;&gt;ID] Interval           Transfer     Bitrate         Retr  Cwnd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-1.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   106 MBytes   886 Mbits/sec   15    393 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;1.00-2.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   944 Mbits/sec   11    561 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;2.00-3.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   941 Mbits/sec    7    686 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;3.00-4.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   940 Mbits/sec   50    796 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;4.00-5.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   113 MBytes   946 Mbits/sec    6    884 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;5.00-6.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   113 MBytes   945 Mbits/sec    9    973 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;6.00-7.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  87.9 MBytes   737 Mbits/sec  240    734 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;7.00-8.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   935 Mbits/sec    0    843 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;8.00-9.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   942 Mbits/sec    4    707 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;9.00-10.00&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   935 Mbits/sec    0    819 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- - - - - - - - - - - - - - - - - - - - - - - - -
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ &lt;span style=&#34;color:#ae81ff&#34;&gt;ID] Interval           Transfer     Bitrate         Retr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-10.00&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  1.07 GBytes   915 Mbits/sec  342            sender&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-10.02&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  1.07 GBytes   913 Mbits/sec                  receiver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;throughput-cyperf&#34;&gt;Throughput (Cyperf)&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test Result Summary                                   &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test duration         30 seconds                      &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Throughput                                            &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average TX &amp;amp; RX       905.054472 Mb/s                 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average TX            891.920008 Mb/s                 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average RX            13.134464 Mb/s                  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;TCP Data                                              &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total transferred     2.900737 GB                     &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total sent            2.900737 GB                     &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total received        0.000000 GB                      &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;cps-cyperf&#34;&gt;CPS (Cyperf)&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test Result Summary                                      &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test duration         40 seconds                                                         &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Connections                                              &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;----------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total succeeded       271844                             &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total failed          0                                  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average rate          6796.000000 connections per second &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average latency       579 µs  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;routing-nat44&#34;&gt;Routing NAT44&lt;/h1&gt;
&lt;p&gt;Configured using &lt;code&gt;/etc/network/interfaces&lt;/code&gt; (again using IPv4 for cyperf):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;auto gbe0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;allow-hotplug gbe0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iface gbe0 inet static
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    address 192.0.0.1/29
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;auto gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;allow-hotplug gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iface gbe1 inet dhcp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iface gbe1 inet6 auto
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and using iptables (&lt;em&gt;not&lt;/em&gt; the nf_tables version due to kernel limitations): &lt;code&gt;iptables-legacy -t nat -A POSTROUTING -o gbe1 -j MASQUERADE&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;iperf-1&#34;&gt;IPerf&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Connecting to host 172.27.15.180, port 5201&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;] &lt;span style=&#34;color:#ae81ff&#34;&gt;local 192.0.0.5 port 58318 connected to 172.27.15.180 port 5201&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ &lt;span style=&#34;color:#ae81ff&#34;&gt;ID] Interval           Transfer     Bitrate         Retr  Cwnd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-1.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   103 MBytes   866 Mbits/sec   59    400 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;1.00-2.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   943 Mbits/sec    6    554 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;2.00-3.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   942 Mbits/sec   94    680 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;3.00-4.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   936 Mbits/sec   27    796 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;4.00-5.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   941 Mbits/sec    3    894 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;5.00-6.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   938 Mbits/sec   41    741 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;6.00-7.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   938 Mbits/sec    0    851 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;7.00-8.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   943 Mbits/sec    2    943 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;8.00-9.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   941 Mbits/sec   49    737 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;9.00-10.00&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   112 MBytes   935 Mbits/sec    1    843 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- - - - - - - - - - - - - - - - - - - - - - - - -
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ &lt;span style=&#34;color:#ae81ff&#34;&gt;ID] Interval           Transfer     Bitrate         Retr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-10.00&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  1.09 GBytes   932 Mbits/sec  282            sender&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-10.01&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  1.08 GBytes   930 Mbits/sec                  receiver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;throughput-cyperf-1&#34;&gt;Throughput (Cyperf)&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test Result Summary                                   &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test duration         51 seconds                      &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Throughput                                            &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average TX &amp;amp; RX       860.770592 Mb/s                 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average TX            851.627024 Mb/s                 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average RX            9.143568 Mb/s                   &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;TCP Data                                              &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total transferred     4.853985 GB                     &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total sent            4.853985 GB                     &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total received        0.000000 GB                     &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;cps-cyperf-1&#34;&gt;CPS (Cyperf)&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test Result Summary                                     &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Test duration         33 seconds                                            &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Connections                                             &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total succeeded       8187                              &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Total failed          48                                &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average rate          248.000000 connections per second&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;Average latency       671 µs  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;routing-nat46&#34;&gt;Routing NAT46&lt;/h1&gt;
&lt;p&gt;Configured using &lt;code&gt;/etc/network/interfaces&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;auto gbe0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;allow-hotplug gbe0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iface gbe0 inet static
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    address 192.0.0.1/29
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;auto gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;allow-hotplug gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iface gbe1 inet6 auto
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;IPv4-island inside, IPv6-only outside
&amp;lsquo;inside&amp;rsquo; is 192.0.0.0/29 (DSLite range) mapped to 2001:db8::6460/125, leading to this Tayga config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tun-device nat64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ipv4-addr 192.0.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ipv6-addr 2601:40e:8100:ac30::6468
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prefix 64:ff9b::/96
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wkpf-strict no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;log drop reject icmp self dyn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Map IPv4-island to a seqential range of v6s on LAN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 192.0.0.0/29 2601:40e:8100:ac30::6460/125
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#test system on IPv6, mapped to a random IPv4 so we can iperf to it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 10.0.0.1/32 2001:db8::be24:11ff:feeb:716e/128
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the commands I ran to set up routing and such (didn&amp;rsquo;t bother trying to make this persistent):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Enable IP forwarding of IPv6 and IPv4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &amp;gt; /proc/sys/net/ipv6/conf/all/forwarding
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &amp;gt; /proc/sys/net/ipv4/conf/all/forwarding
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Enable Accept RA (=2 due to forwarding) on gbe1 for SLAAC address assignment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &amp;gt; /proc/sys/net/ipv6/conf/gbe1/accept_ra
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Proxy NDP the CLAT addresses&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &amp;gt; /proc/sys/net/ipv6/conf/gbe1/proxy_ndp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Proxy ND addresses from /29&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip neigh add proxy 2601:40e:8100:ac30::6460 dev gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip neigh add proxy 2601:40e:8100:ac30::6461 dev gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip neigh add proxy 2601:40e:8100:ac30::6462 dev gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip neigh add proxy 2601:40e:8100:ac30::6463 dev gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip neigh add proxy 2601:40e:8100:ac30::6464 dev gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip neigh add proxy 2601:40e:8100:ac30::6465 dev gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip neigh add proxy 2601:40e:8100:ac30::6466 dev gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip neigh add proxy 2601:40e:8100:ac30::6467 dev gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#plus one for Tayga itself&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip neigh add proxy 2601:40e:8100:ac30::6468 dev gbe1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Start tayga (using default.conf and included systemd unit)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now tayga@default
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Bring up iface and route to it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#no need for IPs on this iface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip link set dev nat64 up
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip route add default dev nat64 mtu &lt;span style=&#34;color:#ae81ff&#34;&gt;1480&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip route add 2601:40e:8100:ac30::6464/124 dev nat64
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;iperf-2&#34;&gt;IPerf&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Connecting to host 10.0.0.1, port 5201&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;] &lt;span style=&#34;color:#ae81ff&#34;&gt;local 192.0.0.5 port 43146 connected to 10.0.0.1 port 5201&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ &lt;span style=&#34;color:#ae81ff&#34;&gt;ID] Interval           Transfer     Bitrate         Retr  Cwnd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-1.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  39.9 MBytes   334 Mbits/sec    5    771 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;1.00-2.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  43.1 MBytes   362 Mbits/sec    0    866 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;2.00-3.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  43.4 MBytes   364 Mbits/sec    0    937 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;3.00-4.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  43.1 MBytes   362 Mbits/sec    0    987 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;4.00-5.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  42.9 MBytes   360 Mbits/sec    0   1022 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;5.00-6.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  41.9 MBytes   351 Mbits/sec    8    766 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;6.00-7.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  43.5 MBytes   365 Mbits/sec    0    813 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;7.00-8.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  43.2 MBytes   363 Mbits/sec    0    844 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;8.00-9.00&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  42.0 MBytes   352 Mbits/sec    0    867 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;9.00-10.00&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec  42.1 MBytes   353 Mbits/sec    0    905 KBytes       &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- - - - - - - - - - - - - - - - - - - - - - - - -
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ &lt;span style=&#34;color:#ae81ff&#34;&gt;ID] Interval           Transfer     Bitrate         Retr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-10.00&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   425 MBytes   357 Mbits/sec   13            sender&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[  &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]   &lt;span style=&#34;color:#ae81ff&#34;&gt;0.00-10.01&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;sec   424 MBytes   355 Mbits/sec                  receiver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;wireguard-vpn&#34;&gt;Wireguard VPN&lt;/h1&gt;
&lt;p&gt;I did this using network namespaces instead of multiple table. You can choose to either have the WAN or LAN on the &amp;lsquo;default&amp;rsquo; namespace, where normal processes on Linux will bind to. I chose WAN in this case, since I am relying on ssh + avahi mdns on my normal network.&lt;/p&gt;
&lt;p&gt;Wireguard will always send/receive packets from the network namespace it is started in, even if you move the adapter to a new netns! So start the adapter from the WAN-side (or in my case, use wireguard-go launched from the default netns), THEN move the adapter into the netns and bring it up.&lt;/p&gt;
&lt;p&gt;So, steps:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Create netns named &amp;#39;user&amp;#39;, add inteface gbe0 (downstream &amp;#39;LAN&amp;#39;) to netns&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip netns add user
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip link set dev gbe0 netns user
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Placed Mullvad&amp;#39;s conf generator in /etc/wg/wg0.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Removed Address and DNS lines, which are for wg-quick&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# will need those values separately&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Launch wireguard-go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wireguard-go wg0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Configure it using wg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wg setconf wg0 /etc/wg/wg0.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Move wg tun adapter to netns&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip link set dev wg0 netns user
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Config within the netns (&lt;code&gt;ip netns exec user bash&lt;/code&gt;)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# enable forwarding within the netns (it has its own settings!)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &amp;gt; /proc/sys/net/ipv6/conf/all/forwarding
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &amp;gt; /proc/sys/net/ipv4/conf/all/forwarding
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# bring up wg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip link set up wg0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# These came from Mullvad&amp;#39;s conf generator&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip addr add 10.67.156.35/32 dev wg0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip addr add fc00:bbbb:bbbb:bb01::4:9c22/128 dev wg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add default routes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip route add default dev wg0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip -6 route add default dev wg0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add masquerade rules&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iptables-legacy -t nat -A POSTROUTING -o wg0 -j MASQUERADE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip6tables-legacy -t nat -A POSTROUTING -o wg0 -j MASQUERADE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add IPs to gbe0 in our netns (it loses config when moved)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip addr add 192.0.0.1/29 dev gbe0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip addr add 2001:db8:6464::1/64 dev gbe0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Config for dnsmasq for this setup&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#static dns resolver conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;no-resolv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#server which came from Mullvad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;server&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;10.64.0.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#iface to listen on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gbe0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#using the dslite range since I already had configured this for 464xlat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dhcp-range&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.0.0.2,192.0.0.6,1h
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#using doc prefix for nat66&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dhcp-range&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;2001:db8:6969::, ra-stateless
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I launched dnsmasq within the netns so it will serve DHCP on interface gbe0.&lt;/p&gt;
&lt;h1 id=&#34;openssl-bench&#34;&gt;OpenSSL bench&lt;/h1&gt;
&lt;p&gt;OpenSSL bench on this hw:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Speed test AES-128-GCM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;root@smart-sfp:~# openssl speed -evp aes-128-gcm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-128-GCM for 3s on 16 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;753963&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-128-GCM&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-128-GCM for 3s on 64 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;733150&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-128-GCM&amp;#39;s in 3.00s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-128-GCM for 3s on 256 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;660259&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-128-GCM&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-128-GCM for 3s on 1024 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;469975&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-128-GCM&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-128-GCM for 3s on 8192 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;141423&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-128-GCM&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-128-GCM for 3s on 16384 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;78532&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-128-GCM&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3.0.17&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;built on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Tue Aug  5 07:09:41 2025 UTC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;options&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bn(64,64)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;compiler&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gcc -fPIC -pthread -Wa,--noexecstack -Wall -fzero-call-used-regs=used-gpr -DOPENSSL_TLS_SECURITY_LEVEL=2 -Wa,--noexecstack -g -O2 -ffile-prefix-map=/build/reproducible-path/openssl-3.0.17=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DOPENSSL_PIC -DOPENSSL_BUILDING_OPENSSL -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPUINFO&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;OPENSSL_armcap=0xbd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;The &amp;#39;numbers&amp;#39; are in 1000s of bytes per second processed.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;AES-128-GCM       4034.58k    15640.53k    56530.54k   160954.65k   387470.64k   430323.84k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Speed test AES-256-GCM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;root@smart-sfp:~# openssl speed -evp aes-256-gcm      &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-256-GCM for 3s on 16 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;735862&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-256-GCM&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-256-GCM for 3s on 64 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;712262&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-256-GCM&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-256-GCM for 3s on 256 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;632462&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-256-GCM&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-256-GCM for 3s on 1024 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;417102&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-256-GCM&amp;#39;s in 3.00s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-256-GCM for 3s on 8192 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;125089&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-256-GCM&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing AES-256-GCM for 3s on 16384 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;69521&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;AES-256-GCM&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3.0.17&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;built on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Tue Aug  5 07:09:41 2025 UTC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;options&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bn(64,64)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;compiler&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gcc -fPIC -pthread -Wa,--noexecstack -Wall -fzero-call-used-regs=used-gpr -DOPENSSL_TLS_SECURITY_LEVEL=2 -Wa,--noexecstack -g -O2 -ffile-prefix-map=/build/reproducible-path/openssl-3.0.17=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DOPENSSL_PIC -DOPENSSL_BUILDING_OPENSSL -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPUINFO&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;OPENSSL_armcap=0xbd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;The &amp;#39;numbers&amp;#39; are in 1000s of bytes per second processed.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;AES-256-GCM       3937.72k    15245.74k    54150.59k   142370.82k   342718.76k   380947.18k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Speed test ChaCha20-Poly1305&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;root@smart-sfp:~# openssl speed -evp chacha20-poly1305&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing ChaCha20-Poly1305 for 3s on 16 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5122281&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;ChaCha20-Poly1305&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing ChaCha20-Poly1305 for 3s on 64 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2859045&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;ChaCha20-Poly1305&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing ChaCha20-Poly1305 for 3s on 256 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1448219&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;ChaCha20-Poly1305&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing ChaCha20-Poly1305 for 3s on 1024 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;457043&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;ChaCha20-Poly1305&amp;#39;s in 3.00s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing ChaCha20-Poly1305 for 3s on 8192 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;60887&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;ChaCha20-Poly1305&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Doing ChaCha20-Poly1305 for 3s on 16384 size blocks&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30481&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;ChaCha20-Poly1305&amp;#39;s in 2.99s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3.0.17&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;built on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Tue Aug  5 07:09:41 2025 UTC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;options&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;bn(64,64)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;compiler&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gcc -fPIC -pthread -Wa,--noexecstack -Wall -fzero-call-used-regs=used-gpr -DOPENSSL_TLS_SECURITY_LEVEL=2 -Wa,--noexecstack -g -O2 -ffile-prefix-map=/build/reproducible-path/openssl-3.0.17=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DOPENSSL_PIC -DOPENSSL_BUILDING_OPENSSL -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPUINFO&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;OPENSSL_armcap=0xbd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;The &amp;#39;numbers&amp;#39; are in 1000s of bytes per second processed.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ChaCha20-Poly1305    27410.20k    61196.95k   123994.67k   156004.01k   166818.16k   167023.65k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Final results for your comparison:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;The &amp;#39;numbers&amp;#39; are in 1000s of bytes per second processed.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;type               16 bytes     64 bytes    256 bytes    1024 bytes   8192 bytes   16384 bytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;AES-128-GCM         4034.58k    15640.53k    56530.54k   160954.65k   387470.64k   430323.84k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;AES-256-GCM         3937.72k    15245.74k    54150.59k   142370.82k   342718.76k   380947.18k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ChaCha20-Poly1305  27410.20k    61196.95k   123994.67k   156004.01k   166818.16k   167023.65k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Setting up a Home ISP with GPON (and CData)</title>
      <link>https://www.apalrd.net/posts/2025/isp_gpon/</link>
      <pubDate>Fri, 03 Oct 2025 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2025/isp_gpon/</guid>
      <description>Today I&amp;rsquo;m setting up a GPON network in my homelab. GPON is the ITU&amp;rsquo;s Gigabit-class Passive Optical Network technology, one of the most commonly deployed fiber to the home technologies. While it&amp;rsquo;s being replaced by its faster descendant XGS-PON, it&amp;rsquo;s still capable of 2.44Gbps down / 1.22Gbps up across 128 clients, all using only passive optical components between the headend (OLT) and clients (ONU).
I&amp;rsquo;ve got a single-port Optical Line Terminal (OLT) made by CData, as well as 8x client Optical Network Units (ONU) also made by CData.</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m setting up a GPON network in my homelab. GPON is the ITU&amp;rsquo;s Gigabit-class Passive Optical Network technology, one of the most commonly deployed fiber to the home technologies. While it&amp;rsquo;s being replaced by its faster descendant XGS-PON, it&amp;rsquo;s still capable of 2.44Gbps down / 1.22Gbps up across 128 clients, all using only passive optical components between the headend (OLT) and clients (ONU).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve got a single-port Optical Line Terminal (OLT) made by CData, as well as 8x client Optical Network Units (ONU) also made by CData. Big thanks to CData for providing the equipment for this project!&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/sKBoO0eRAJY&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2025/isp_gpon/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;cdata-olt-config&#34;&gt;CData OLT Config&lt;/h1&gt;
&lt;p&gt;You can also download the config as a file &lt;a href=&#34;https://www.apalrd.net/posts/2025/isp_gpon/config_final.txt&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sysname FD1601S-B1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;traffic-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; profile-name resi-1000-down cir &lt;span style=&#34;color:#ae81ff&#34;&gt;512000&lt;/span&gt; pir &lt;span style=&#34;color:#ae81ff&#34;&gt;1024000&lt;/span&gt; cbs &lt;span style=&#34;color:#ae81ff&#34;&gt;10240000&lt;/span&gt; pbs &lt;span style=&#34;color:#ae81ff&#34;&gt;10240000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;traffic-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; profile-name resi-1000-up cir &lt;span style=&#34;color:#ae81ff&#34;&gt;256000&lt;/span&gt; pir &lt;span style=&#34;color:#ae81ff&#34;&gt;1024000&lt;/span&gt; cbs &lt;span style=&#34;color:#ae81ff&#34;&gt;8194000&lt;/span&gt; pbs &lt;span style=&#34;color:#ae81ff&#34;&gt;10240000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;traffic-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; profile-name resi-200-down cir &lt;span style=&#34;color:#ae81ff&#34;&gt;102400&lt;/span&gt; pir &lt;span style=&#34;color:#ae81ff&#34;&gt;204800&lt;/span&gt; cbs &lt;span style=&#34;color:#ae81ff&#34;&gt;3278800&lt;/span&gt; pbs &lt;span style=&#34;color:#ae81ff&#34;&gt;6555600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;traffic-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; profile-name resi-200-up cir &lt;span style=&#34;color:#ae81ff&#34;&gt;51200&lt;/span&gt; pir &lt;span style=&#34;color:#ae81ff&#34;&gt;102400&lt;/span&gt; cbs &lt;span style=&#34;color:#ae81ff&#34;&gt;1640400&lt;/span&gt; pbs &lt;span style=&#34;color:#ae81ff&#34;&gt;3278800&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dba-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; profile-name dba-profile_0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  type1 fix &lt;span style=&#34;color:#ae81ff&#34;&gt;256&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dba-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; profile-name dba-profile_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  type3 assure &lt;span style=&#34;color:#ae81ff&#34;&gt;56000&lt;/span&gt; max &lt;span style=&#34;color:#ae81ff&#34;&gt;1024000&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dba-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; profile-name dba-service-100
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  type3 assure &lt;span style=&#34;color:#ae81ff&#34;&gt;25600&lt;/span&gt; max &lt;span style=&#34;color:#ae81ff&#34;&gt;102400&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dba-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; profile-name dba-service-500
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  type3 assure &lt;span style=&#34;color:#ae81ff&#34;&gt;25600&lt;/span&gt; max &lt;span style=&#34;color:#ae81ff&#34;&gt;512000&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dba-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; profile-name dba-service-1000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  type3 assure &lt;span style=&#34;color:#ae81ff&#34;&gt;30720&lt;/span&gt; max &lt;span style=&#34;color:#ae81ff&#34;&gt;1024000&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont-line-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; profile-name line-profile_0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#tcont 0 dba-profile-id 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#tcont 1 dba-profile-id 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#gem add 1 tcont 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;#gem mapping 1 1 vlan 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont-line-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; profile-name line-resi1000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#tcont 0 dba-profile-id 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#tcont 1 dba-profile-id 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#gem add 1 tcont 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;#gem mapping 1 1 vlan transparent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    no gem mapping &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gem delete &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gem add &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; encrypt disable gem-car-upstream &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; gem-car-downstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gem mapping &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont-line-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; profile-name line-resi200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#tcont 0 dba-profile-id 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#tcont 1 dba-profile-id 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#gem add 1 tcont 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;#gem mapping 1 1 vlan transparent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    no gem mapping &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gem delete &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gem add &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; encrypt disable gem-car-upstream &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; gem-car-downstream &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gem mapping &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ipconfig-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; profile-name ipconfig-profile_0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#service internet &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#nat enable &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont-srv-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; profile-name srv-profile_0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#ont-port eth adaptive pots adaptive catv adaptive wifi adaptive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;18&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont-srv-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; profile-name srv-resi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont-port eth adaptive pots adaptive catv adaptive 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port native-vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;18&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  port vlan eth &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; transparent 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont-sipagent-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; profile-name sipagent-profile_0 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont-digitmap-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; profile-name digitmap-profile_0 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont-siprightflag-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; profile-name sipright-profile_0 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont-pots-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; profile-name pots-profile_0 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont mult-srv-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; profile-name default-mult-srv-profile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont-line-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont-srv-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont mult-srv-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; profile-name resi1000-srv-profile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont-line-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont-srv-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ont mult-srv-profile gpon profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; profile-name resi-200-srv-profile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont-line-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont-srv-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; commit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vlan 1-2,20-30,69,666,1000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;radius 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tacacs+ 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user name root password *#*!#/&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;zW*+C-J/J123 privilege-level &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user name admin password *#*!#/&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;zW*+C-J/J123 privilege-level &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user name operator password *#*!#/&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;zW*+C-J/J123 privilege-level &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user name guest password *#*$N&amp;amp;C&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Ho+U0.lp&lt;span style=&#34;color:#ae81ff&#34;&gt;\2&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; privilege-level &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;aaa 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; domain default
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  aaa_protocol radius 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;interface mgmt 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ip address 192.168.1.100 &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;interface gpon 0/0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; flow-control &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; disable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; frame-max &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;9600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont authmode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; auto 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont policy-auth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; match any sn-auth to mult-srv-profile profile-name default-mult-srv-profile priority &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont policy-auth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; match any sn-auth to mult-srv-profile profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; priority &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont add &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; sn-auth &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CDTCAF53E6E3&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont ont-port &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; eth adaptive pots adaptive catv adaptive iphost adaptive wifi adaptive 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mac-learning &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; enable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mac-aging &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont veip &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; trunk 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont loopdetect &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; disable detect-frequency &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt; resume-interval &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt; auto-shutdown enable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont native-vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; concern 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont multicast mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; unconcern 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont port native-vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont port vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; dba-profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; dba-profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mapping-mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont gemport &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; gem-car-upstream &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; gem-car-downstream &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; encrypt disable priority-queue-upstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; priority-queue-downstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont gemport mapping &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont fec &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; disable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont omcc encrypt &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; disable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont qos-mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; priority-queue 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont add &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; sn-auth &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CDTCAF53E6DF&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont ont-port &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; eth adaptive pots adaptive catv adaptive iphost adaptive wifi adaptive 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mac-learning &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; enable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mac-aging &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont veip &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; trunk 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont loopdetect &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; disable detect-frequency &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt; resume-interval &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt; auto-shutdown enable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont native-vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; concern 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont multicast mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; unconcern 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont port native-vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont port vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; dba-profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; dba-profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mapping-mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; vlan 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont gemport &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; gem-car-upstream &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; gem-car-downstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; encrypt disable priority-queue-upstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; priority-queue-downstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont gemport mapping &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont fec &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; disable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont omcc encrypt &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; disable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont qos-mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; priority-queue 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont add &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; sn-auth &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CDTCAF53E6E1&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont ont-port &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; eth adaptive pots adaptive catv adaptive iphost adaptive wifi adaptive 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mac-learning &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; enable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mac-aging &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont veip &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; trunk 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont loopdetect &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; disable detect-frequency &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt; resume-interval &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt; auto-shutdown enable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont native-vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; concern 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont multicast mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; unconcern 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont port native-vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont port vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; dba-profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; dba-profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mapping-mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; vlan 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont gemport &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; gem-car-upstream &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; gem-car-downstream &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; encrypt disable priority-queue-upstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; priority-queue-downstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont gemport mapping &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont fec &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; disable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont omcc encrypt &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; disable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont qos-mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; priority-queue 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ont add &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; sn-auth &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CDTCAF53E6DD&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont ont-port &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; eth adaptive pots adaptive catv adaptive iphost adaptive wifi adaptive 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mac-learning &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; enable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mac-aging &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont veip &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; trunk 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont loopdetect &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; disable detect-frequency &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt; resume-interval &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt; auto-shutdown enable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont native-vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; concern 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont multicast mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; unconcern 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont port native-vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont port vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; eth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; dba-profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; dba-profile-id &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont mapping-mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; vlan 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont gemport &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; tcont &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; gem-car-upstream &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; gem-car-downstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; encrypt disable priority-queue-upstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; priority-queue-downstream &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont gemport mapping &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; vlan &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont fec &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; disable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont omcc encrypt &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; disable 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ont qos-mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; priority-queue 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;interface ge 0/0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;interface xge 0/0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; frame-max &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;9600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; vlan mode &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; trunk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; vlan trunk &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 20-30,69
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# DHCP snooping config &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;! 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# DHCP security-table config &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;! 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# DHCP ipsg config &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;interface vlanif &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; description vlan-lan 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ip address 192.168.0.4 &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;timezone gmt+ 02:00 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;snmp-agent community read */*puhcfl 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;snmp-agent community write */*pxfydqe 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;snmp-agent community write */*LoxxelqBox|eHdqqexv&lt;span style=&#34;color:#ae81ff&#34;&gt;\q&lt;/span&gt;dpce 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;service telnet enable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;service ssh enable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;service http enable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;service https enable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;service snmp disable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;end
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;mikrotik-bng-config&#34;&gt;Mikrotik BNG Config&lt;/h1&gt;
&lt;p&gt;You can also download the config as a file &lt;a href=&#34;https://www.apalrd.net/posts/2025/isp_gpon/config_final.rsc&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 2025-09-27 15:34:10 by RouterOS 7.20rc1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# software id = XB52-1V8V&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# model = CRS305-1G-4S+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# serial number = HHB0A3N8HRP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface bridge
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add admin-mac&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;F4:1E:57:74:FD:8E auto-mac&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    vlan-filtering&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface vlan
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust-com vlan-id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust1 vlan-id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust2 vlan-id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust3 vlan-id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust4 vlan-id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-iptv vlan-id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;69&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-lan vlan-id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip pool
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pool-cust-com ranges&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.0.100-100.64.0.254
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pool-cust1 ranges&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.1.100-100.64.1.254
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pool-cust2 ranges&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.2.100-100.64.2.254
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pool-cust3 ranges&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.3.100-100.64.3.254
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pool-cust4 ranges&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.4.100-100.64.4.254
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip dhcp-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address-pool&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pool-cust-com interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust-com name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;dhcp4-cust-com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface bridge port
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add bridge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf frame-types&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    admit-only-untagged-and-priority-tagged interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ether1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add bridge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;sfp-sfpplus1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add bridge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;sfp-sfpplus2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add bridge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;sfp-sfpplus3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add bridge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;sfp-sfpplus4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip neighbor discovery-settings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set discover-interface-list&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface bridge vlan
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add bridge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge tagged&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;sfp-sfpplus3,sfp-sfpplus2 vlan-ids&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;20-30,69
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip address
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.0.1/24 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust-com network&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.1.1/24 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust1 network&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.1.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.2.1/24 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust2 network&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.2.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.3.1/24 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust3 network&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.3.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.4.1/24 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust4 network&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.4.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.69.2/24 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-iptv network&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.69.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip dhcp-client
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-lan
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip dhcp-server network
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;100.64.0.0/24 dns-server&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.0.3 domain&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;apalrd.fi gateway&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    100.64.0.1 netmask&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; ntp-none&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip firewall nat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;masquerade chain&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;srcnat out-interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-lan src-address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    100.64.0.0/10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ipv6 route
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add disabled&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no distance&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; dst-address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;64:ff9b::/96 gateway&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    fe80::be24:11ff:fed7:e52d%vlan-lan pref-src&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; routing-table&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;main scope&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt; suppress-hw-offload&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no target-scope&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add disabled&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no distance&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; dst-address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;::/0 gateway&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    fe80::10:18ff:fe48:74c%vlan-lan pref-src&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; routing-table&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;main scope&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    suppress-hw-offload&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no target-scope&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ipv6 address
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;2001:db8:420:6944::9 advertise&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-lan
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# address pool error: pool not found: pd-pool1 (4)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;::1 from-pool&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pd-pool1 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust-com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# address pool error: pool not found: pd-pool1 (4)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;::1 from-pool&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pd-pool1 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# address pool error: pool not found: pd-pool1 (4)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;::1 from-pool&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pd-pool1 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# address pool error: pool not found: pd-pool1 (4)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;::1 from-pool&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pd-pool1 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# address pool error: pool not found: pd-pool1 (4)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;::1 from-pool&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pd-pool1 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ipv6 dhcp-client
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-lan pool-name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pd-pool1 prefix-hint&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;::/59 request&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    address,prefix
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ipv6 dhcp-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address-pool&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pd-pool1 interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-cust-com name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;dhcp-cust-com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ipv6 firewall nat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;src-nat chain&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;srcnat out-interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vlan-lan src-address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    2001:db8:420:6920::/59 to-address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    2001:db8:420:6900:e203:18ab:6c15:dbe4/128
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ipv6 nd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; find default&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; dns&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;2001:db8:420:6900:be24:11ff:fe19:afa6 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    managed-address-configuration&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes pref64&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;64:ff9b::/96 ra-interval&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;5s-10s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/system clock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set time-zone-name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Europe/Helsinki
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/system package update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set channel&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;testing
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Setting up a Postmarks server for the Fediverse</title>
      <link>https://www.apalrd.net/posts/2025/fedi_postmarks/</link>
      <pubDate>Fri, 05 Sep 2025 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2025/fedi_postmarks/</guid>
      <description>Today I&amp;rsquo;m bringing my shared bookmarks to the Fediverse: @bookmarks@mark.apalrd.net
It&amp;rsquo;s a list of things that I like, basically. I hope to post links to lesser-known content creators or content that I really enjoy. The hope is that if you enjoy my content, that you might enjoy the things that I enjoy as well.
Hopefully this brings you things that The Algorithm normally might not.
So, anyway, how do you run the server?</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m bringing my shared bookmarks to the Fediverse: @bookmarks@mark.apalrd.net&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a list of things that I like, basically. I hope to post links to lesser-known content creators or content that I really enjoy. The hope is that if you enjoy my content, that you might enjoy the things that I enjoy as well.&lt;/p&gt;
&lt;p&gt;Hopefully this brings you things that The Algorithm normally might not.&lt;/p&gt;
&lt;p&gt;So, anyway, how do you run the server?&lt;/p&gt;
&lt;h1 id=&#34;content&#34;&gt;Content&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/fedi_postmarks/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/fedi_postmarks/#server&#34;&gt;Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/fedi_postmarks/#postmarks&#34;&gt;Postmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/fedi_postmarks/#systemd&#34;&gt;Systemd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/fedi_postmarks/#caddy&#34;&gt;Caddy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/u9y3bwpouVI&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2025/fedi_postmarks/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;server&#34;&gt;Server&lt;/h1&gt;
&lt;p&gt;I ran this in a LXC container based on the latest Debian (Trixie). I&amp;rsquo;m hosting it in my environment, you can host it on a VPS or your own environment, whatever you want.&lt;/p&gt;
&lt;p&gt;Postmarks&amp;rsquo;s official docker image is using the extremely outdated Node.js 16, so I&amp;rsquo;ve used the oldest still supported version (18) to hopefully not break all this node shit, which has super picky version dependencies. It seems to be fine currently.&lt;/p&gt;
&lt;p&gt;After doing the usual system upgrades (&lt;code&gt;apt update &amp;amp;&amp;amp; apt upgrade -y&lt;/code&gt;), I install the tools we will need:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install nodesource&amp;#39;s repo key to add node.js repositories&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /usr/share/keyrings/nodesource.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod &lt;span style=&#34;color:#ae81ff&#34;&gt;644&lt;/span&gt; /usr/share/keyrings/nodesource.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Add repo for Nodesourde node.js 18&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb [arch=amd64 signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main&amp;#34;&lt;/span&gt; | tee /etc/apt/sources.list.d/nodesource.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Apt update, since we added a repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install packages we need&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install nodejs npm git sudo -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;postmarks&#34;&gt;Postmarks&lt;/h1&gt;
&lt;p&gt;You can find the official instructions &lt;a href=&#34;https://github.com/ckolderup/postmarks&#34;&gt;Here&lt;/a&gt;. I&amp;rsquo;m not deviating from this, I&amp;rsquo;m adding to it&lt;/p&gt;
&lt;p&gt;Now that the base software is installed, I&amp;rsquo;m going to git clone Postmarks into my web directory, change ownership to Mark, and then login as &lt;code&gt;mark&lt;/code&gt; to do the final configuration and testing.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Create a new user for the service to run as&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;useradd -m -U mark
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Clone Postmarks into service location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /var
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/ckolderup/postmarks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Change ownership to mark&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R mark:mark postmarks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd postmarks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can login as mark: &lt;code&gt;sudo -u mark bash&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;As mark, we need to create our &lt;code&gt;.env&lt;/code&gt; file. Here&amp;rsquo;s my file, choose your own passwords (and read the Postmarks readme for information on what these mean):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PUBLIC_BASE_URL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;mark.apalrd.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ADMIN_KEY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;CorrectHorseBatteryStaple
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SESSION_SECRET&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;CorrectHorseBatteryStaple
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PORT&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOST&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;::1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m using Caddy as a reverse proxy to handle TLS termination, HTTP/3, and cert management, among other things, so we will run Postmarks on its own bound to localhost only. As of this writing, this hasn&amp;rsquo;t merged into main yet, but it&amp;rsquo;s on my fork if you want to use my fork for now.&lt;/p&gt;
&lt;p&gt;After the env file, you also need to copy &lt;code&gt;account.json.example&lt;/code&gt; into &lt;code&gt;account.json&lt;/code&gt; and edit it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp account.json.example account.json
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nano account.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The instructions for what to do are on the Postmarks github, but this is more customization and entirely optional.&lt;/p&gt;
&lt;p&gt;And finally we need to run npm install: &lt;code&gt;npm install&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And you can use &lt;code&gt;exit&lt;/code&gt; to get out of the user mark&lt;/p&gt;
&lt;h1 id=&#34;systemd&#34;&gt;Systemd&lt;/h1&gt;
&lt;p&gt;Here&amp;rsquo;s the systemd unit I am using (&lt;code&gt;/etc/systemd/system/postmarks.service&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Postmarks bookmarking service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;network-online.target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;mark
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Group&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;mark
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WorkingDirectory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/var/postmarks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;npm run start
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Restart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;always
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then you can run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now postmarks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and the service should be up!&lt;/p&gt;
&lt;h1 id=&#34;caddy&#34;&gt;Caddy&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;m using Caddy for TLS termination, to provide HTTP/2 and HTTP/3, and automatic TLS. This isn&amp;rsquo;t a full guide to Caddy, but here&amp;rsquo;s a bit to get you started:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Debian packages a very old version, so use Caddy&amp;#39;s repos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# These instructions come straight from Caddy&amp;#39;s site&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# https://caddyserver.com/docs/install#debian-ubuntu-raspbian&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -1sLf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://dl.cloudsmith.io/public/caddy/stable/gpg.key&amp;#39;&lt;/span&gt; | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -1sLf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt&amp;#39;&lt;/span&gt; | tee /etc/apt/sources.list.d/caddy-stable.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod o+r /etc/apt/sources.list.d/caddy-stable.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install caddy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here is my Caddyfile (`/etc/caddy/Caddyfile):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The Caddyfile is an easy way to configure your Caddy web server.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mark.apalrd.net &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;# Reverse proxy mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    reverse_proxy localhost:3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Enable TLS but use self-signed cert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tls internal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And restart Caddy: &lt;code&gt;systemctl restart caddy&lt;/code&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Netbox: The Network Source of Truth</title>
      <link>https://www.apalrd.net/posts/2025/iaac_netbox/</link>
      <pubDate>Wed, 23 Apr 2025 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2025/iaac_netbox/</guid>
      <description>Today I&amp;rsquo;m diving into Netbox, a tool designed to help you keep track of your network infrastructure. Netbox is a database of relationships, showing you what is connected where, all of your equipment, IP addresses and prefixes, etc.
We&amp;rsquo;ve got a LOT to install today! So hold on tight and follow along. Probably also want to do an apt update &amp;amp;&amp;amp; apt full-upgrade -y before we start just to make sure the sytem is fully up to date.</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m diving into Netbox, a tool designed to help you keep track of your network infrastructure. Netbox is a database of relationships, showing you what is connected where, all of your equipment, IP addresses and prefixes, etc.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve got a LOT to install today! So hold on tight and follow along. Probably also want to do an &lt;code&gt;apt update &amp;amp;&amp;amp; apt full-upgrade -y&lt;/code&gt; before we start just to make sure the sytem is fully up to date.&lt;/p&gt;
&lt;p&gt;If you want to do one big apt install and skip the rest, here it is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Update&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install everything&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y sudo postgresql redis-server python3 python3-pip python3-venv python3-dev build-essential libxml2-dev libxslt1-dev libffi-dev libpq-dev libssl-dev zlib1g-dev git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Does not include Caddy and their repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/iaac_netbox/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/iaac_netbox/#postgres&#34;&gt;Postgres&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/iaac_netbox/#redis&#34;&gt;Redis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/iaac_netbox/#netbox&#34;&gt;Netbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/iaac_netbox/#gunicorn&#34;&gt;Gunicorn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/iaac_netbox/#caddy&#34;&gt;Caddy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/p3J3f2QWFGE&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2025/iaac_netbox/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;postgres&#34;&gt;Postgres&lt;/h2&gt;
&lt;p&gt;First install it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y postgresql sudo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, login as the postgres user (&lt;code&gt;sudo -u postgres psql&lt;/code&gt;) and run this SQL to create the database. You need to copy these commands one at a time into the prompt! I&amp;rsquo;ve added a line break each time you need to copy separately!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ALTER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;database&lt;/span&gt; template1 is_template&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;DROP&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;database&lt;/span&gt; template1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;DATABASE&lt;/span&gt; template1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WITH&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;OWNER&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;ENCODING&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;UTF8&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   TABLESPACE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pg_default
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   LC_COLLATE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;en_US.UTF-8&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   LC_CTYPE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;en_US.UTF-8&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;CONNECTION&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;LIMIT&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;TEMPLATE&lt;/span&gt; template0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ALTER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;database&lt;/span&gt; template1 is_template&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;DATABASE&lt;/span&gt; netbox;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;USER&lt;/span&gt; netbox &lt;span style=&#34;color:#66d9ef&#34;&gt;WITH&lt;/span&gt; PASSWORD &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;CorrectHorseBatteryStaple&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ALTER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;DATABASE&lt;/span&gt; netbox &lt;span style=&#34;color:#66d9ef&#34;&gt;OWNER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TO&lt;/span&gt; netbox;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;connect&lt;/span&gt; netbox;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;GRANT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;SCHEMA&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TO&lt;/span&gt; netbox;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;q
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Whew! First step done&lt;/p&gt;
&lt;h2 id=&#34;redis&#34;&gt;Redis&lt;/h2&gt;
&lt;p&gt;Now more stuff to install!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y redis-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can test it with &lt;code&gt;redis-cli ping&lt;/code&gt; but that&amp;rsquo;s it, it&amp;rsquo;s done&lt;/p&gt;
&lt;h2 id=&#34;netbox&#34;&gt;Netbox&lt;/h2&gt;
&lt;p&gt;More shell stuff to copy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install everything we need&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y python3 python3-pip python3-venv python3-dev build-essential libxml2-dev libxslt1-dev libffi-dev libpq-dev libssl-dev zlib1g-dev git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Clone netbox into its new home (master should have latest stable release)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /opt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone -b main --depth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; https://github.com/netbox-community/netbox.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create a system user for netbox to run as&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adduser --system --group netbox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Chown netbox subdir&amp;#39;s to Netbox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R netbox /opt/netbox/netbox/&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;media,reports,scripts&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy example config as running config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Dear god guys can you stop nesting netbox folders??&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp /opt/netbox/netbox/netbox/configuration_example.py /opt/netbox/netbox/netbox/configuration.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now before we edit the config file, let&amp;rsquo;s generate a random number to use as our secret key (and copy it for later) by running &lt;code&gt;/opt/netbox/netbox/generate_secret_key.py&lt;/code&gt;. Then we can edit the config file (&lt;code&gt;nano /opt/netbox/netbox/netbox/configuration.py&lt;/code&gt;)and change our settings. Here&amp;rsquo;s what I modified (this is a diff):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;--- configuration_example.py
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+++ configuration.py
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -8,15 +8,15 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; # access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; #
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; # Example: ALLOWED_HOSTS = [&amp;#39;netbox.example.com&amp;#39;, &amp;#39;netbox.internal.local&amp;#39;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-ALLOWED_HOSTS = []
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+ALLOWED_HOSTS = [&amp;#39;netbox.palnet.net&amp;#39;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; # PostgreSQL database configuration. See the Django documentation for a complete list of available parameters:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; #   https://docs.djangoproject.com/en/stable/ref/settings/#databases
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; DATABASE = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &amp;#39;ENGINE&amp;#39;: &amp;#39;django.db.backends.postgresql&amp;#39;,  # Database engine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &amp;#39;NAME&amp;#39;: &amp;#39;netbox&amp;#39;,         # Database name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    &amp;#39;USER&amp;#39;: &amp;#39;&amp;#39;,               # PostgreSQL username
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    &amp;#39;PASSWORD&amp;#39;: &amp;#39;&amp;#39;,           # PostgreSQL password
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    &amp;#39;USER&amp;#39;: &amp;#39;netbox&amp;#39;,         # PostgreSQL username
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    &amp;#39;PASSWORD&amp;#39;: &amp;#39;CorrectHorseBatteryStaple&amp;#39;,           # PostgreSQL password
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;     &amp;#39;HOST&amp;#39;: &amp;#39;localhost&amp;#39;,      # Database server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &amp;#39;PORT&amp;#39;: &amp;#39;&amp;#39;,               # Database port (leave blank for default)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &amp;#39;CONN_MAX_AGE&amp;#39;: 300,      # Max database connection age
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -64,7 +64,7 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; # For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; # symbols. NetBox will not run without this defined. For more information, see
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; # https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-SECRET_KEY = &amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+SECRET_KEY = &amp;#39;w!13OYWS!o2Or156)-!Ld^!9BZAKYrGFAeHGV=XnGYuM!!v*hk&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, we can run the actual install script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/netbox/upgrade.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;create-superuser&#34;&gt;Create Superuser&lt;/h3&gt;
&lt;p&gt;Even after installing, we still need to create a superuser for our new site:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;source /opt/netbox/venv/bin/activate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /opt/netbox/netbox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 manage.py createsuperuser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deactivate
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;housekeeping-task&#34;&gt;Housekeeping Task&lt;/h3&gt;
&lt;p&gt;We could create a systemd timer unit for this, but I&amp;rsquo;m tired at this point and just want to get it done. So we are putting this entry in cron.daily:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /opt/netbox/contrib/netbox-housekeeping.sh /etc/cron.daily/netbox-housekeeping
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;test-it&#34;&gt;Test It&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s a way to test it if you want to (you probably should):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;source /opt/netbox/venv/bin/activate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /opt/netbox/netbox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 manage.py runserver &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;::&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;:8000 --insecure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Use Crtl-C to end, log in to port 8000 to make sure it&amp;#39;s up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deactivate
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;gunicorn&#34;&gt;Gunicorn&lt;/h2&gt;
&lt;p&gt;Now we can add the WSGI server, Gunicorn, and its associated systemd service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp /opt/netbox/contrib/gunicorn.py /opt/netbox/gunicorn.py
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp /opt/netbox/contrib/netbox.service /etc/systemd/system
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp /opt/netbox/contrib/netbox-rq.service /etc/systemd/system
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now netbox netbox-rq
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Gunicorn will bind to localhost:8001, which is perfect since we are going to run a reverse proxy to do TLS termination.&lt;/p&gt;
&lt;h2 id=&#34;caddy&#34;&gt;Caddy&lt;/h2&gt;
&lt;p&gt;And now the TLS termination proxy - Caddy. Netbox suggests Apache or Nginx, but I prefer Caddy, so here&amp;rsquo;s my setup:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install from Caddy&amp;#39;s repos (they are more up to date)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Download their deb signing key + their sources.list file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -1sLf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://dl.cloudsmith.io/public/caddy/stable/gpg.key&amp;#39;&lt;/span&gt; | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -1sLf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt&amp;#39;&lt;/span&gt; | sudo tee /etc/apt/sources.list.d/caddy-stable.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Update with new sources&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install Caddy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y caddy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s my &lt;code&gt;/etc/caddy/Caddyfile&lt;/code&gt; (delete everything already in it):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;netbox.palnet.net&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;handle&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/static*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/opt/netbox/netbox/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;file_server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;handle&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#Backend&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;running&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;on&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;8001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;reverse_proxy&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;http:&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//localhost:8001
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#Only&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;you&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;don&amp;#39;t&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;want&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;Let&amp;#39;s&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;Encrypt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;tls&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;internal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#Otherwise&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;you&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;can&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;your&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;email:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#tls&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;adventure@apalrd.net&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we can start it with &lt;code&gt;systemctl enable --now caddy&lt;/code&gt;! If it&amp;rsquo;s already running, then &lt;code&gt;systemctl restart caddy&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;upgrading&#34;&gt;Upgrading&lt;/h2&gt;
&lt;p&gt;When you need to upgrade, checkout master again and run the upgrade script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Go to netbox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /opt/netbox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Pull latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git checkout master
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git pull origin master
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run upgrade&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./upgrade.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Restart services&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl restart netbox netbox-rq caddy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>All Open-Source THREAD Network</title>
      <link>https://www.apalrd.net/posts/2025/ha_thread/</link>
      <pubDate>Wed, 26 Mar 2025 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2025/ha_thread/</guid>
      <description>Today I&amp;rsquo;m taking a deep dive into the Thread protocol! Based on IEEE 802.15.4, Thread is a mesh networking protocol designed to balance the needs of small, battery powered Internet-of-Things devices with the ability to communicate directly on The Internet. By leveraging IPv6 and 6LoWPAN, Thread is able to finally bring these automation networks into the land of the Internet Protocol, where interoperability thrives.
I walk through the setup of an OpenThread Border Router, OpenThread daemon for end devices, and compile the OpenThread Radio Co-Processor for a Nordic Semiconductor NRF52840 dongle, one of the cheapest ways to get started with Thread.</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m taking a deep dive into the Thread protocol! Based on IEEE 802.15.4, Thread is a mesh networking protocol designed to balance the needs of small, battery powered Internet-of-Things devices with the ability to communicate directly on The Internet. By leveraging IPv6 and 6LoWPAN, Thread is able to finally bring these automation networks into the land of the Internet Protocol, where interoperability thrives.&lt;/p&gt;
&lt;p&gt;I walk through the setup of an OpenThread Border Router, OpenThread daemon for end devices, and compile the OpenThread Radio Co-Processor for a Nordic Semiconductor NRF52840 dongle, one of the cheapest ways to get started with Thread.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_thread/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_thread/#dongle-firmware&#34;&gt;Dongle Firmware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_thread/#open-thread-border-router&#34;&gt;OpenThread Border Router&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_thread/#thread-client&#34;&gt;Thread Client&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/D9blNRhtN7k&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2025/ha_thread/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;dongle-firmware&#34;&gt;Dongle Firmware&lt;/h2&gt;
&lt;p&gt;First, we need firmware for our Radio Co-Processor. I&amp;rsquo;m using the Nordic Semi NRF52840 Dongle, using the firmware image provided by Nordic. &lt;a href=&#34;https://docs.nordicsemi.com/bundle/ncs-2.7.0/page/nrf/samples/openthread/coprocessor/README.html&#34;&gt;Here&amp;rsquo;s the guide directly from them&lt;/a&gt;. I setup a small Debian VM on Proxmox using my &lt;a href=&#34;https://www.apalrd.net/posts/2023/pve_cloud/&#34;&gt;cloud-init tutorial&lt;/a&gt; so I could easily pass-through USB devices and run the builds. Since the cloud-init VMs have no hardware support, I also had to install the normal kernel (&lt;code&gt;apt install linux-image-generic -y&lt;/code&gt;) and reboot for it to detect my USB hardware. Nordic&amp;rsquo;s stuff seems to be very picky about Linux versions, it * really * wants Ubuntu 22.04 or 20.04 and not other versions, which is why the steps don&amp;rsquo;t exactly match theirs.&lt;/p&gt;
&lt;p&gt;Anyway, here are the steps to follow:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install -y python3-pip git cmake ninja-build
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Add ourselves to dialout group so we can use the serial port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# NOTE: You may have to log out and back in after this or flashing will fail later&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo usermod -a -G dialout $USER
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# It&amp;#39;s bad form to break system packages, but nordic doesn&amp;#39;t provide us a better option&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip3 install --user -U west --break-system-packages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Download nrfutil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl https://files.nordicsemi.com/artifactory/swtools/external/nrfutil/executables/x86_64-unknown-linux-gnu/nrfutil -o nrfutil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# make executable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod +x nrfutil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Move to location on PATH&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mv nrfutil /usr/local/bin/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install device so we can flash the device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nrfutil install device
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install for pkg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nrfutil install nrf5sdk-tools
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install toolchain-manager so we can manage toolchains&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nrfutil install toolchain-manager
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Show toolchain options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nrfutil toolchain-manager search
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install the latest version (as of this writing, 2.9.1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nrfutil toolchain-manager install --ncs-version v2.9.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Make a subdir for us to work in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p nrfbuild
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd nrfbuild
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Clone the repo at main (possibly dangerous, but you could choose a release tag instead)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 -m west init -m https://github.com/nrfconnect/sdk-nrf --mr main
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# such as this tag&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#west init -m https://github.com/nrfconnect/sdk-nrf --mr v2.9.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Make west download dependencies (this is very slow)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 -m west update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 -m west zephyr-export
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Go to the RCP folder and compile it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd nrf/samples/openthread/coprocessor
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Launch into nrfutil toolchain environment (this sets up env vars)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nrfutil toolchain-manager launch --shell
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point, you are in the coprocessor folder in the nrfutil shell. I stopped you here so you realize that you need to copy/paste again, in this new shell, and not in the other shell.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# -p means &amp;#39;pristine&amp;#39; so it will start from scratch, in case you ran it before with errors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;west build -b nrf52840dongle/nrf52840 -p
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Technically these don&amp;#39;t need to go in the nrfutil shell, but they work either way&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Package the build for the bootloader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nrfutil pkg generate --hw-version &lt;span style=&#34;color:#ae81ff&#34;&gt;52&lt;/span&gt; --sd-req&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;0x00 --application build/merged.hex --application-version &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; otbr-rcp.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Flash the built onto the device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nrfutil dfu usb-serial -pkg otbr-rcp.zip -p /dev/ttyACM0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want a premade &lt;code&gt;orbr-rcp.zip&lt;/code&gt; file, here&amp;rsquo;s the file I compiled (warning, random internet binaries, YMMV, no warranty, &amp;hellip;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_thread/otbr-rcp.zip&#34;&gt;otbr-rcp.zip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_thread/merged.hex&#34;&gt;merged.hex&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In that case, you &lt;em&gt;just&lt;/em&gt; need the nrfutil tool with &lt;code&gt;device&lt;/code&gt; installed. You can also use their GUI flashing tool for Windows. I included the zip and the hex, some of the flashing tools want the hex instead.&lt;/p&gt;
&lt;h2 id=&#34;open-thread-border-router&#34;&gt;Open Thread Border Router&lt;/h2&gt;
&lt;p&gt;followed &lt;a href=&#34;https://openthread.io/codelabs/openthread-border-router#1&#34;&gt;https://openthread.io/codelabs/openthread-border-router#1&lt;/a&gt;
need to add WEB_GUI=1 before bootstrap and setup (it&amp;rsquo;s not the default on Debian)&lt;/p&gt;
&lt;p&gt;I did this on Debian, this time on a single-board computer. I also tried a Raspberry Pi 4 and 3, and a Debian VM on Proxmox (but not using the cloud kernel!)&lt;/p&gt;
&lt;p&gt;Here are the commands. You need sudo installed, even if you run as root, since OTBR&amp;rsquo;s scripts will use it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Instlll dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install -y git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Clone Open Thread Border Router&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/openthread/ot-br-posix.git --depth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ot-br-posix
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Many of these exports have defaults already&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# However, since they vary wildly for different OSes, I&amp;#39;ve set them here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Enable Routing + Border Routing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export BACKBONE_ROUTER&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export BORDER_ROUTING&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Disable NAT64 and DHCPv6-PD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export NAT64&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export DNS64&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export DHCPV6_PD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export DHCPV6_PD_REF&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Enable the web GUI and REST API&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export WEB_GUI&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export REST_API&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set this to the name of your Ethernet interface to route to&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export INFRA_IF_NAME&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;eth0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Bootstrap environment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./script/bootstrap
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Actually do the build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./script/setup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next we need to edit the UART location (only if you have multiple USB UART devices). You can find your serial devices in &lt;code&gt;/dev/serial/by-id/&lt;/code&gt;, and pointing to those will be more reliable than using &lt;code&gt;/dev/ttyACM0&lt;/code&gt; if you have multiple dongles (i.e. Zigbee, Thread, ..). OpenThread Border Router loads an environment file called &lt;code&gt;/etc/default/otbr-agent&lt;/code&gt; which contains some environment variables, so here&amp;rsquo;s what I started with and ended with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Default settings for otbr-agent. This file is sourced by systemd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Options to pass to otbr-agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OTBR_AGENT_OPTS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-I wpan0 -B ens18 spinel+hdlc+uart:///dev/ttyACM0 trel://ens18&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OTBR_NO_AUTO_ATTACH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and now it&amp;rsquo;s:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Default settings for otbr-agent. This file is sourced by systemd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Options to pass to otbr-agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OTBR_AGENT_OPTS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-I wpan0 -B ens18 spinel+hdlc+uart:///dev/serial/by-id/usb-Nordic_Semiconductor_ASA_Thread_Co-Processor_FB7FFA86E3D48E34-if00 trel://ens18&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OTBR_NO_AUTO_ATTACH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once that&amp;rsquo;s done, you can (re)start the services:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Start the services&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl start otbr-agent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl start otbr-web
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And since I enabled the web UI, you can login on regular http port 80.&lt;/p&gt;
&lt;h2 id=&#34;thread-client&#34;&gt;Thread Client&lt;/h2&gt;
&lt;p&gt;If you want to use Thread instead of Wifi, here&amp;rsquo;s the instructions to build Openthread as an end device (router eligible, but not a border router):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Instlll dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install -y git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Clone Open Thread (not the border router)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/openthread/openthread.git --depth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd openthread
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Bootstrap environment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./script/bootstrap
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Actually do the build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./script/cmake-build posix -DOT_DAEMON&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ON
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we need to start up the daemon:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./build/posix/src/posix/ot-daemon -I wpan0 -v -d &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;spinel+hdlc+uart:///dev/ttyACM0?uart-baudrate=115200&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(That will take the terminal, so login to another SSH session for ot-ctl)&lt;/p&gt;
&lt;p&gt;Next, we can execute &lt;code&gt;./build/posix/src/posix/ot-ctl&lt;/code&gt; which should get us into an OpenThread terminal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;state
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Now we need to copy/paste the dataset from the border router&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# On the BR, run:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# dataset active -x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# then copy the big blob of data,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# on the client, run:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dataset set active &amp;lt;big data blob&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Now bring up the interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ifconfig up
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;thread start
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#And some useful commands for you&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;help
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ipaddr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;netdata show
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;extaddr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I wrote a systemd unit for this guy, so we can install it into &lt;code&gt;/etc/systemd/system/ot-daemon.service&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;Unit&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Description&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;OpenThread&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DAemon&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;After&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;network-online&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;Service&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ExecStart&lt;/span&gt;=&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;usr&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;local&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bin&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ot-daemon&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;-I&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wpan0&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;-d&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;spinel+hdlc+uart:///dev/ttyACM0?uart-baudrate=115200&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Restart&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;Install&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WantedBy&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;multi-user&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also, copy &lt;code&gt;ot-daemon&lt;/code&gt; and &lt;code&gt;ot-ctl&lt;/code&gt; to &lt;code&gt;/usr/local/bin&lt;/code&gt; so they are in a normal binary place to be happy&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Wireguard, OpenVPN, and IPSec for Client VPNs</title>
      <link>https://www.apalrd.net/posts/2025/network_wg_ovpn/</link>
      <pubDate>Thu, 13 Mar 2025 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2025/network_wg_ovpn/</guid>
      <description>Today I&amp;rsquo;m trying to understand if Wireguard really is over-hyped, if OpenVPN is really worth all the hassle to get the user-side features like client authentication and two factor, and if IPSec has any place in the modern VPN landscape. Specifically, looking at traditional &amp;lsquo;road warrior&amp;rsquo; or client access VPNs, where all of your users are dialing in to your enterprise network, not the new-fangled mesh VPNs or zero trust setups.</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m trying to understand if Wireguard really is over-hyped, if OpenVPN is really worth all the hassle to get the user-side features like client authentication and two factor, and if IPSec has any place in the modern VPN landscape. Specifically, looking at traditional &amp;lsquo;road warrior&amp;rsquo; or client access VPNs, where all of your users are dialing in to your enterprise network, not the new-fangled mesh VPNs or zero trust setups.&lt;/p&gt;
&lt;p&gt;This page contains all of the configurations I used in testing, feel free to use them on your own. I did all of my testing on Debian 13 (Trixie) which is currently in testing, on Linux 6.12. My clients are also running the same OS/kernel.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#beginning&#34;&gt;Beginning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#ipip&#34;&gt;IPIP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#wireguard&#34;&gt;Wireguard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#openvpn&#34;&gt;OpenVPN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#certificates&#34;&gt;OpenVPN - Certificates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#server&#34;&gt;OpenVPN - Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#client&#34;&gt;OpenVPN - Client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#dco&#34;&gt;OpenVPN - DCO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#ipsec&#34;&gt;IPSec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#strongswan-server&#34;&gt;IPSec - Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/#strongswan-client&#34;&gt;IPSec - Client&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/LmaPT7_T87g&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2025/network_wg_ovpn/thumbnail1.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;beginning&#34;&gt;Beginning&lt;/h2&gt;
&lt;p&gt;We need to enable IP forwarding on our router for any of these setups. This doesn&amp;rsquo;t persist across reboots, but most of my configs on this page are not intended to.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Enable Forwarding&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &amp;gt; /proc/sys/net/ipv6/conf/all/forwarding
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;ipip&#34;&gt;IPIP&lt;/h2&gt;
&lt;p&gt;No install here. Just copy the commands and change the IPs as necessary. client is given 2001:db8:7:a::/64 in this example with the router taking the first address for itself, Enterprise subnet is 2001:db8:7::/48 in this example, Public IPs must be hardcoded for IPIP (cannot be dynamic).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# IPIP Setup (on Client)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip link add name ipip6 type ip6tnl local &amp;lt;client IP&amp;gt; remote &amp;lt;server IP&amp;gt; mode any
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip link set up ipip6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip addr add 2001:db8:7:a::2/64 dev ipip6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip -6 route add 2001:db8:7::/48 dev ipip6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# IPIP Setup (on Server)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip link add name ipip6 type ip6tnl local &amp;lt;server IP&amp;gt; remote &amp;lt;client IP&amp;gt; mode any
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip link set up ipip6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip addr add 2001:db8:7:a::/64 dev ipip6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#addr add implicitly adds a /64 route to that interface, so no other routes required&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;wireguard&#34;&gt;Wireguard&lt;/h2&gt;
&lt;p&gt;First we install it (&lt;code&gt;apt install wireguard&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;Next, we need to create keys on each nodes, so run this command on both sides:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Gen private key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wg genkey | tee /etc/wireguard/server.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Gen public key from private key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat /etc/wireguard/server.key | wg pubkey | tee /etc/wireguard/server.pub
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# You will need these two keys later, so be ready to copy and paste them&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we need a &lt;code&gt;/etc/wireguard/wg0.conf&lt;/code&gt; on both nodes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Conf for SERVER side&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;Interface&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;PrivateKey&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;oBic4cnZOBjmucL10dtiB5QZpUkqPPjEm9rA6E90iUg&lt;/span&gt;=
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Address&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;2001&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;db8&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;::/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;128&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ListenPort&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;51820&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Peer (CLIENT&amp;#39;s public key here)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;Peer&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;PublicKey&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b0J0WcCObEOq0R9zIQoitRa6I4YqLDDL7evmNwN3Go&lt;/span&gt;=
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;AllowedIPs&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;2001&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;db8&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;::/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Endpoint&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;testsrc2&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;palnet&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;net&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;51820&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Conf for CLIENT side&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;Interface&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;PrivateKey&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;qKUMygkE&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;YPWE2MmdCOi5j6Sno78&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;w9FvXHGTIVpoVU&lt;/span&gt;=
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Address&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;2001&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;db8&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ListenPort&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;51820&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Peer (SERVER&amp;#39;s public key here)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;Peer&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;PublicKey&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;VIGy0JS27RjGI9VDug2iNK4dd&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Ned9dNDnlCOP1DTQ&lt;/span&gt;=
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;AllowedIPs&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;2001&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;db8&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;::/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;48&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Endpoint&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;wgmetal&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;palnet&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;net&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;51820&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then bring up the interfaces (&lt;code&gt;wg-quick up wg0&lt;/code&gt; on both sides). WG will automatically brign up the route to our enterprise subnet, and it will work.&lt;/p&gt;
&lt;h2 id=&#34;openvpn&#34;&gt;OpenVPN&lt;/h2&gt;
&lt;p&gt;First we install it (&lt;code&gt;apt install openvpn&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&#34;certificates&#34;&gt;Certificates&lt;/h3&gt;
&lt;p&gt;We will be using cert auth here, so we need an x.509 cert for both sides.
For simplicity, I&amp;rsquo;m using self-signed ECDSA certs using prime256v1 for leafs and scep384 for the CA&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate private key using scep384:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl ecparam -name secp384r1 -genkey -out root.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign the root certificate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Pathlen:0 means there can be only one more cert below this CA (no more CAs)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make sure you update the subj name with your own names&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#C=US is also the country, it&amp;#39;s optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#O= is the organization, also optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#CN= is the Common Name and it&amp;#39;s required&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#I also set validity to 69 years, make sure you watch for expiration (manually)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl req -new -key root.key -x509 -nodes -days &lt;span style=&#34;color:#ae81ff&#34;&gt;25202&lt;/span&gt; -out root.pem -subj &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/C=US/O=apalrd.net/CN=openvpn&amp;#34;&lt;/span&gt; -addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;basicConstraints=critical,CA:TRUE,pathlen:0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now you can view it (for fun)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -in root.pem -text -noout
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, generate the server&amp;rsquo;s cert + key&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Change this to the name of your server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export sv&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;wgmetal.palnet.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate scep256 key for this client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you want 192-bit security, use scep384r1 instead of prime256v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl ecparam -name prime256v1 -genkey -out $sv.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate a CSR (certificate signing request) for my new key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#again, C and O are optional, CN is the Common Name of the cert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Allowed only for server auth&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl req -new -key $sv.key -out $sv.csr -subj &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/C=US/O=apalrd.net/CN=&lt;/span&gt;$sv&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;extendedKeyUsage = serverAuth&amp;#34;&lt;/span&gt; --addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;keyUsage = digitalSignature,keyAgreement&amp;#34;&lt;/span&gt; -addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;subjectAltName = DNS:&lt;/span&gt;$sv&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign the CSR using the root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Shorter lived at only 365 days&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -req -in $sv.csr -CA root.pem -CAkey root.key -CAcreateserial -out $sv.crt -days &lt;span style=&#34;color:#ae81ff&#34;&gt;365&lt;/span&gt; -sha256 -copy_extensions&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;copyall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now you can view it (for fun)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -in $sv.crt -text -noout
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, generate the client cert:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Change this to the name of your client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export cl&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;testsrc2.palnet.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate scep256 key for this client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you want 192-bit security, use scep384r1 instead of prime256v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl ecparam -name prime256v1 -genkey -out $cl.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate a CSR (certificate signing request) for my new key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#again, C and O are optional, CN is the Common Name of the cert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl req -new -key $cl.key -out $cl.csr -subj &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/C=US/O=apalrd.net/CN=&lt;/span&gt;$cl&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;extendedKeyUsage = clientAuth&amp;#34;&lt;/span&gt; --addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;keyUsage = digitalSignature,keyAgreement&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign the CSR using the root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign it allowing for server and client auth as the key usage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -req -in $cl.csr -CA root.pem -CAkey root.key -CAcreateserial -out $cl.crt -days &lt;span style=&#34;color:#ae81ff&#34;&gt;365&lt;/span&gt; -sha256 -copy_extensions&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;copyall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now you can view it (for fun)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -in $cl.crt -text -noout
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Transfer your .key and .crt files to the server and client respectively. The server will need its client .key and .crt, and the server will need its server .key and .crt, and they both need root.pem&lt;/p&gt;
&lt;h3 id=&#34;server&#34;&gt;Server&lt;/h3&gt;
&lt;p&gt;The server setup is quite complex. Here&amp;rsquo;s my final &lt;code&gt;/etc/openvpn/server.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#UDP over IPV6 outside of tunnel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;port &lt;span style=&#34;color:#ae81ff&#34;&gt;1194&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;proto udp6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dev tun
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user nobody
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;group nogroup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;persist-key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;persist-tun
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;keepalive &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;120&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;topology subnet
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#IPv6 inside of tunnel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;server-ipv6 2001:db8:7:c::/64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ifconfig-ipv6-pool 2001:db8:7:c::/64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;push &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;route-ipv6 2001:db8:7::/48&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ifconfig-pool-persist ipp.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Crypto parameters&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dh none
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ecdh-curve prime256v1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tls-crypt tls-crypt.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Client verification&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ca root.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cert server.crt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;key server.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;remote-cert-tls client
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# no CRL in my setup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#crl-verify root.pem&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;auth SHA256
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cipher AES-128-GCM
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;data-ciphers AES-128-GCM
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tls-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tls-version-min 1.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tls-cipher TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;client-config-dir /etc/openvpn/ccd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;status /var/log/openvpn/status.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;verb &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also, a few commands to get it started:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openvpn --genkey secret /etc/openvpn/tls-crypt.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /etc/openvpn/ccd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /var/log/openvpn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now openvpn@server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once we&amp;rsquo;ve generated tls-crypt.key we need to copy that file to the client (it&amp;rsquo;s our Shared Secret). We don&amp;rsquo;t * have * to use shared secret auth, but I have here.&lt;/p&gt;
&lt;h3 id=&#34;client&#34;&gt;Client&lt;/h3&gt;
&lt;p&gt;For the client we need a &lt;code&gt;/etc/openvpn/client.conf&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;client
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;remote wgmetal.palnet.net &lt;span style=&#34;color:#ae81ff&#34;&gt;1194&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dev tun
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;resolv-retry infinite
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nobind
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;persist-key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;persist-tun
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;remote-cert-tls server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;verify-x509-name wgmetal.palnet.net name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;auth SHA256
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cipher AES-128-GCM
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;data-ciphers AES-128-GCM
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;auth-nocache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tls-client
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tls-version-min 1.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tls-cipher TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;verb &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Client certs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cert client.crt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;key client.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Server&amp;#39;s CA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ca root.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tls-crypt tls-crypt.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;remote-cert-tls server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a simple command to start:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now openvpn@client
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;dco&#34;&gt;DCO&lt;/h3&gt;
&lt;p&gt;The whole reason for this test is to see if DCO is as performant! And we aren&amp;rsquo;t using DCO just yet. So, here&amp;rsquo;s how to enable it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make sure you are running a kernel version which is in the repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt upgrade -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Reboot if you installed a new kernel here, or linux-headers will not find itself&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y linux-headers-&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;uname -r&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#This will compile the module with DKMS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y openvpn-dco-dkms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;modprobe ovpn-dco-v2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point, restarting the server (or client, it works both ways) should enable DCO. Check the logs (&lt;code&gt;journalctl -xeu openvpn@server&lt;/code&gt;) to make sure.&lt;/p&gt;
&lt;h2 id=&#34;ipsec&#34;&gt;IPSec&lt;/h2&gt;
&lt;p&gt;Oh boy you are in for a fun ride here, we&amp;rsquo;re gonna install Strongswan (&lt;code&gt;apt install -y strongswan&lt;/code&gt;) to get started.&lt;/p&gt;
&lt;h3 id=&#34;strongswan-server&#34;&gt;StrongSwan Server&lt;/h3&gt;
&lt;p&gt;We are gonna need the server&amp;rsquo;s certificate and key from earlier, and since StrongSwan is stupid, we need to convert it to DER format (&lt;code&gt;openssl ec -inform pem -outform der -in server.key -out server.der&lt;/code&gt;). Put the root cert into &lt;code&gt;/etc/ipsec.d/cacerts/root.pem&lt;/code&gt;, the server&amp;rsquo;s cert in &lt;code&gt;/etc/ipsec.d/certs/server.crt&lt;/code&gt;, and the server&amp;rsquo;s DER key in &lt;code&gt;/etc/ipsec.d/private/server.der&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re going to completely erase &lt;code&gt;/etc/ipsec.conf&lt;/code&gt;, you can replace it with my new one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;config setup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    charondebug&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ike 1, knl 1, cfg 0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    uniqueids&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# our ikev2 vpn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conn ikev2-vpn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    auto&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;add
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    compress&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tunnel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    keyexchange&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ikev2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    fragmentation&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    forceencaps&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    dpdaction&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;clear
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    dpddelay&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;300s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rekey&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#left side (idfk why they name it left and right)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#ip to bind to locally&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    left&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;%any
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#this must match the SAN of the certificate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#or, skip the @ and use an IP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    leftid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;@wgmetal.palnet.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#leftid=2001:db8:6969::420&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    leftcert&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;server.crt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    leftsendcert&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;always
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#route to tell the clients&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    leftsubnet&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;2001:db8:7::/48
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#again, no idea why they call them left/right&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#anyway clients can be anything&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    right&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;%any
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rightid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;%any
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#eap-tls would use client certs, but we will do mschap for now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rightauth&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;eap-mschapv2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#address pool for clients&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rightsourceip&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;2001:db8:7:d::/64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#you can assign DNS too if you want&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#rightdns=2620:fe::fe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#set this to never for mschap or always for eap-tls&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rightsendcert&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;never
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#??&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    eap_identity&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;%identity
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#crypto&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#yes, these are no longer recommended in favor of AES 256&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#however I tested OpenVPN with aes128gcm so I wanted to make it fair&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ike&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;aes128gcm16-prfsha256-ecp256
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    esp&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;aes128gcm16-ecp256
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For some reason, StrongSwan doesn&amp;rsquo;t use a file path to a key in the config file. I guess they treat the path itself as secret? Anyway, edit &lt;code&gt;/etc/ipsec.secrets&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# This file holds shared secrets or RSA private keys for authentication.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Our ECDSA private key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ECDSA server.der&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Our admin user accounts (these are plaintext passwords)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;admin &lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;EAP &amp;#34;admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;admin2 &lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;EAP &amp;#34;admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;admin3 &lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;EAP &amp;#34;admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;admin4 &lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;EAP &amp;#34;admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;admin5 &lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;EAP &amp;#34;admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;admin6 &lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;EAP &amp;#34;admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;admin7 &lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;EAP &amp;#34;admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;strongswan-client&#34;&gt;StrongSwan Client&lt;/h3&gt;
&lt;p&gt;The client side is a bit easier. We again need our root certificate (put it in &lt;code&gt;/etc/ipsec.d/cacerts/root.pem&lt;/code&gt;), but not a client cert, since we are doing old fashioned usernames and passwords here.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re going to setup the config for the client (&lt;code&gt;/etc/ipsec.conf&lt;/code&gt;) also:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;config setup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conn ikev2-rw
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    right&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;wgmetal.palnet.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# This should match the `leftid` value on your server&amp;#39;s configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rightid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;%wgmetal.palnet.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rightsubnet&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;::/0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rightauth&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pubkey
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    leftsourceip&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;%config
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    leftid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;admin2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    leftauth&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;eap-mschapv2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    eap_identity&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;admin2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    auto&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we need a &lt;code&gt;ipsec.secrets&lt;/code&gt; file here too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# This file holds shared secrets or RSA private keys for authentication.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Our user account (these are plaintext passwords)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;admin2 &lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;EAP &amp;#34;admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Home Assistant Remote Radio</title>
      <link>https://www.apalrd.net/posts/2025/ha_zeus/</link>
      <pubDate>Tue, 25 Feb 2025 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2025/ha_zeus/</guid>
      <description>One of the challenges of running Home Assistant in a virtualized environment is the access to hardware radios. Home Assistant ultimately needs to bridge a ton of home automation networks, and most of these require some sort of USB / Serial dongle. You could have all of your dongles in your server closet and pass them through to the VM/container, but then you can&amp;rsquo;t migrate it across hosts. You could have one dongle for each host, I guess, but that doesn&amp;rsquo;t work for Z-wave where the entire network is stored on the dongle.</description>
      <content>&lt;p&gt;One of the challenges of running Home Assistant in a virtualized environment is the access to hardware radios. Home Assistant ultimately needs to bridge a ton of home automation networks, and most of these require some sort of USB / Serial dongle. You could have all of your dongles in your server closet and pass them through to the VM/container, but then you can&amp;rsquo;t migrate it across hosts. You could have one dongle for each host, I guess, but that doesn&amp;rsquo;t work for Z-wave where the entire network is stored on the dongle. Plus, the server closet probably isn&amp;rsquo;t a great place for the one radio anyway. So, I&amp;rsquo;m showing you how I use a Raspberry Pi to run my Zwave and Zigbee radios, remotely, for Home Assistant. This keeps the core Home Assistant setup flexible in where it can run on the network, and also lets me run multiple remote radios without resorting to weird tricks in HA OS.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_zeus/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_zeus/#base-os&#34;&gt;Base OS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_zeus/#pbs-backups&#34;&gt;PBS Backups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_zeus/#zwavejs-ui&#34;&gt;Zwave JS UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_zeus/#zigbee2mqtt&#34;&gt;Zigbee2MQTT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_zeus/#rtl-433&#34;&gt;RTL-433&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2025/ha_zeus/#updates&#34;&gt;Updates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/vtbhZf9KaXI&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2025/ha_zeus/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;base-os&#34;&gt;Base OS&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve chosen to install Raspberry Pi OS Lite, a variant of Debian Bookworm. I&amp;rsquo;m using the ARM 64-bit builds for Raspberry Pi 3. The Lite version just lacks the UI, which is fine since I&amp;rsquo;m never going to plug in a display.&lt;/p&gt;
&lt;p&gt;As far as I know, all of this should work fine on Debian Bookworm as well, if you want to use a mini PC.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t forget to run OS update as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt full-upgrade -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also dropped my SSH public key into &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; (the file does not exist by default) to avoid password logins.&lt;/p&gt;
&lt;p&gt;I disabled IPv4 on my setup (&lt;code&gt;nmcli connection modify &#39;Wired connection 1&#39; ipv4.method disable&lt;/code&gt;), and put the IPv6 address in DNS where it belongs. You are of course free to do other things, such as instlaling avahi-daemon for mdns, for example.&lt;/p&gt;
&lt;h2 id=&#34;pbs-backups&#34;&gt;PBS Backups&lt;/h2&gt;
&lt;p&gt;I backup everything to Proxmox Backup Server, so I need to install the client to backup this host.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re running on an ARM device you can get deb packages from &lt;a href=&#34;https://github.com/wofferl/proxmox-backup-arm64&#34;&gt;https://github.com/wofferl/proxmox-backup-arm64&lt;/a&gt; (you only need the client deb, not all of them)&lt;/p&gt;
&lt;p&gt;If you are running on x86 you can use Proxmox&amp;rsquo;s client-only repository instead.&lt;/p&gt;
&lt;p&gt;In any case, install PBS Client from packages.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s my backup script (&lt;code&gt;/etc/systemd/system/backup.service&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Description=Run Backup to Proxmox Backup Server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;After=network-online.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#TLS fingerprint if cert is self-signed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Environment=PBS_FINGERPRINT=your_fingerptint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Your API key here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Environment=PBS_PASSWORD=api_key_here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Use your user @ realm ! api key name @ hostname : repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Environment=PBS_REPOSITORY=user@pbs!apikey@localhost:backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Type=oneshot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup the root fs. This will not backup any other mount points, only the mount point which mounts /&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#You can add more pxars if you want more mount points&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#--change-detection-mode=metadata is optional, but I prefer it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ExecStart=proxmox-backup-client backup root.pxar:/ --change-detection-mode=metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;WantedBy=default.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also have a backup timer (&lt;code&gt;/etc/systemd/system/backup.timer&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Description=Backup System Daily&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;RefuseManualStart=no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;RefuseManualStop=no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Timer]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run 540 seconds after boot for the first time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#OnBootSec=540&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run at 7pm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;OnCalendar=*-*-* 19:00:00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Unit=backup.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;WantedBy=timers.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then a quick &lt;code&gt;systemctl daemon-reload&lt;/code&gt; and &lt;code&gt;sytemctl enable backup.timer&lt;/code&gt; is all you need. When the timer fires, it will trigger the service, which will run a single backup. Since it runs every day at 7pm, it will do one backup per day.&lt;/p&gt;
&lt;h2 id=&#34;zwavejs-ui&#34;&gt;ZwaveJS UI&lt;/h2&gt;
&lt;p&gt;I previously used Snap packages but I really hated working with them, so I am now using the NPN (nodeJS package manager) version combined with a systemd service script.&lt;/p&gt;
&lt;p&gt;Install:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Node 22 (seems like a reasonable choice)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo -E bash nodesource_setup.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install it from packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install nodejs -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Since we used apt here, we can run `apt upgrade -y` to upgrade Node minor versions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install zwave js ui&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo npm install -g zwave-js-ui
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /var/zwavejs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Service (&lt;code&gt;/etc/systemd/system/zwavejs.service&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Description=Z-Wave Network Manager&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;After=network-online.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#ZwaveJS binary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ExecStart=/usr/bin/zwave-js-ui&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Storage location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Environment=STORE_DIR=/var/zwavejs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Config location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Environment=ZWAVEJS_EXTERNAL_CONFIG=/var/zwavejs/.config-db&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;WantedBy=default.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then it&amp;rsquo;s just a &lt;code&gt;systemctl daemon-reload&lt;/code&gt; and &lt;code&gt;systemctl enable --now zwavejs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In my case, this would immediately cause the Pi to lock up due to underpower, so &amp;hellip;. that&amp;rsquo;s fun? I was hoping to migrate my old Zwave network, but I bought a new dongle and moved on to re-pairing everything. Zwave stores everything within the chipset, and being a proprietary standard with a single vendor, there are no hardware options other than Silicon Labs. On the plus side, compatibility between devices is excellent, but the downside is it isn&amp;rsquo;t as easy for ZwaveJS to store the network config in a place I can back it up.&lt;/p&gt;
&lt;h2 id=&#34;zigbee2mqtt&#34;&gt;Zigbee2MQTT&lt;/h2&gt;
&lt;p&gt;This one is also written in NodeJS, so we again need to make sure NodeJS is installed and ready to go (skip this if you already did ZwaveJS):&lt;/p&gt;
&lt;p&gt;Install NodeJS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Node 22 (ZwaveJS is using 18 in their docker images I think?)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo -E bash nodesource_setup.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install it from packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install nodejs -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Since we used apt here, we can run `apt upgrade -y` to upgrade Node minor versions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can install Zigbee2MQTT from source:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Need git and friends&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Create a directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mkdir /opt/zigbee2mqtt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo chown -R &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;USER&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;: /opt/zigbee2mqtt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Checkout into directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone --depth &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; https://github.com/Koenkk/zigbee2mqtt.git /opt/zigbee2mqtt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install depends&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /opt/zigbee2mqtt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm ci
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm run build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Service (&lt;code&gt;/etc/systemd/system/zigbee2mqtt.service&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Description=Zigbee 2 MQTT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;After=network-online.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Node binary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ExecStart=/usr/bin/node index.js&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;WorkingDirectory=/opt/zigbee2mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;WantedBy=default.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then it&amp;rsquo;s just a &lt;code&gt;systemctl daemon-reload&lt;/code&gt; and &lt;code&gt;systemctl enable --now zigbee2mqtt&lt;/code&gt; (these may need sudo fyi).&lt;/p&gt;
&lt;p&gt;After that, we need to set a few things in the configuration.yaml, so edit &lt;code&gt;data/configuration.yaml&lt;/code&gt; (it&amp;rsquo;s in /opt/zigbee2mqtt/data/configuration.yaml). You can also copy the example (&lt;code&gt;configuration.example.yaml&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Things you should do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;homeassistant&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;permit_join&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; (you can re-enable it from the UI)&lt;/li&gt;
&lt;li&gt;Set your MQTT broker server, username, and password&lt;/li&gt;
&lt;li&gt;Set the location of your serial port (please use the one in &lt;code&gt;/dev/serial/by-id/&lt;/code&gt; instead of &lt;code&gt;/dev/ttyUSBX&lt;/code&gt; in case your devices change)&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;frontend: true&lt;/code&gt; to run the web UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can access the web ui on port 8080 to configure it.&lt;/p&gt;
&lt;p&gt;For reference, here is my configuration (redacted) for reference:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;homeassistant&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;frontend&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;mqtt&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;base_topic&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;zigbee2mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#MQTT User Information Here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;server&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt://telstar.palnet.net&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;serial&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;advanced&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;homeassistant_legacy_entity_attributes&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;legacy_api&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;legacy_availability_payload&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#PAN ID, etc. removed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Devices removed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;rtl-433&#34;&gt;RTL-433&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/rtl433/&#34;&gt;Previous Project Entry Here&lt;/a&gt;
When I previously set this up I had to compile it from source. Now, it&amp;rsquo;s included in the Pi repos directly, so no need to do that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install rtl-433 -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not to revisit that previous entry too much, here&amp;rsquo;s my service file (&lt;code&gt;/etc/systemd/rtl433.service&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Description=rtl_433 SDR Receiver Daemon&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;After=network-online.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ExecStart=/usr/bin/rtl_433 -C si -F &amp;#34;mqtt://&amp;lt;broker&amp;gt;:1883,user=&amp;lt;user&amp;gt;,pass=&amp;lt;pass&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Restart=always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;WantedBy=multi-user.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then it&amp;rsquo;s just a &lt;code&gt;systemctl daemon-reload&lt;/code&gt; and &lt;code&gt;systemctl enable --now rtl433&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;updates&#34;&gt;Updates&lt;/h2&gt;
&lt;p&gt;Managing software updates can be a full-time task, so here are the update commands for everything:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;apt update &amp;amp;&amp;amp; apt upgrade -y&lt;/code&gt; to update the base Debian system and Node.JS&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm update zwave-js-ui &amp;amp;&amp;amp; systemctl restart zwavejs&lt;/code&gt; to update ZwaveJS UI itself&lt;/li&gt;
&lt;li&gt;There are no updates for my UPS daemon&lt;/li&gt;
&lt;li&gt;Zigbee2MQTT needs a bit more:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#cd to the directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /opt/zigbee2mqtt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Pull update from Git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git pull
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make depend&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm ci
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm run build
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Restart service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl restart zigbee2mqtt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Sponsors</title>
      <link>https://www.apalrd.net/sponsors/</link>
      <pubDate>Fri, 24 Jan 2025 08:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/sponsors/</guid>
      <description>Inspired by Jeff Geerling&amp;rsquo;s complete list of sponsor disclosures, I thought I&amp;rsquo;d work on my own page. This lists every company I&amp;rsquo;ve worked with in some form, alphabetically, and if any of these agreements were sponsored financially.
All links to Amazon and Ebay on my channel are affiliate links. If I am a part of any other affiliate programs, I&amp;rsquo;ll note it below.
Aiffro Relevant Video: Aiffro K1 Review
Aiffro provided this unit for the review, including one 256G boot NVMe boot drive.</description>
      <content>&lt;p&gt;Inspired by Jeff Geerling&amp;rsquo;s complete list of sponsor disclosures, I thought I&amp;rsquo;d work on my own page. This lists every company I&amp;rsquo;ve worked with in some form, alphabetically, and if any of these agreements were sponsored financially.&lt;/p&gt;
&lt;p&gt;All links to Amazon and Ebay on my channel are affiliate links. If I am a part of any other affiliate programs, I&amp;rsquo;ll note it below.&lt;/p&gt;
&lt;h2 id=&#34;aiffro&#34;&gt;Aiffro&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/jv739Kw7_JQ&#34;&gt;Aiffro K1 Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Aiffro provided this unit for the review, including one 256G boot NVMe boot drive.&lt;/p&gt;
&lt;p&gt;After the video, they reached out again with the same email text as before, and I asked if they wanted to supply 2 additional units for a 3-node cluster, and they declined.&lt;/p&gt;
&lt;h2 id=&#34;airgradient&#34;&gt;AirGradient&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/gCO8KoihId8&#34;&gt;AirGradient Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;AirGradient sent me two AirGraient DIY kits for review.&lt;/p&gt;
&lt;h2 id=&#34;aurga-viewer&#34;&gt;Aurga Viewer&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/6EU-XAcMY9A&#34;&gt;Aurga Viewer Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I reached out to them requesing to review the product. They provided the unit for review.&lt;/p&gt;
&lt;h2 id=&#34;cdata&#34;&gt;CData&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/sKBoO0eRAJY&#34;&gt;Fiber Optic Home Lab&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;CData provided the equipment for the video - mini-OLT and 8x ONUs in 3 form factors. I purchased the fiber equipment from fs.com (GPON transceiver, PLC spltter, attenuator, and fiber cable). CData also reviewed the video before release, and provided some product B-roll for me at one point.&lt;/p&gt;
&lt;h2 id=&#34;creality&#34;&gt;Creality&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/PGNg2ZNp1_0&#34;&gt;Creality Falcon 2 Pro Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Creality sent me the laser and accessories for review. I provided my own stock materials.&lt;/p&gt;
&lt;p&gt;After completing the video, the laser was used by the robotics team for a year, until they sold it to upgrade to a CO2 laser which can cut Delrin. The Creality laser was better at wood and vinyl graphics.&lt;/p&gt;
&lt;h2 id=&#34;cytrence&#34;&gt;Cytrence&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/lzYP0a0F8Y0&#34;&gt;Cytrence Kiwi Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cytrence provided the unit for review. After the video was published one of their founders donated to my Ko-Fi.&lt;/p&gt;
&lt;h2 id=&#34;elecrow&#34;&gt;Elecrow&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/V-tsVKjjme4&#34;&gt;Elecrow Pi Touchscreen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/HWF6Qm7JhJU&#34;&gt;Elecrow LoRaWAN Video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Elecrow sent me the items for review, including a number of sensors to use with the LoRa board which I did not use.&lt;/p&gt;
&lt;p&gt;Elecrow has an affiliate program which I am a part of, it has not produced a significant revenue for me.&lt;/p&gt;
&lt;h2 id=&#34;fikwot-ssd&#34;&gt;Fikwot SSD&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/m4zwJvzQ65s&#34;&gt;Fikwot SSD Video&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fikwot sent me one NVMe SSD for me to use in a video.&lt;/p&gt;
&lt;h2 id=&#34;flexispot&#34;&gt;Flexispot&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/Uu3kWtEXFps&#34;&gt;Flexispot Standing Desk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Flexispot provided the standing desk and chair for both videos. Additionally, they offer standing desks very frequently, and they were easy to work with.&lt;/p&gt;
&lt;h2 id=&#34;glbb-japan&#34;&gt;GLBB Japan&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/XgmQ-qBrqxY&#34;&gt;SFP Serial Console Server&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GLBB provided one serial console server, one cable, and I had to pay tariffs on this one.&lt;/p&gt;
&lt;h2 id=&#34;glinet&#34;&gt;GL.inet&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/BmuaojsXDc4&#34;&gt;GL.Inet Comet Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GL.inet provided the Comet for review. I have since asked if they would provide the updated comet for an updated review, and they have declined.&lt;/p&gt;
&lt;h2 id=&#34;gmktek&#34;&gt;GMKTek&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/wIN6MZCnG9I&#34;&gt;GMKTek G9 Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/hnrc45hZjpE&#34;&gt;GMKTek K10 Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/CGh1NZSxXbI&#34;&gt;GMKTek EVO-T1 Review&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GMKTek provided the units for review, and also provided the coupon/discount codes for their site. I am not a part of any affiliate program with them, however, the Amazon links are part of my usual Amazon affiliate account.&lt;/p&gt;
&lt;h2 id=&#34;goldenmate&#34;&gt;Goldenmate&lt;/h2&gt;
&lt;p&gt;Relevant video: &lt;a href=&#34;https://youtu.be/MU7gFjkBkN0&#34;&gt;Goldenmate UPS Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Goldenmate reached out wanting to provide the UPS for a full video. I agreed to include it in a longer video on my power problems and power metering setup.&lt;/p&gt;
&lt;p&gt;In Early 2025, they uploaded my video in its entirety onto their own channel, and I submitted a copyright claim on their copy of my video, and it is now removed. They have not contacted me about it.&lt;/p&gt;
&lt;h2 id=&#34;grandstream&#34;&gt;Grandstream&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/9SyxGNT4o5M&#34;&gt;Grandstream GWN7665&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Grandstream provided one GWN7665 for review. I have not decided if I will purchase more for my home network.&lt;/p&gt;
&lt;h2 id=&#34;icewhale-zima&#34;&gt;Icewhale (Zima)&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/R5QtXMwzJas&#34;&gt;ZimaBoard Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Icewhale sent me the unit for review.&lt;/p&gt;
&lt;h2 id=&#34;jetkvm&#34;&gt;JetKVM&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/KXW9jcUI7ZE&#34;&gt;JetKVM Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/yHhdTRVvDFU&#34;&gt;JetKVM Security&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JetKVM sent me the unit, extra PCB, and some accessories in the box. I was not a part of the Kickstarter crowdfunding campaign in any way, I did not back the product or purchase additional units on my own.&lt;/p&gt;
&lt;p&gt;I have also submitted bug reports to their Github, both before and after it was made public.&lt;/p&gt;
&lt;p&gt;I followed-up with a security review, and have now committed minor fixes to their Github which have been accepted and merged.&lt;/p&gt;
&lt;h2 id=&#34;kwumsy&#34;&gt;Kwumsy&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/3VZtBSO4Dhg&#34;&gt;Kwumsy K3 Touchscreen Keyboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/8hgGcEk4tgs&#34;&gt;Kwumsy Stream Dock&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The K3 touchscreen keyboard and Stream Dock were both sent for review. They also offered many different laptop screen extensions, which I have turned down.&lt;/p&gt;
&lt;p&gt;I stopped using the K3 full time when the USB-C cable started to become flaky. I now use the K3 as a portable keyboard+monitor when I need to take my workstation to events for live streaming.&lt;/p&gt;
&lt;h2 id=&#34;lcmd&#34;&gt;LCMD&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/m1RPC5UpLJU&#34;&gt;LCMD MicroServer Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;LCMD provided the MicroServer for review. They were also very unhappy with the video and asked me to take it down.&lt;/p&gt;
&lt;h2 id=&#34;lincstation&#34;&gt;Lincstation&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/aUG3t98SIIw&#34;&gt;Lincstation N1 Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Lincstation sent me the unit for review.&lt;/p&gt;
&lt;h2 id=&#34;maiyunda&#34;&gt;Maiyunda&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/V6MkbKLzdwo&#34;&gt;Maiyunda M1S Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Maiyunda sent one M1S for review.&lt;/p&gt;
&lt;h2 id=&#34;mdslink&#34;&gt;MDSLink&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/RFa7IWiqnb8&#34;&gt;MoCa Video&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MDSLink sent me (9) units for testing, and later sent me several coax components (Splitters, cabling, ..) after I struggled with the parts from my local hardware store.&lt;/p&gt;
&lt;h2 id=&#34;mikrotik&#34;&gt;Mikrotik&lt;/h2&gt;
&lt;p&gt;Relevant Videos:
&lt;a href=&#34;https://youtu.be/V1Ke4_jK08w&#34;&gt;Mikrotik CRS312 and CRS305 Upgrade&lt;/a&gt;
&lt;a href=&#34;https://youtube.com/shorts/xLb9zXUvaF0?feature=share&#34;&gt;Mikrotik CRS312 Short&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Mikrotik provided the products in the video. I paid for the fiber and transceivers. Mikrotik has not provided hardware other than this video - the hEX S and wAP AC that I often use for testing were not provided.&lt;/p&gt;
&lt;h2 id=&#34;mele&#34;&gt;Mele&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/lJSODruRSe8&#34;&gt;Mele Mini PC Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Mele sent me the mini PC for review.&lt;/p&gt;
&lt;h2 id=&#34;milk-v&#34;&gt;Milk-V&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/z-GoLDQHYsE&#34;&gt;RISC-V Video&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Milk-V provided one Duo, breakout board, and camera for review.&lt;/p&gt;
&lt;p&gt;I additionally purchased 50 Duos and 10 Cameras to distribute in the US on my own. I still have 4 remaining to use for my own projects.&lt;/p&gt;
&lt;h2 id=&#34;minisforum&#34;&gt;Minisforum&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/KGQvssq3ee0&#34;&gt;Minisforum MS-A1 Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Minisforum sent me the MS-A1 for review. I previously had contacting them requesting an MS-O1 for review, but did not hear back about that.&lt;/p&gt;
&lt;p&gt;Additionally, I reported the hardware issues with my MS-A1 to my marketting contact. He replied that he was on vacation and would forward my questions to a coworker, but I never heard a reply. After a week of waiting, I published the video, and still have not heard back.&lt;/p&gt;
&lt;h2 id=&#34;minix&#34;&gt;MINIX&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/qLgKIT5QlPE&#34;&gt;Fanless N300 Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MINIX provided the unit for review.&lt;/p&gt;
&lt;h2 id=&#34;openterface&#34;&gt;Openterface&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/ZZ5P6MnBcHw&#34;&gt;Openterface KVM Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Openterface sent me their full kit (including optional cables) for review, and additionally provided beta versions of the macOS app through Test Flight prior to releasing it publicly. The Windows/Linux app is open source and was already released publicly.&lt;/p&gt;
&lt;p&gt;I was not a part of the Kickstarter crowdfunding campaign in any way, I did not back the product or purchase additional units on my own.&lt;/p&gt;
&lt;h2 id=&#34;opnnas&#34;&gt;OPNNas&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/s7dSwm3GC3s&#34;&gt;OPNNas Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OPNNAs provided the unit for review, not including hard drives, and included an extra SAS HBA card so I could test both configurations they were planning on shipping at the time (SATA expander and SAS HBA).&lt;/p&gt;
&lt;h2 id=&#34;orico&#34;&gt;Orico&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/7hve4ixg880&#34;&gt;Put your Game Library on a NAS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/7hve4ixg880&#34;&gt;Orico MetaHome Review&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Orico sponsored a video product placement using their SSDs (&amp;lsquo;put your game library on a nas&amp;rsquo; video). They later offered a product review of the Orico MetaHome, which I accepted based on the spec sheet, and was entirely underwhelmed with it.&lt;/p&gt;
&lt;h2 id=&#34;patchbox&#34;&gt;Patchbox&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/owmzj3dOru0&#34;&gt;Patchbox&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Patchbox sent me the hardware in the video. Initially I was only going to look at the Patchbox itself, but they really wanted to include the setup tool and rack studs.&lt;/p&gt;
&lt;h2 id=&#34;peladn&#34;&gt;Peladn&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/17FeofdCpfw&#34;&gt;Peladn WO4 Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/WyKzFFg959o&#34;&gt;Peladn WO4 Review&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Peladn sent me the units for review.&lt;/p&gt;
&lt;h2 id=&#34;pi-cast&#34;&gt;Pi-Cast&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/RHTGNQdGwW8&#34;&gt;Pi-Cast KVM Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pi-Cast sent me two units, and two sets of ATX extension hardware for review.&lt;/p&gt;
&lt;h2 id=&#34;private-internet-access&#34;&gt;Private Internet Access&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/d20roxFfU0A&#34;&gt;PIA Sponsor Spot&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PIA paid for a sponsored spot in this video. Additionally, I am a part of their affiliate program.&lt;/p&gt;
&lt;p&gt;I do not plan on working with them again. Going forward, I am only going to work with VPN companies which support IPv6.&lt;/p&gt;
&lt;h2 id=&#34;protectli&#34;&gt;Protectli&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/Yb7JdIFriKI&#34;&gt;OPNsense Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/-Uta6GdDZm0&#34;&gt;VP2430 Review&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Protectli provided the FW4C and VP2430 for the videos, and also a branded cup which I use.&lt;/p&gt;
&lt;p&gt;I purchased my own FW4B in 2021 before starting Youtube and continue to use it. I plan on replacing it with the FW4C long term.&lt;/p&gt;
&lt;h2 id=&#34;proxmox-server-solutions-gmbh&#34;&gt;Proxmox Server Solutions Gmbh&lt;/h2&gt;
&lt;p&gt;Proxmox sent me a T-shirt, pen, and flashdrive.&lt;/p&gt;
&lt;h2 id=&#34;reolink&#34;&gt;Reolink&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/jrM6LL2bOh0&#34;&gt;Reolink Duo 3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Reolink sent me two identical Duo 3 cameras for review. I damaged one camera due to poor waterproofing of the connector, which caused water to pool and corrode the RJ45 female connection.&lt;/p&gt;
&lt;p&gt;Reolink has offered additional cameras. I will only look at their models which support cloud-free RTSP control (which is mostly their wired cameras).&lt;/p&gt;
&lt;h2 id=&#34;ruipro&#34;&gt;Ruipro&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/1aIK01S5qa4&#34;&gt;Ruipro HDMI Fiber&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ruipro sent me two sets of the fiber + ends for review.&lt;/p&gt;
&lt;h2 id=&#34;sipeed&#34;&gt;Sipeed&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/plJGZQ35Q6I&#34;&gt;Sipeed NanoKVM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/AmENtwiBWZM&#34;&gt;Sipeed NanoKVM USB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sipeed provided 3x NanoKVM units for review - Lite, base model, and PCIe. I did not inform them of the security issues prior to releasing the video. However, all of the issues I highlighted were already disclosed via their Github issues and had an insufficient response from Sipeed.&lt;/p&gt;
&lt;p&gt;Sipeed responded publicly &lt;a href=&#34;https://github.com/sipeed/NanoKVM/issues/301&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since their response, their stance seems to have improved significantly, and I included the NanoKVM in a round-up video later with a generally positive outlook.&lt;/p&gt;
&lt;p&gt;For the NanoKVM USB, they provided two units for review.&lt;/p&gt;
&lt;h2 id=&#34;smallstep&#34;&gt;Smallstep&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/zD0w6SJI_Ww&#34;&gt;Smallstep EAP-TLS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Smallstep paid me to produce a video showing their new EAP-TLS configurtion feature of their cloud hosted software. I had previously made content on my own of their open-source offerings, and continue to use their open-source solution.&lt;/p&gt;
&lt;p&gt;Smallstep additionally provided me with Bill Wi, my Unifi Dream Router, as they wanted to demonstrate EAP-TLS using the Unifi ecosystem.&lt;/p&gt;
&lt;h2 id=&#34;smartwave-shades&#34;&gt;SmartWave Shades&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/A0Su3yGC4yc&#34;&gt;How will Matter and Thread revolutionize Home Automation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;SmartWave sent two motorized roller shades for the video, and all accessories shown in the video. They initially wanted a review video, but I instead suggested a demonstration of their product in the context of Matter, which they agreed to.&lt;/p&gt;
&lt;h2 id=&#34;synology&#34;&gt;Synology&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/BlsmG3CtjE8&#34;&gt;Synology Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Synology sent me both NAS units for review. They have offered many consumer level products, and I asked them to continue to send me new items as they are available, but I have not yet found any unique enough.&lt;/p&gt;
&lt;h2 id=&#34;terramaster&#34;&gt;TerraMaster&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/-mN3ECv2AVE&#34;&gt;Terramaster F8 Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/qML-ct2dGvQ&#34;&gt;Terramaster DAS Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/4_5uvWjOaR8&#34;&gt;Terramaster 223 review&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Terramaster sent me those products for review, without any drives.&lt;/p&gt;
&lt;h2 id=&#34;tesmart&#34;&gt;TESmart&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/y-PxmQn8Xr8&#34;&gt;TESMart KVM over IP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/jmwSfUyKC1Q&#34;&gt;TESMart KVM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;TESMart provided the units for review.&lt;/p&gt;
&lt;p&gt;Additionally, I am a part of a TESmart affiliate program.&lt;/p&gt;
&lt;h2 id=&#34;tp-link&#34;&gt;TP-Link&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/B86BLIpKA7s&#34;&gt;1882 Detroit Mansion&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;TP-Link provided all of the equipment in the video to the Wayne Engineering Society. Additionally, they selected the equipment based on my description of the needs and floor plan.&lt;/p&gt;
&lt;h2 id=&#34;ugreen&#34;&gt;Ugreen&lt;/h2&gt;
&lt;p&gt;Relevant Videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/R8t-Wqx_E3U&#34;&gt;Ugreen DXP-4800 Plus Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/JMqCTrfif5U&#34;&gt;Ugreen DXP-480T Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/pwbLqCXyWAc&#34;&gt;Proxmox Backup Server video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ugreen sent the two NAS units for review. Ugreen also included drives in branded packaging (4x 4T spinning drives for the HDD, and 4x Samsung 980s for the NVMe unit).&lt;/p&gt;
&lt;p&gt;After this review, they paid me to produce an ad spot for their chargers on my channel.&lt;/p&gt;
&lt;p&gt;Additionally, they unprompted sent me a Christmas box which included a Ugreen branded mug, and a letter from the wrong year.&lt;/p&gt;
&lt;p&gt;Later, they also sponsored the Proxmox Backup Server video, for which they provided another DXP-4800 and another 4 hard drives.&lt;/p&gt;
&lt;h2 id=&#34;zenarmor&#34;&gt;Zenarmor&lt;/h2&gt;
&lt;p&gt;Relevant Video: &lt;a href=&#34;https://youtu.be/khC9TQ4pJqA&#34;&gt;Zenarmor Review&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Zenarmor provided me with a 6-month small business license for evaluation in a video.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Physical Network Access Control with 802.1X</title>
      <link>https://www.apalrd.net/posts/2024/network_dot1x/</link>
      <pubDate>Sat, 14 Dec 2024 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/network_dot1x/</guid>
      <description>Today I&amp;rsquo;m diving in to the world of network access control! Being able to authenticate network devies plugged in to your switches is a great way to improve network security without resorting to unplugging or disabling every unused port on yout equipment. Now every switch port is universal, and will enable on demand based on what is plugged in. While I couldn&amp;rsquo;t go through the complete authorization part of the setup (mapping devices to VLANs), I&amp;rsquo;m planning on making a future video for that step.</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m diving in to the world of network access control! Being able to authenticate network devies plugged in to your switches is a great way to improve network security without resorting to unplugging or disabling every unused port on yout equipment. Now every switch port is universal, and will enable on demand based on what is plugged in. While I couldn&amp;rsquo;t go through the complete authorization part of the setup (mapping devices to VLANs), I&amp;rsquo;m planning on making a future video for that step.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#certificates-overview&#34;&gt;Certificates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#freeradius-test-certs&#34;&gt;Certificates - FreeRADIUS Test Certs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#certificate-authority&#34;&gt;Certificates - Simple CA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#server&#34;&gt;Certificates - Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#client&#34;&gt;Certificates - Clients&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#install-freeradius&#34;&gt;Install FreeRADIUS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#systemd-override&#34;&gt;Install FreeRADIUS - Systemd Override&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#radsec-configuration&#34;&gt;FreeRADIUS - RADsec Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#eap-module-configuration&#34;&gt;FreeRADIUS - EAP Module Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#inner-tunnel-configuration-optional&#34;&gt;FreeRADIUS - Inner Tunnel Configuration (Optional)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#default-server-configuration-optional&#34;&gt;FreeRADIUS - Default Server Configuration (Optional)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_dot1x/#users-file-optional&#34;&gt;FreeRADIUS - Users File (PEAP Only)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/snpjL8BN_rI&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2024/network_dot1x/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;certificates-overview&#34;&gt;Certificates Overview&lt;/h2&gt;
&lt;p&gt;RADIUS and EAP love nesting, so we need a lot of keys here. In particular:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Server cert for RADsec&lt;/li&gt;
&lt;li&gt;Client cert for RADsec (per-authenticator, which is an AP or Switch)&lt;/li&gt;
&lt;li&gt;Server cert for EAP (may be the same as RADsec)&lt;/li&gt;
&lt;li&gt;Client cert for each client&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;RADIUS is not a particularly secure protocol on its own. It operates over UDP 1812/1813 and has no encryption at all. Messages are &lt;em&gt;authenticated&lt;/em&gt; using a &amp;lsquo;shared secret&amp;rsquo; (which is often words instead of randomly generated), and relying on an MD5 hash. MD5 isn&amp;rsquo;t a great hash function in 2024 (it&amp;rsquo;s cryptographically considered insecure already, and so is its replacement SHA1). It&amp;rsquo;s also far from a password-quality hash for dealing with poor human-generated sources, so it&amp;rsquo;s basically entirely broken. Most of the RADIUS payloads do their own encryption all the way to the client, using TLS, but this still doesn&amp;rsquo;t encrypt our Accept decision which is sent over the clear to the authenticator.&lt;/p&gt;
&lt;p&gt;Two industries took on the bad RADIUS security problem in different ways - the telecom industry decided to go off into the weeds and build something completely different and far more complex with far more ASN.1 and called it DIAMETER (ha ha). The normal people took the whole RADIUS protocol (MD5 and all) and dropped it inside a TLS session, where TLS provides security and RADIUS uses a hardcoded &amp;lsquo;secret&amp;rsquo; (&lt;code&gt;radsec&lt;/code&gt; is the literal secret).&lt;/p&gt;
&lt;p&gt;So now we need to implement RADsec, which relies on mutual TLS (this should sound familiar if you follow me). So, for the TLS Sessions for RADsec, we need a server cert (for FreeRADIUS) and a client cert (for our authenticators). These can be from any CA, but since all of this equipment is our own it would make sense to use a private CA for all of these.&lt;/p&gt;
&lt;p&gt;Then, separately, we are either going to do EAP-TLS (preferred) or EAP-PEAP (not preferred but commonly implemented) to the clients. Both of these encapsulate in TLS. EAP-TLS uses mutual TLS to authenticate the client, and EAP-PEAP uses TLS to authenticate the server and then MS-CHAPv2 to authenticate the client (probably using MD5 again).&lt;/p&gt;
&lt;p&gt;I have three different methods for generating certs, which I have used in videos at this point:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use OpenSSL and do it entirely manually&lt;/li&gt;
&lt;li&gt;Use Smallstep and run a full private PKI setup&lt;/li&gt;
&lt;li&gt;Use FreeRADIUS&amp;rsquo;s testing certs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your choice depends on what you want to get out of the full setup. I&amp;rsquo;d also like to remind you that one cert per machine is very normal, you don&amp;rsquo;t need a different set of certs for mtls and also vpn and also 802.1x.&lt;/p&gt;
&lt;h2 id=&#34;freeradius-test-certs&#34;&gt;FreeRADIUS Test Certs&lt;/h2&gt;
&lt;p&gt;To generate FreeRADIUS test certs (&lt;em&gt;after installing FreeRADIUS&lt;/em&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Go to this directory, you must cd here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc/freeradius/3.0/certs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make the CA initially&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you change configs and re-run make, it should regenerate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#In case it doesn&amp;#39;t, you can run destroycerts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make destroycerts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;my-easy-openssl-method&#34;&gt;My Easy OpenSSL Method&lt;/h2&gt;
&lt;p&gt;This method generates all of the certs we will need today by copying/pasting. Edit the commands before you run them to change the options. It&amp;rsquo;s easier to understand than the makefile, but also not very scalable. If you watched my mTLS video, it&amp;rsquo;s basically the same as that. You should probably use Smallstep for production-like things.&lt;/p&gt;
&lt;h3 id=&#34;certificate-authority&#34;&gt;Certificate Authority&lt;/h3&gt;
&lt;p&gt;Same as mtls, simple 384-bit key&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate private key using scep384:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl ecparam -name secp384r1 -genkey -out root.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign the root certificate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Pathlen:0 means there can be only one more cert below this CA (no more CAs)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make sure you update the subj name with your own names&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#C=US is also the country, it&amp;#39;s optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#O= is the organization, also optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#CN= is the Common Name and it&amp;#39;s required&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#I also set validity to 69 years, make sure you watch for expiration (manually)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl req -new -key root.key -x509 -nodes -days &lt;span style=&#34;color:#ae81ff&#34;&gt;25202&lt;/span&gt; -out root.pem -subj &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/C=US/O=apalrd.net/CN=radius&amp;#34;&lt;/span&gt; -addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;basicConstraints=critical,CA:TRUE,pathlen:0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#CA cert must be readable by freerad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown freerad:freerad root.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now you can view it (for fun)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -in root.pem -text -noout
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;server&#34;&gt;Server&lt;/h3&gt;
&lt;p&gt;The same cert is used for both radsec and eap on the server side.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export sv&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;raddb.apalrd.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate scep256 key for this client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you want 192-bit security, use scep384r1 instead of prime256v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl ecparam -name prime256v1 -genkey -out $sv.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate a CSR (certificate signing request) for my new key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#again, C and O are optional, CN is the Common Name of the cert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Allowed only for server auth (in both radsec and eap roles, we are the server)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Set for TOFU policy (network asks the user to trust on first use)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Change certificatePolicy to 1.3.6.1.4.1.40808.1.3.1 for strict (client must be pre-configured to trust CA)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl req -new -key $sv.key -out $sv.csr -subj &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/C=US/O=apalrd.net/CN=&lt;/span&gt;$sv&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;extendedKeyUsage = serverAuth&amp;#34;&lt;/span&gt; -addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;certificatePolicies = 1.3.6.1.4.1.40808.1.3.2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#TODO crlDistributionPoints&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign the CSR using the root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Shorter lived at only 365 days&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -req -in $sv.csr -CA root.pem -CAkey root.key -CAcreateserial -out $sv.crt -days &lt;span style=&#34;color:#ae81ff&#34;&gt;365&lt;/span&gt; -sha256 -copy_extensions&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;copyall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Must add CA cert after server cert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat root.pem &amp;gt; $sv.crt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Server key must be readable by freerad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown freerad:freerad $sv.key $sv.crt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now you can view it (for fun)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -in $sv.crt -text -noout
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;client&#34;&gt;Client&lt;/h3&gt;
&lt;p&gt;You need one of these for each authenticator (wifi AP / switch), and also one for each EAP client. Change the name (&lt;code&gt;export cl&lt;/code&gt;) each time. Common practice is to use a FQDN for device certs and user@domain for user certs&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export cl&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;wap1.apalrd.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate scep256 key for this client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you want 192-bit security, use scep384r1 instead of prime256v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl ecparam -name prime256v1 -genkey -out $cl.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate a CSR (certificate signing request) for my new key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#again, C and O are optional, CN is the Common Name of the cert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl req -new -key $cl.key -out $cl.csr -subj &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/C=US/O=apalrd.net/CN=&lt;/span&gt;$cl&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;extendedKeyUsage = clientAuth&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign the CSR using the root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign it allowing for server and client auth as the key usage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -req -in $cl.csr -CA root.pem -CAkey root.key -CAcreateserial -out $cl.crt -days &lt;span style=&#34;color:#ae81ff&#34;&gt;365&lt;/span&gt; -sha256 -copy_extensions&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;copyall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now you can view it (for fun)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -in $cl.crt -text -noout
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now let&amp;#39;s package it into a P12 archive so you can send it to your favorite client device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#You *must* enter a password here or some OSes will not accept the P12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The password just encrypts the P12 file itself&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl pkcs12 -export -out $cl.p12 -in $cl.crt -inkey $cl.key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;install-freeradius&#34;&gt;Install FreeRADIUS&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m running FreeRADIUS on a Debian 12 system (LXC continer, unprivilaged). Start by installing Debian 12 using your favorite method, and updating it fully (&lt;code&gt;apt update &amp;amp;&amp;amp; apt full-upgrade -y&lt;/code&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install from deb packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install freeradius -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we&amp;rsquo;re going to move over to &lt;code&gt;/etc/freeradius/3.0&lt;/code&gt; where we are going to hang out for a &lt;em&gt;long&lt;/em&gt; time&lt;/p&gt;
&lt;p&gt;The folder structure contains two directories with configs (&lt;code&gt;mods-available&lt;/code&gt; and &lt;code&gt;sites-available&lt;/code&gt;), which is what we edit, and when we want to enable them, we create a symlink in the corresponding &lt;code&gt;*-enabled&lt;/code&gt; directory. This is similar to how a lot of distros package Apache and nginx, for example.&lt;/p&gt;
&lt;h3 id=&#34;systemd-override&#34;&gt;Systemd Override&lt;/h3&gt;
&lt;p&gt;To use client certificates (in both RADsec and in EAP-TLS), we need a temp directory for FreeRADIUS. Systemd is smart enough to create a per-service &lt;code&gt;/tmp&lt;/code&gt; which we should just use, but FreeRADIUS is dumb enough to demand a directory which already exists, and then tries to chmod/chown it on startup (which Systemd has prevented). So, edit the systemd service (&lt;code&gt;systemctl edit freeradius&lt;/code&gt;) and add this to the top:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;freerad
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Group&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;freerad
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RuntimeDirectory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;freeradius freeradius/tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RuntimeDirectoryPreserve&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;radsec-configuration&#34;&gt;RADsec Configuration&lt;/h3&gt;
&lt;p&gt;This file goes in &lt;code&gt;sites-available/radsec&lt;/code&gt; and configures the clients. Then, create a symlink to it (&lt;code&gt;ln -s ../sites-available/radsec sites-enabled/radsec&lt;/code&gt;). I have cut a lot of the documentation out of this file, but if you want to read it, I started from the file &lt;code&gt;sites-available/tls&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;######################################################################&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  RADIUS over TLS (radsec)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;######################################################################&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;listen &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# FreeRADIUS is stupid sometimes / often&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ipaddr = * means any *IPv4*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ipaddr = :: means any *IPv6*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	ipaddr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ::
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	port &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2083&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;# Allow both Auth and Accounting&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; auth+acct
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;# For now, only TCP transport is allowed.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	proto &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; tcp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;# Send packets to the default virtual server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	virtual_server &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; default
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# This is a client name, for the `radsec` section later&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	clients &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; radsec
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;# Connection limiting for sockets with &amp;#34;proto = tcp&amp;#34;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	limit &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	      &lt;span style=&#34;color:#75715e&#34;&gt;#  Limit the number of simultaneous TCP connections to the socket&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	      max_connections &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	      &lt;span style=&#34;color:#75715e&#34;&gt;#  The lifetime, in seconds, of a TCP connection.  After&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	      &lt;span style=&#34;color:#75715e&#34;&gt;#  this lifetime, the connection will be closed.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	      lifetime &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	      &lt;span style=&#34;color:#75715e&#34;&gt;#  The idle timeout, in seconds, of a TCP connection.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	      &lt;span style=&#34;color:#75715e&#34;&gt;#  If no packets have been received over the connection for&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	      &lt;span style=&#34;color:#75715e&#34;&gt;#  this time, the connection will be closed.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	      idle_timeout &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# TLS Crypto section&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tls &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# If your private key is encrypted&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# private_key_password = whatever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		private_key_file &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; /etc/freeradius/3.0/certs/raddb.apalrd.net.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# Certificate file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# If key + cert are in the same file, use the same filename as above&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		certificate_file &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; /etc/freeradius/3.0/certs/raddb.apalrd.net.crt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# Trusted Root CA list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Combine all roots one after another into this file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		ca_file &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; /etc/freeradius/3.0/certs/root.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# Fragment size (read the docs if you want to change)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		fragment_size &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8192&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# Set this option to specify the allowed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# TLS cipher suites.  The format is listed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# in &amp;#34;man 1 ciphers&amp;#34;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		cipher_list &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DEFAULT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# If enabled, OpenSSL will use server cipher list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		cipher_server_preference &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  Older TLS versions are deprecated.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		tls_min_version &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		tls_max_version &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  Session resumption / fast reauthentication cache&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		cache &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            enable &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            lifetime &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# hours&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TLS RADSEC&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			persist_dir &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;logdir&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/tlscache&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  Require a client certificate.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		require_client_cert &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# Verify client certs (i.e. using OCSP)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Configured to use the CA we setup earlier&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		verify &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;# Due to some *quirks* in FreeRADIUS, it expects to be able to&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# manipulate the permissions of this directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# systemd would rather isolate it itself, so we need&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# a systemd override to use this feature&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            tmpdir &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; /run/freeradius/tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;#  The command used to verify the client cert.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;#  We recommend using the OpenSSL command-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;#  tool.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        client &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/usr/bin/openssl verify -CAfile /etc/freeradius/3.0/certs/root.pem %{TLS-Client-Cert-Filename}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#end verify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#end tls&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#end server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clients radsec &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Local host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    client localhost &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ipaddr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ::1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        proto &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; tls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#When using radsec, secret MUST be &amp;#39;radsec&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#this is literally written in the RFC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        secret &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; radsec
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Local network, in CIDR notation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Since we are using cert based auth, it would not be unreasonable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#to allow all (::/0)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    client localnet &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ipaddr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; fd69:beef:cafe::/48
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        proto &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; tls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        secret &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; radsec
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#end radsec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;eap-module-configuration&#34;&gt;EAP Module Configuration&lt;/h3&gt;
&lt;p&gt;Next, we need to setup the certs we will use for EAP. These are different than the ones we use for RADsec. This configuration goes in &lt;code&gt;mods-available/eap&lt;/code&gt;, and I&amp;rsquo;ve written out the whole file so you can replace it if you want. Again, I trimmed comments for features I&amp;rsquo;m not using, so read the original for more context.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;######################################################################&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  EAP-TLS and no other modes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;######################################################################&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;eap &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;#  Invoke the default supported EAP type when&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;#  EAP-Identity response is received.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	default_eap_type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; tls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;# EAP-Request/Response cache timeout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	timer_expire &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;# Reject unknown types&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	ignore_unknown_eap_types &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;#  Help prevent DoS attacks by limiting the number of sessions we track&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	max_sessions &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;max_requests&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;#  Common TLS configuration for TLS-based EAP types&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tls-config tls-common &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#private_key_password = whatever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		private_key_file &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; /etc/freeradius/3.0/certs/radius.apalrd.net.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		certificate_file &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; /etc/freeradius/3.0/certs/radius.apalrd.net.crt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  Trusted Root CA list *for clients*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		ca_file &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; /etc/freeradius/3.0/certs/root.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  Set this option to specify the allowed TLS cipher suites&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		cipher_list &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DEFAULT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  If enabled, OpenSSL will use server cipher list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#  In 2024 leave this disabld&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		cipher_server_preference &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  Set min / max TLS version.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  While the server will accept &amp;#34;1.3&amp;#34; as a value,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  most EAP supplicants WILL NOT DO TLS 1.3 PROPERLY.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  i.e. they WILL NOT WORK, SO DO NOT ASK QUESTIONS ON&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  THE LIST ABOUT WHY IT DOES NOT WORK.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  The TLS 1.3 support is here for future&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  compatibility, as clients get upgraded, and people&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  don&amp;#39;t upgrade their copies of FreeRADIUS.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  Also note that we only support TLS 1.3 for EAP-TLS.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  Other versions of EAP (PEAP, TTLS, FAST) DO NOT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  SUPPORT TLS 1.3.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		tls_min_version &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		tls_max_version &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  Client certificates can be validated via an&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  external command.  This allows dynamic CRLs or OCSP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  to be used.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		verify &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		    tmpdir &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; /run/freeradius/tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;#  The command used to verify the client cert.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;#  We recommend using the OpenSSL command-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;#  tool.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            client &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/usr/bin/openssl verify -CAfile /etc/freeradius/3.0/certs/root.pem %{TLS-Client-Cert-Filename}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;#  EAP-TLS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tls &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# Point to the common TLS configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		tls &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; tls-common
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# EAP PEAP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	peap &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;# Point to the common TLS configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		tls &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; tls-common
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Name of virtual server to handle the inner tunnel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		virtual_server &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;inner-tunnel&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  The tunneled EAP session needs a default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  EAP type which is separate from the one for&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;#  the non-tunneled EAP module.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		default_eap_type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mschapv2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Other things you don&amp;#39;t need to change&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# I cut out paragraphs of docs here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		copy_request_to_tunnel &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		use_tunneled_reply &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#end eap peap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;#  EAP-MSCHAPv2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;#  This will be used *inside* PEAP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	mschapv2 &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#We actually need no config here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# end eap mschapv2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# end eap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;inner-tunnel-configuration-optional&#34;&gt;Inner Tunnel Configuration (Optional)&lt;/h3&gt;
&lt;p&gt;If you need to support clients which only speap EAP-PEAP, then we can configure the &amp;lsquo;inner&amp;rsquo; tunnel. This is basically an EAP session (EAP-MSCHAPv2) inside of another EAP session, and how anyone thought this was intelligent is beyond me.&lt;/p&gt;
&lt;p&gt;If you are NOT using inner tunnel, you can remove the symlink to disable the virtual server: &lt;code&gt;rm sites-enabled/inner-tunnel&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you ARE using inner tunnel, you can leave the symlink alone. The default file is fine.&lt;/p&gt;
&lt;h3 id=&#34;default-server-configuration-optional&#34;&gt;Default Server Configuration (Optional)&lt;/h3&gt;
&lt;p&gt;Since the default server listens on the (insecure) RADIUS ports 1812 and 1813, I removed those lines from the default file (&lt;code&gt;sites-available/default&lt;/code&gt;). In my setup, this is from line 48 (the line immediately after &lt;code&gt;server default {&lt;/code&gt;) to line 272 (right before the comment block for &lt;code&gt;authorize {&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This is purely optional. The current attacks on non-radsec RADIUS all involve attacking the authenticator side and allowing access, so having the RADIUS server exposed in this way is not believed to be a security risk. FreeRADIUS is also protected by not having any clients defined by default, so connections would be rejected anyway. Regardless, I don&amp;rsquo;t want that protocol in use, so I disabled it.&lt;/p&gt;
&lt;p&gt;If you like using the &lt;code&gt;radtest&lt;/code&gt; tool, you could change it to bind to &lt;code&gt;::1&lt;/code&gt; instead of &lt;code&gt;::&lt;/code&gt;, so radtest still works unencrypted on localhost.&lt;/p&gt;
&lt;h2 id=&#34;users-file-optional&#34;&gt;Users File (Optional)&lt;/h2&gt;
&lt;p&gt;The Users file (&lt;code&gt;users&lt;/code&gt;, right in the freeradius directory) stores user info when logging in with a username+password. It&amp;rsquo;s not used in EAP-TLS, since we instead trace the cert and don&amp;rsquo;t actually look at the identity at all, but it&amp;rsquo;s used in PEAP-MSCHAPv2. If you are enabling that one, then here&amp;rsquo;s an example users file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 	Configuration file for the rlm_files module.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 	Please see rlm_files(5) manpage for more information.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#   All lines start with the username, followed by the conditions to accept&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#   Remaining lines are responses. Read the original users file for more help.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# My stupid camera that won&amp;#39;t do TLS, only PEAP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;camera3 Cleartext-Password :&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Same, but only on port 3 of the switch with the right hostname&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;camera5 Cleartext-Password :&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera5&amp;#34;&lt;/span&gt;, NAS-Port-Id &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ether3&amp;#34;&lt;/span&gt;, NAS-Identifier &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sw5.palnet.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Same, but with a specific MAC address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;camera7 Cleartext-Password :&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera7&amp;#34;&lt;/span&gt;, Calling-Station-Id &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;08-ED-ED-F1-1B-32&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Tunnel-Type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; VLAN,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Tunnel-Medium-Type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 802,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Tunnel-Private-Group-ID &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Add it to the camera VLAN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Same, but stuck on a VLAN 9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;camera11 Cleartext-Password :&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera11&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Tunnel-Type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; VLAN,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Tunnel-Medium-Type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 802,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Tunnel-Private-Group-ID &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Add it to the camera VLAN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# DEFAULT reject them&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# You could also := Accept them&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# and give them attributes like default vlan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DEFAULT Auth-Type :&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Reject
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Caching Linux Package Repositories</title>
      <link>https://www.apalrd.net/posts/2024/cluster_debcache/</link>
      <pubDate>Thu, 05 Dec 2024 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/cluster_debcache/</guid>
      <description>Today I&amp;rsquo;m setting up a simple nginx proxy, so I can store updates used by my many Linux systems. Most of them run a derivative of Debian, so this guide focuses mostly on caching apt repositories (Debian, Ubuntu, Proxmox, and more), but the same approach should work with any distro.
Install nginx I&amp;rsquo;m using a Debian 12 (Bookworm) unprivilaged LXC container, but this is basic nginx which should be in every distro ever.</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m setting up a simple nginx proxy, so I can store updates used by my many Linux systems. Most of them run a derivative of Debian, so this guide focuses mostly on caching apt repositories (Debian, Ubuntu, Proxmox, and more), but the same approach should work with any distro.&lt;/p&gt;
&lt;h2 id=&#34;install-nginx&#34;&gt;Install nginx&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m using a Debian 12 (Bookworm) unprivilaged LXC container, but this is basic nginx which should be in every distro ever. I pointed my local DNS address &lt;code&gt;deb.palnet.net&lt;/code&gt; (using a DNS override in Unbound on OPNsense, in my case) to the IP of the container.&lt;/p&gt;
&lt;p&gt;So:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Ensure system is up to date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt upgrade -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install nginx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install nginx -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Set it to autostart&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Remove defaults in sites-enabled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc/nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm sites-enabled/*
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we&amp;rsquo;re ready to setup our cache!&lt;/p&gt;
&lt;h2 id=&#34;nginx-config&#34;&gt;Nginx Config&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s my nginx config (&lt;code&gt;/etc/nginx/sites-available/debcache.conf&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Global Cache settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache_path /var/debcache/cache levels=2:2 keys_zone=generic:500m inactive=3650d max_size=1000g min_free=5g loader_files=1000 loader_sleep=50ms loader_threshold=300ms use_temp_path=off;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Log with cache status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;log_format cachelog &amp;#39;$remote_addr [$time_local] &amp;#34;$request&amp;#34; $status &amp;#34;$http_user_agent&amp;#34; &amp;#34;$upstream_cache_status&amp;#34;&amp;#39;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# URI paths to avoid cache&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# These paths will change to indicate new release contents&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# All other .deb files can be cached nearly indefinitely, as the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# version number is coded into the file name.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;map $request_uri $nocache {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;~InRelease 1;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;~Release 1;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;~Packages 1;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Deb Server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;server {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# IF you need legacy IP, enable this one&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#listen 80 reuseport;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Everyone needs modern IP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;listen [::]:80 reuseport;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Log settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;access_log /var/debcache/access.log cachelog;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;error_log /var/debcache/error.log;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Cache Location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;slice 1m;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache generic;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_ignore_headers Expires Cache-Control;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache_valid 200 206 3650d;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache_valid 301 302 0;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header  Range $slice_range;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache_lock on;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache_lock_age 2m;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache_lock_timeout 1h;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache_revalidate on;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Nocache for those entries&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache_bypass $nocache;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_no_cache $nocache;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 1G max file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_max_temp_file_size 1024m;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Cache key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_cache_key      $http_host$uri$slice_range;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Upstream Configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_next_upstream error timeout http_404;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Cache status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;add_header X-Cache-Status $upstream_cache_status;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_redirect off;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_ignore_client_abort on;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Upstream request headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_ssl_server_name on;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Redirect Locations&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Must include trailing slash!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Debian&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /debian/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass http://deb.debian.org/debian/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;deb.debian.org&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /debsec/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass http://deb.debian.org/debian-security/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;deb.debian.org&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Raspberry Pi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /raspi/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass http://archive.raspberrypi.com/debian/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;archive.raspberrypi.com&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Ubuntu&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /ubuntu/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass http://us.archive.ubuntu.com/ubuntu/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;us.archive.ubuntu.com&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /ubusec/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass http://security.ubuntu.com/ubuntu/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;security.ubuntu.com&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Kali&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /kali/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass http://http.kali.org/kali/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;http.kali.org&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Proxmox (non-enterprise)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /proxmox/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass http://download.proxmox.com/debian/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;download.proxmox.com&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Caddy Server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /caddy/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass https://dl.cloudsmith.io/public/caddy/stable/deb/debian/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;dl.cloudsmith.io&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Nodesource NodeJS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /node/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass http://deb.nodesource.com/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;deb.nodesource.com&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Authelia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /authelia/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass https://apt.authelia.com/stable/debian/debian/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;apt.authelia.com&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Influx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location /influx/ {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_pass http://repos.influxdata.com/debian/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;proxy_set_header Host &amp;#34;repos.influxdata.com&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Stats endpoint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;location = /nginx_status {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;stub_status;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Static Files (conversion scripts)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;root /var/debcache/static/;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;autoindex on;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you are done creating the file, create a link to it in &lt;code&gt;sites-enabled&lt;/code&gt; so it is loaded by nginx:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc/nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s ../sites-available/debcache.conf sites-enabled/debcache.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And restart nginx (&lt;code&gt;systemctl restart nginx&lt;/code&gt;)&lt;/p&gt;
&lt;h2 id=&#34;replacement-script&#34;&gt;Replacement Script&lt;/h2&gt;
&lt;p&gt;I went through all of my Debian systems (to see which repos they are using), and wrote a simple script which uses &lt;code&gt;sed&lt;/code&gt; to replace everything to point to my cache. I chose this approach instead of setting up apt to use a proxy, since this replaces https requests with http requests (to the cache - the cache -&amp;gt; upstream is still using HTTPS). This avoids complications in having apt trust a self-signed proxy cert. The lack of TLS is not significant here since deb packages are GPG signed.&lt;/p&gt;
&lt;p&gt;Anyway, here&amp;rsquo;s the script (put it in &lt;code&gt;/var/debcache/static/rewrite.sh&lt;/code&gt;)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# My mirror location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export mirror&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;http://deb.palnet.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Load OS release info into variables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;. /etc/os-release
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Function to rewrite a single file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rewrite&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo Rewriting $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Debian repos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#http://deb.debian.org/debian-security#$mirror/debsec#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#http://deb.debian.org/debian#$mirror/debian#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#http://ftp.us.debian.org/debian#$mirror/debian#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#http://security.debian.org#$mirror/debsec#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Raspberry Pi repos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#http://archive.raspberrypi.com/debian#$mirror/raspi#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Ubuntu repos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#http://us.archive.ubuntu.com/ubuntu#$mirror/ubuntu#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#http://archive.ubuntu.com/ubuntu#$mirror/ubuntu#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#http://security.ubuntu.com/ubuntu#$mirror/ubusec#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Kali repos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#http://http.kali.org/kali#$mirror/kali#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Proxmox repos (this catches all of them)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#http://download.proxmox.com/debian#$mirror/proxmox#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Caddy server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#https://dl.cloudsmith.io/public/caddy/stable/deb/debian#$mirror/caddy#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#NodeJS from Nodesource&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#https://deb.nodesource.com#$mirror/node#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Authelia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#https://apt.authelia.com/stable/debian/debian#$mirror/authelia#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Influxdata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sed -i s#https://repos.influxdata.com/debian#$mirror/influx#g $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Rewrite sources.list itself&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rewrite &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/etc/apt/sources.list&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Rewrite everything in sources.list.d&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export -f rewrite
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/etc/apt/sources.list.d/&amp;#39;&lt;/span&gt; -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*.list&amp;#34;&lt;/span&gt; -type f -exec bash -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;rewrite &amp;#34;$0&amp;#34;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# If this system is using the &amp;#39;new style&amp;#39; deb mirrors file (/etc/apt/sources.list.d/debian.sources)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Replace it with equivalent sources.list entries&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; test -f &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/etc/apt/sources.list.d/debian.sources&amp;#34;&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Rewriting /etc/apt/sources.list.d/debian.sources to sources.list format&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/debian &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt; main contrib&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb-src &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/debian &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt; main contrib&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/debian &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;-updates main contrib&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb-src &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/debian &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;-updates main contrib&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/debsec &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;-security main contrib&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb-src &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/debsec &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;-security main contrib&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rm /etc/apt/sources.list.d/debian.sources
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Same, but for Ubuntu&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; test -f &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/etc/apt/sources.list.d/ubuntu.sources&amp;#34;&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Rewriting /etc/apt/sources.list.d/ubuntu.sources to sources.list format&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/ubuntu &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt; main universe restricted multiverse&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb-src &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/ubuntu &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt; main universe restricted multiverse&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/ubuntu &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;-updates main universe restricted multiverse&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb-src &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/ubuntu &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;-updates main universe restricted multiverse&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/ubuntu &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;-backports main universe restricted multiverse&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb-src &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/ubuntu &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;-backports main universe restricted multiverse&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/ubusec &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;-security main universe restricted multiverse&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb-src &lt;/span&gt;$mirror&lt;span style=&#34;color:#e6db74&#34;&gt;/ubusec &lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;-security main universe restricted multiverse&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rm /etc/apt/sources.list.d/ubuntu.sources
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, on any system you have, you can run &lt;code&gt;curl deb.palnet.net/rewrite.sh | bash&lt;/code&gt; and it will replace all of the deb references it finds. If you don&amp;rsquo;t have curl, you can do the same thing with &lt;code&gt;wget -q -O - deb.palnet.net/rewrite.sh | bash&lt;/code&gt; (you may need to &lt;code&gt;sudo bash&lt;/code&gt; depending on your current privilege)&lt;/p&gt;
&lt;h2 id=&#34;upgrade-distribution&#34;&gt;Upgrade Distribution&lt;/h2&gt;
&lt;p&gt;Now that I have this place to put deb upgrade scripts, I wrote another one to replace &lt;code&gt;bookworm&lt;/code&gt; with &lt;code&gt;trixie&lt;/code&gt; to help upgrade deb systems easily.&lt;/p&gt;
&lt;p&gt;This one goes in &lt;code&gt;/var/debcache/static/bookworm2trixie.sh&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Only do sources.list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sed -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/bookworm/trixie/g&amp;#39;&lt;/span&gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and you can again get to it at &lt;code&gt;deb.palnet.net/bookworm2trixie.sh&lt;/code&gt; and pipe it into bash.&lt;/p&gt;
&lt;h2 id=&#34;monitoring&#34;&gt;Monitoring&lt;/h2&gt;
&lt;p&gt;You can access the logs of your cache from the debcache system, to see if you are getting hits or misses. The first system to update will miss everything, but after that the hit rate should be decent.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tail -f /var/debcache/access.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Or for the error file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tail -f /var/debcache/error.log
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Securely Expose your Homelab Services with Mutual TLS</title>
      <link>https://www.apalrd.net/posts/2024/network_mtls/</link>
      <pubDate>Fri, 22 Nov 2024 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/network_mtls/</guid>
      <description>Today I&amp;rsquo;m diving into Mutual TLS to securely expose my homelab services! TLS is already ubiquitous in the modern era, providing strong symmetric encryption, perfect forward secrecy, and a public chain of trust to authenticate the server. But, it also has a lesser known ability to authenticate the client. By creating our own certificate authority to issue certs to clients, we can securely authenticate them to the server, preventing other users from even hitting our web app and probing it for vulnerabilities.</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m diving into Mutual TLS to securely expose my homelab services! TLS is already ubiquitous in the modern era, providing strong symmetric encryption, perfect forward secrecy, and a public chain of trust to authenticate the server. But, it also has a lesser known ability to authenticate the client. By creating our own certificate authority to issue certs to clients, we can securely authenticate them to the server, preventing other users from even hitting our web app and probing it for vulnerabilities.&lt;/p&gt;
&lt;p&gt;This is a simpler solution than using a VPN to &amp;rsquo;expose&amp;rsquo; your services, as long as the app is already relying on TLS (which includes more protocols than just HTTPS). There&amp;rsquo;s less user friction in installing a .p12 cert than setting up a VPN client, which could be important if you are sharing your services with friends and family.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_mtls/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_mtls/#create-a-simple-root-ca&#34;&gt;Simple CA - Create Root&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_mtls/#sign-a-user-cert-using-the-root-ca&#34;&gt;Simple CA - Sign Client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_mtls/#sign-a-user-cert-using-smallstep&#34;&gt;Smallstep CA - Sign Client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_mtls/#setup-caddy-for-client-auth&#34;&gt;Server - Caddy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_mtls/#setup-nginx-for-client-auth&#34;&gt;Server - Nginx&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/YhuWay9XJyw&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2024/network_mtls/thumbnail1.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;create-a-simple-root-ca&#34;&gt;Create a Simple Root CA&lt;/h2&gt;
&lt;p&gt;This is section will setup a small 2-layer (root + leaf) authority, instead of the usual 3-layer (root + intermediate + leaf), for testing only. You should probably use the Smallstep CA for anything scalable.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m also using an ECDSA key chain, more to see how the process compares to RSA. So, the root will use scep384. I chose scep384 due to its arguably overkill security level, roughly equivalent to ~7000 bit RSA.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate private key using scep384:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl ecparam -name secp384r1 -genkey -out root.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign the root certificate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Pathlen:0 means there can be only one more cert below this CA (no more CAs)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make sure you update the subj name with your own names&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#C=US is also the country, it&amp;#39;s optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#O= is the organization, also optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#CN= is the Common Name and it&amp;#39;s required&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#I also set validity to 4 years, make sure you watch for expiration (manually)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl req -new -key root.key -x509 -nodes -days &lt;span style=&#34;color:#ae81ff&#34;&gt;1461&lt;/span&gt; -out root.pem -subj &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/C=US/O=apalrd.net/CN=test&amp;#34;&lt;/span&gt; -addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;basicConstraints=critical,CA:TRUE,pathlen:0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now you can view it (for fun)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -in root.pem -text -noout
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;sign-a-user-cert-using-the-root-ca&#34;&gt;Sign a User Cert using the Root CA&lt;/h2&gt;
&lt;p&gt;Now we can use openssl to generate and sign a user cert using the root key. I chose scep256 for this since it has a smaller &amp;lsquo;blast radius&amp;rsquo; than the root and scep256 still provides roughly equivalent security to rsa 3072.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate scep256 key for this client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl ecparam -name prime256v1 -genkey -out adventure@apalrd.net.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate a CSR (certificate signing request) for my new key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#again, C and O are optional, CN is the Common Name of the cert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl req -new -key adventure@apalrd.net.key -out adventure@apalrd.net.csr -subj &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/C=US/O=apalrd.net/CN=adventure@apalrd.net&amp;#34;&lt;/span&gt; -addext &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;extendedKeyUsage = clientAuth&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign the CSR using the root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign it allowing for server and client auth as the key usage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -req -in adventure@apalrd.net.csr -CA root.pem -CAkey root.key -CAcreateserial -out adventure@apalrd.net.crt -days &lt;span style=&#34;color:#ae81ff&#34;&gt;365&lt;/span&gt; -sha256 -copy_extensions&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;copyall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now you can view it (for fun)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl x509 -in adventure@apalrd.net.crt -text -noout
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now let&amp;#39;s package it into a P12 archive so you can send it to your favorite client device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#You *must* enter a password here or some OSes will not accept the P12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The password just encrypts the P12 file itself&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl pkcs12 -export -out adventure@apalrd.net.p12 -in adventure@apalrd.net.crt -inkey adventure@apalrd.net.key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Important note, I know it&amp;rsquo;s tempting to try to use Bernsein&amp;rsquo;s curves (ed25519 especially), but they aren&amp;rsquo;t approved by the CA + Browser Forum for use in public CAs, and aren&amp;rsquo;t implemented in any major web browser. So, I&amp;rsquo;ve chosen scep256 (which OpenSSL confusingly calls prime256) and scep384 for my CA. Of course, RSA is always an option as well.&lt;/p&gt;
&lt;h2 id=&#34;sign-a-user-cert-using-smallstep&#34;&gt;Sign a User Cert using Smallstep&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve already setup a Smallstep CA from my previous TLS videos, you can use that instead of OpenSSL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign cert (run as root on the CA)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#laptop.crt/laptop.key are the key files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#I signed this one for a long ass time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;step ca certificate adventure@apalrd.net laptop.crt laptop.key --not-after&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;2160h 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Bundle into p12 and include intermediate cert we are using&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The P12 file can be imported into any OS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;step certificate p12 laptop.p12 laptop.crt laptop.key --ca /etc/step/certs/intermediate_ca.crt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;setup-caddy-for-client-auth&#34;&gt;Setup Caddy for Client Auth&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the Caddyfile I used (Debian packs a start page with Caddy):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The Caddyfile is an easy way to configure your Caddy web server.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#TLS email (global section)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Please stop using my email for your Let&amp;#39;s Encrypt certs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#I am sick of getting your renewal notices&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    email mail@example.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Test website&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test1.apalrd.net &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Caddy example lives here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    root * /usr/share/caddy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    file_server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#mTLS verify client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tls &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        client_auth &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;#Default is none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;#there are other options here if you want it to be optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;#i.e. to bypass a signin page when using mTLS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            mode require_and_verify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            trust_pool file &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;#Can be specified multiple times for multiple roots&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                pem_file /etc/caddy/root.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, you can make a snippet in the config to make it easier - this Caddyfile has the exact same behavior:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The Caddyfile is an easy way to configure your Caddy web server.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#TLS email (global section)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Please stop using my email for your Let&amp;#39;s Encrypt certs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#I am sick of getting your renewal notices&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    email mail@example.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Snippet for TLS client auth&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;tls_client&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#mTLS verify client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tls &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        client_auth &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;#Default is none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;#there are other options here if you want it to be optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;#i.e. to bypass a signin page when using mTLS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            mode require_and_verify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            trust_pool file &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;#Can be specified multiple times for multiple roots&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                pem_file /etc/caddy/root.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Test website&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test1.apalrd.net &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Caddy example lives here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    root * /usr/share/caddy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    file_server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Reuse the snipper from earlier&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    import tls_client
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;setup-nginx-for-client-auth&#34;&gt;Setup Nginx for Client Auth&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a full nginx configuration (&lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt;) with client auth. The default Debian config is quite .. verbose .. so I&amp;rsquo;ve cut out a lot of things which &lt;em&gt;I&lt;/em&gt; didn&amp;rsquo;t need, but you might have needed them. Anyway, it&amp;rsquo;s framework. Nginx on Debian also subscribes to the whole &lt;code&gt;sites-available&lt;/code&gt; and &lt;code&gt;sites-enabled&lt;/code&gt; thing, which I find unnecessary.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user www-data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;worker_processes auto;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;worker_cpu_affinity auto;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pid /run/nginx.pid;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;error_log /var/log/nginx/error.log;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;include /etc/nginx/modules-enabled/*.conf;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;events &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    worker_connections 768;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# multi_accept on;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;http &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Basic Settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sendfile on;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tcp_nopush on;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    types_hash_max_size 2048;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    server_tokens off; &lt;span style=&#34;color:#75715e&#34;&gt;# Recommended practice is to turn this off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# server_names_hash_bucket_size 64;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# server_name_in_redirect off;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    include /etc/nginx/mime.types;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    default_type application/octet-stream;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# SSL Settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ssl_protocols TLSv1.2 TLSv1.3; &lt;span style=&#34;color:#75715e&#34;&gt;# Dropping SSLv3 (POODLE), TLS 1.0, 1.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ssl_prefer_server_ciphers off; &lt;span style=&#34;color:#75715e&#34;&gt;# Don&amp;#39;t force server cipher order.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Logging Settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    access_log /var/log/nginx/access.log;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Gzip Settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gzip on;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Virtual Host Configs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Redirect all HTTP to HTTPS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    server &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        listen &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt; default_server;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        server_name _;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;301&lt;/span&gt; https://$host$request_uri;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Default (TLS) server configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    server &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# TLS (Server) configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        listen &lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt; ssl default_server;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        listen &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;::&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;:443 ssl default_server;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# This is where Certbot puts them in standalone mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ssl_certificate     /etc/letsencrypt/live/test-nginx.apalrd.net/fullchain.pem;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ssl_certificate_key /etc/letsencrypt/live/test-nginx.apalrd.net/privkey.pem;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# TLS (Client) configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Possible values are &amp;#39;on&amp;#39; or &amp;#39;optional&amp;#39; (or &amp;#39;off&amp;#39;, the default)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# If you use &amp;#39;on&amp;#39;, nginx will return 400 Bad Request if it fails&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# If you like 400, then use &amp;#39;on&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# If you&amp;#39;d rather drop, then use &amp;#39;optional&amp;#39; and drop below (return 444)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ssl_verify_client optional;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Path to the client CA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ssl_client_certificate /etc/nginx/root.pem;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Number of steps we allow from the root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ssl_verify_depth 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Drop connections which fail verification (optional)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;$ssl_client_verify !&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SUCCESS&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; 444; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Example website&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        root /var/www/html;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Add index.php to the list if you are using PHP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        index index.html index.htm index.nginx-debian.html;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        server_name _;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        location / &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;# First attempt to serve request as file, then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;# as directory, then fall back to displaying a 404.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                try_files $uri $uri/ &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;404;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Single Root IO Virtualization in Proxmox (for NICs)</title>
      <link>https://www.apalrd.net/posts/2024/pve_sriov/</link>
      <pubDate>Tue, 05 Nov 2024 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/pve_sriov/</guid>
      <description>In this episode, I&amp;rsquo;m playing with Single Root I/O Virtualization (SR-IOV) in Proxmox Virtual Environment (PVE). I&amp;rsquo;ve heard ruomors that it will be anything from a minor to major improvement in IO performance for my VMs, so I wanted to do some testing on my own system to be sure.
Please don&amp;rsquo;t take my results as final, I&amp;rsquo;m not comfortable saying that I&amp;rsquo;ve removed all of the background tasks and load from the measurements.</description>
      <content>&lt;p&gt;In this episode, I&amp;rsquo;m playing with Single Root I/O Virtualization (SR-IOV) in Proxmox Virtual Environment (PVE). I&amp;rsquo;ve heard ruomors that it will be anything from a minor to major improvement in IO performance for my VMs, so I wanted to do some testing on my own system to be sure.&lt;/p&gt;
&lt;p&gt;Please don&amp;rsquo;t take my results as final, I&amp;rsquo;m not comfortable saying that I&amp;rsquo;ve removed all of the background tasks and load from the measurements. My system is also relatively underpowered, so this may show as a thread-bound performance limit on some of these drivers where your system may not have this issue.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/pve_sriov/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/pve_sriov/#enable-sr-iov&#34;&gt;Enable SR-IOV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/pve_sriov/#lxc&#34;&gt;LXC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/pve_sriov/#mellanox-mstflint&#34;&gt;Mellanox MSTFLINT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/AdzeMpBIXlQ&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2024/pve_sriov/thumbnail2.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;enable-sr-iov&#34;&gt;Enable SR-IOV&lt;/h2&gt;
&lt;p&gt;Prerequisites:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your card supports SR-IOV&lt;/li&gt;
&lt;li&gt;You have enabled SR-IOV in the card firmware if required (See MSTFLINT below for MLX5)&lt;/li&gt;
&lt;li&gt;You have enabled IOMMU and PCIe ACS in your BIOS/UEFI firmware&lt;/li&gt;
&lt;li&gt;You have enabled IOMMU in the kernel (intel_iommu=on or amd_iommu=on) and functioning correctly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once all of that is done, to enable SR-IOV, you just need to set a particular sysctl which corresponds to your network device. The sysctl is the same for all drivers (Intel/Mellanox). This is NOT persistent across reboots. I didn&amp;rsquo;t bother scripting a way to automate this for my tests, and since I&amp;rsquo;m not going to continue to use SR-IOV, I also didn&amp;rsquo;t write it here. Anyway:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt; &amp;gt; /sys/class/net/enpXXsYfZ/device/sriov_num_vfs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Obviously change the enpXX with the full name of your own device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#f0 is the physical function of the card and should already exist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#f1+ are the virtual functions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#At this point it will possibly take awhile and if you are unlucky&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#and have system IOMMU / ACS issues it could hang here for 60+ seconds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;lxc&#34;&gt;LXC&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the LXC configuration I used. Proxmox renames the link on starting/stopping an LXC container, and sometimes it doesn&amp;rsquo;t rename back correctly. Be warned.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.apparmor.profile&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;unconfined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.net.2.type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;phys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.net.2.link&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;enp1s0f0v3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.net.2.flags&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.net.2.ipv6.address&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;fc69::4/64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;mellanox-mstflint&#34;&gt;Mellanox MSTFLINT&lt;/h2&gt;
&lt;p&gt;If you are using a Mellanox (now Nvidia) card, you may need to configure the firmware to enable SR-IOV and also set the number of VFs. This is persistent to the card, so if you bought your card used it may already be configured this way. In any case, here&amp;rsquo;s the commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#apt update if you haven&amp;#39;t recently&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install mstflint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Find the PCI ID of the card&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lspci
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#My card was 01:00.0 and 01:00.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Query all of the info, if you are qurious what the card is configured as&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mstconfig -d 01:00.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Configure the VFs and enable SR_IOV&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mstconfig -d 01:00.0 set NUM_OF_VFS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt; SRIOV_EN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Reboot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Using NETCONSOLE to debug Linux (and Proxmox) Kernel Panics</title>
      <link>https://www.apalrd.net/posts/2024/pve_netconsole/</link>
      <pubDate>Fri, 05 Jul 2024 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/pve_netconsole/</guid>
      <description>In this post (and video) I&amp;rsquo;m going to setup Netconsole, so you can capture kernel panics and logs on headless systems. I know some of you are doing wild things with graphics drivers and passthrough, so hopefully this helps you debug them.
Enable Now This option enables the module immediately, so you can use it before you do dangerous things. You Simply rebooting clears the setting, so you won&amp;rsquo;t continue to spam your kernel messages on the local network.</description>
      <content>&lt;p&gt;In this post (and video) I&amp;rsquo;m going to setup Netconsole, so you can capture kernel panics and logs on headless systems. I know some of you are doing wild things with graphics drivers and passthrough, so hopefully this helps you debug them.&lt;/p&gt;
&lt;h2 id=&#34;enable-now&#34;&gt;Enable Now&lt;/h2&gt;
&lt;p&gt;This option enables the module immediately, so you can use it before you do dangerous things. You Simply rebooting clears the setting, so you won&amp;rsquo;t continue to spam your kernel messages on the local network.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;modprobe netconsole netconsole&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;@/eth0,@&amp;lt;destination_IP_address&amp;gt;/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want the full syntax of the argument, &lt;a href=&#34;https://www.kernel.org/doc/html/latest/networking/netconsole.html#sender-and-receiver-configuration&#34;&gt;you can find it here&lt;/a&gt;. I&amp;rsquo;m leaving a lot of things as defaults, so it will use the broadcast MAC and UDP port 6666.&lt;/p&gt;
&lt;p&gt;And to disable it without rebooting:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rmmod netconsole
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;enable-on-boot&#34;&gt;Enable On Boot&lt;/h2&gt;
&lt;p&gt;This will take effect on the next boot. Similar arguments to above, except we need to add this to the kernel commandline. Also, since the interface won&amp;rsquo;t have this addresses early in boot the process, it&amp;rsquo;s easiest if we use IPv6 link-local addresses. The kernel will generate one from the MAC address. The other option if you want to use legacy IPv4 is to set a source IP address in the kernel command line, this does not have to be the same address you use in the system.&lt;/p&gt;
&lt;p&gt;On Debian systems and some Proxmox systems, the file we need to edit is &lt;code&gt;/etc/default/grub&lt;/code&gt;. On Proxox systems using UEFI boot but &lt;em&gt;not&lt;/em&gt; secure boot, the file we need to edit is &lt;code&gt;/etc/kernel/cmdline&lt;/code&gt;. If you don&amp;rsquo;t have an &lt;code&gt;/etc/kernel/cmdline&lt;/code&gt;, then you need to edit &lt;code&gt;/etc/default/grub&lt;/code&gt;. Anyway, add this to the command line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;netconsole&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;@/eth0,@&amp;lt;destination_IPv6_LL_address&amp;gt;/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we need to run either &lt;code&gt;update-grub&lt;/code&gt; (if you used &lt;code&gt;/etc/default/grub&lt;/code&gt;) or &lt;code&gt;proxmox-boot-tool refresh&lt;/code&gt; (if you used &lt;code&gt;/etc/kernel/cmdline&lt;/code&gt;, and possibly on any Proxmox systems, it doesn&amp;rsquo;t hurt)&lt;/p&gt;
&lt;p&gt;When you reboot, you can check &lt;code&gt;dmesg | grep netcon&lt;/code&gt; to see if it started or if there were errors. If your Ethernet devices goes by multiple names in the boot process, try to &lt;code&gt;dmesg | grep eth0&lt;/code&gt; and see what other names it goes by, and try those if it fails.&lt;/p&gt;
&lt;h2 id=&#34;receive-netconsole-with-netcat&#34;&gt;Receive Netconsole with Netcat&lt;/h2&gt;
&lt;p&gt;Now, we need to setup Netcat to listen to that broadcast. It&amp;rsquo;s sending it to the broadcast MAC address (all F&amp;rsquo;s), but to a unicast IP address, so anyone on the network will see this traffic with Wireshark. But netcat is easier. The default netcat version with Debian doesn&amp;rsquo;t support IPv6, but you can &lt;code&gt;apt install ncat&lt;/code&gt; for a better version, and it will install itself as the &lt;code&gt;nc&lt;/code&gt; command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Call netcat to listen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#-l = listen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#-u = udp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#-p 6666 = the default port for netconsole &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nc -l -u -p &lt;span style=&#34;color:#ae81ff&#34;&gt;6666&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can run as long as you want to monitor the netconsole output.&lt;/p&gt;
&lt;h2 id=&#34;receive-netconsole-with-a-simple-systemd-unit&#34;&gt;Receive Netconsole with a simple systemd unit&lt;/h2&gt;
&lt;p&gt;This is a super simple systemd service which will run netcat and save it to the systemd journal. Useful for cases when your crash is intermittent. You can run this on any machine on the network (of course you need to have netconsole set for this IP as well). Save this as &lt;code&gt;/etc/systemd/system/netconsole-log.service&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr/bin/nc -l -u -p &lt;span style=&#34;color:#ae81ff&#34;&gt;6666&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then start it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now netconsole-log
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And view the logs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;journalctl -xeu netconsole-log
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;panic&#34;&gt;Panic&lt;/h2&gt;
&lt;p&gt;If you want to panic the system, then you can send the sysreq &amp;lsquo;c&amp;rsquo; (as root):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo c &amp;gt; /proc/sysrq-trigger
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&#34;https://www.kernel.org/doc/html/latest/admin-guide/sysrq.html&#34;&gt;Here&amp;rsquo;s a list of all the sysreqs you can trigger for fun.&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Imaging a bare-metal system using Proxmox Backup Client</title>
      <link>https://www.apalrd.net/posts/2024/pbs_image/</link>
      <pubDate>Sat, 29 Jun 2024 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/pbs_image/</guid>
      <description>Since I like to image systems I&amp;rsquo;m testing, here&amp;rsquo;s the process I use to capture the boot drive of a bare metal system in Proxmox Backup Server. I start by booting into a Debian Live image (the small one without a GUI).
Next, I install Proxmox Backup Client from apt packages:
#Run as root sudo bash #Add repo wget https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg echo &amp;#34;deb http://download.proxmox.com/debian/pbs-client bookworm main&amp;#34; &amp;gt; /etc/apt/sources.list.d/pbs-client.list #Install PBS apt update apt install proxmox-backup-client -y After that, I set the environment variables for the backup client (I have a doc I can copy/paste from into my USB KVM):</description>
      <content>&lt;p&gt;Since I like to image systems I&amp;rsquo;m testing, here&amp;rsquo;s the process I use to capture the boot drive of a bare metal system in Proxmox Backup Server. I start by booting into a Debian Live image (the small one without a GUI).&lt;/p&gt;
&lt;p&gt;Next, I install Proxmox Backup Client from apt packages:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run as root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo bash
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb http://download.proxmox.com/debian/pbs-client bookworm main&amp;#34;&lt;/span&gt; &amp;gt; /etc/apt/sources.list.d/pbs-client.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install PBS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install proxmox-backup-client -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After that, I set the environment variables for the backup client (I have a doc I can copy/paste from into my USB KVM):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Environment variables - these will be your Proxmox Backup user and stuff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PBS_REPOSITORY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;user@realm@dns_name.lan:datastore
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PBS_PASSWORD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;api_key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PBS_FINGERPRINT&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fingerprint&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finaly, run the image itself. The &amp;lsquo;backup-id&amp;rsquo; comes across as &amp;lsquo;host&amp;rsquo; in PBS, so I name it only once per physical system, and I can add notes later in the PBS UI as to which backup of the dxp4800 this was. Syntax is &lt;file&gt;.img:/dev/disk. I always use root.img for the root disk, and this captures the entire disk, not partitions.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#root.img is the name of the image (stored in the backup), you can add this multiple times for multiple disks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#/dev/nvme0n1 is the disk that will be copied into root.img&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#backup-id is the &amp;#39;host name&amp;#39; as stored in Proxmox Backup Server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;proxmox-backup-client backup root.img:/dev/nvme0n1 --backup-id &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ugreen-dxp4800&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Restore works similarly, except we do restore instead of backup:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Restore command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy the backup id from the PBS UI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#root.img is the name of the image from the backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#/dev/nvme0n1 is the disk we are restoring onto&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;proxmox-backup-client restore host/hostname/2024-06-30T12:11:46Z root.img - | sudo dd of&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/dev/nvme0n1 status&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;progress bs&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;1M
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Rebuilding Proxmox Backup Server from Backups</title>
      <link>https://www.apalrd.net/posts/2024/pbs_rebuild/</link>
      <pubDate>Thu, 27 Jun 2024 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/pbs_rebuild/</guid>
      <description>So, while I was on vacation, my Proxmox Backup Server boot drive failed! No problem, I take backups of the server itself &amp;hellip;. onto the backup server. So in this video, I&amp;rsquo;m going to start from a clean PBS install, mount my intact backup pool, and then restore the PBS configs out of the backup.
Video Restoring the Datastore First, we need to mount the data disks. In my case, they are a zfs pool named backup, so we use zpool import -f backup to import the pool.</description>
      <content>&lt;p&gt;So, while I was on vacation, my Proxmox Backup Server boot drive failed! No problem, I take backups of the server itself &amp;hellip;. onto the backup server. So in this video, I&amp;rsquo;m going to start from a clean PBS install, mount my intact backup pool, and then restore the PBS configs out of the backup.&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/qf49bTDDHMM&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2024/pbs_rebuild/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;restoring-the-datastore&#34;&gt;Restoring the Datastore&lt;/h1&gt;
&lt;p&gt;First, we need to mount the data disks. In my case, they are a zfs pool named &lt;code&gt;backup&lt;/code&gt;, so we use &lt;code&gt;zpool import -f backup&lt;/code&gt; to import the pool. Once the pool is imported, the directories should show up (you can find them with &lt;code&gt;zfs list&lt;/code&gt; if you forgot where they are).&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using non-zfs, you&amp;rsquo;ll probably have to write a line in &lt;code&gt;/etc/fstab&lt;/code&gt; and mount them the traditional way.&lt;/p&gt;
&lt;p&gt;Now, to get PBS to find the dataset on a brand new PBS system, we need to create a &lt;code&gt;datastore.cfg&lt;/code&gt; which points to the directory of the datastore. That file won&amp;rsquo;t exist if we have no datastores, so create it (&lt;code&gt;/etc/proxmox-backup/datastore.cfg&lt;/code&gt;) with the following contents:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;datastore&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;path /path/to/your/backups&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Refresh in the GUI and it should appear, and you should be able to access your backups at this point (although user accounts and such aren&amp;rsquo;t back yet).&lt;/p&gt;
&lt;h1 id=&#34;restore-the-backup&#34;&gt;Restore the Backup&lt;/h1&gt;
&lt;p&gt;Since we are running on the PBS host, we have access to PBS client (the binary is installed) and we can just point it at &lt;code&gt;localhost&lt;/code&gt;. We won&amp;rsquo;t need the fingerprint to trust localhost, but we will need a username and password, and the long full name of the backup (the one with the date in it). Here&amp;rsquo;s the command I used to mount the backup temporarily:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create a directory to mount at (this can&amp;#39;t exist already)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /mnt/backup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Call the backup client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;proxmox-backup-client mount host/bigstor/2024-05-04T04:00:58Z root.pxar /mnt/backup --repository localhost:backup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At that point, we can rsync the contents of &lt;code&gt;/etc/proxmox-backup&lt;/code&gt; from the backup into its old home. It&amp;rsquo;s critical that you use &lt;code&gt;rsync&lt;/code&gt; and not &lt;code&gt;cp&lt;/code&gt; to do this, since cp will not retain file permissions!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy data from backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rsync -r -v /mnt/backup/etc/proxmox-backup/ /etc/proxmox-backup/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point I would unmount the backup (&lt;code&gt;unmount /mnt/backup&lt;/code&gt;) and restart the services. Make sure they come up fine. Also, delete pre-existing temporary files that were in the backup.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Delete temp files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -rf /etc/proxmox-backup/.*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Restart proxmox backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl restart proxmox-backup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl restart proxmox-backup-proxy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you need to look at logs:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;journalctl -xeu proxmox-backup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;journalctl -xeu proxmox-backup-proxy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that this is done, I copied the remaining files on the system out of the backup (my autoshutdown scripts and other systemd units). You may have authentication errors with &lt;code&gt;proxmox-backup-client&lt;/code&gt; after restoring since sessions will be terminated (we deleted those session temp files), so you will need to run &lt;code&gt;proxmox-backup-client logout&lt;/code&gt; to clear the client&amp;rsquo;s session cache and start over.&lt;/p&gt;
&lt;h1 id=&#34;auto-backup-scripts&#34;&gt;Auto-Backup Scripts&lt;/h1&gt;
&lt;p&gt;Here&amp;rsquo;s the script I use for autobackup. It&amp;rsquo;s a systemd service unit + systemd timer. I use this script on a lot of my Debian systems which are not part of PVE.&lt;/p&gt;
&lt;p&gt;The service (&lt;code&gt;/etc/systemd/system/autobackup.service&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Run Backup to Proxmox Backup Server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;network-online.target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Technically if we are on localhost we can skip the fingerprint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Environment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;PBS_FINGERPRINT&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;your_fingerptint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Your API key here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Environment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;PBS_PASSWORD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;api_key_here
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Use your user @ realm ! api key name @ hostname : repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Environment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;PBS_REPOSITORY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;user@pbs!apikey@localhost:backup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;oneshot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup the root fs. This will not backup any other mount points, only the mount point which mounts /&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#You can add more pxars if you want more mount points&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;proxmox-backup-client backup root.pxar:/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;default.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the timer (&lt;code&gt;/etc/systemd/system/autobackup.timer&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Backup System Daily
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RefuseManualStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RefuseManualStop&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Timer&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run 540 seconds after boot for the first time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Since I shutdown every night, this will be every day&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OnBootSec&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run at midnight UTC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you don&amp;#39;t shutdown every night, uncomment this instead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#OnCalendar=*-*-* 00:00:00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;autobackup.service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;timers.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, we enable the &lt;em&gt;timer&lt;/em&gt;, not the service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now autobackup.timer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All done! You can test it by running &lt;code&gt;systemctl start autobackup&lt;/code&gt; which will run a backup now.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Simple Self-Hosted Security with Authelia</title>
      <link>https://www.apalrd.net/posts/2024/ultimate_authelia/</link>
      <pubDate>Wed, 19 Jun 2024 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/ultimate_authelia/</guid>
      <description>In this video, I&amp;rsquo;m setting up Authelia. It&amp;rsquo;s a very lightweight authentication service, which can be used to provide authentication to services which don&amp;rsquo;t natively support any form of authentication. I think this is a great choice for small scale homelab environments, as it&amp;rsquo;s simple to run and administer.
Contents Video Authelia Configuration User File TLS Certificate Protected Service Example with Caddy Video Authelia I installed Authelia on an LXC container (Debian 12), and set it up with a dns name / AAAA record in public dns, and all the jazz required for normal HTTPS access.</description>
      <content>&lt;p&gt;In this video, I&amp;rsquo;m setting up Authelia. It&amp;rsquo;s a very lightweight authentication service, which can be used to provide authentication to services which don&amp;rsquo;t natively support any form of authentication. I think this is a great choice for small scale homelab environments, as it&amp;rsquo;s simple to run and administer.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/ultimate_authelia/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/ultimate_authelia/#authelia&#34;&gt;Authelia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/ultimate_authelia/#configuration&#34;&gt;Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/ultimate_authelia/#initial-user-file&#34;&gt;User File&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/ultimate_authelia/#tls-certificate&#34;&gt;TLS Certificate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/ultimate_authelia/#protected-service-example&#34;&gt;Protected Service Example with Caddy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/-9Psb0ztMuI&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2024/ultimate_authelia/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;authelia&#34;&gt;Authelia&lt;/h1&gt;
&lt;p&gt;I installed Authelia on an LXC container (Debian 12), and set it up with a dns name / AAAA record in public dns, and all the jazz required for normal HTTPS access. And of course did updates (&lt;code&gt;apt update &amp;amp;&amp;amp; apt full-upgrade -y&lt;/code&gt;) before starting.&lt;/p&gt;
&lt;h3 id=&#34;base-install&#34;&gt;Base Install&lt;/h3&gt;
&lt;p&gt;Now, we are going to install Auehtlia from their apt repository to make updates smooth in the future. The Debian repos tend to lag behind.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install required software for the apt repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y apt-transport-https curl gnupg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Download their signing key, add it with gpg / apt-key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl https://apt.authelia.com/organization/signing.asc | apt-key add -
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add their repo to sources.list.d&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb https://apt.authelia.com/stable/debian/debian/ all main&amp;#34;&lt;/span&gt; &amp;gt; /etc/apt/sources.list.d/authelia-stable-debian.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install authelia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y authelia
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want to run with high availability (since authentication is critical), &lt;a href=&#34;https://www.authelia.com/overview/authorization/statelessness/&#34;&gt;follow the guide here from authelia&lt;/a&gt;. In particular, you will need to setup the required services (Redis and Postgres) in HA themselves. I am not doing an HA setup, so I am using local databases (SQLite) for simplicity.&lt;/p&gt;
&lt;h3 id=&#34;allow-low-numbered-ports&#34;&gt;Allow Low-Numbered Ports&lt;/h3&gt;
&lt;p&gt;To get traffic to Authelia (port 9091) from the real TLS port (443), I found it is easiest to just port forward than to modify the service to add the appropriate capabilities. So, I wrote a port-forward service (&lt;code&gt;/etc/systemd/system/authportfwd.service&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Authelia Port Forwarding Service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;network.target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;oneshot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Of course you can delete the iptabes if you are in the modern era exclusively&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStartPost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;iptables -t nat -A PREROUTING -p tcp --dport &lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt; -j REDIRECT --to-ports &lt;span style=&#34;color:#ae81ff&#34;&gt;9091&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStopPre&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;iptables -t nat -D PREROUTING -p tcp --dport &lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt; -j REDIRECT --to-ports &lt;span style=&#34;color:#ae81ff&#34;&gt;9091&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStartPost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ip6tables -t nat -A PREROUTING -p tcp --dport &lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt; -j REDIRECT --to-ports &lt;span style=&#34;color:#ae81ff&#34;&gt;9091&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStopPre&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ip6tables -t nat -D PREROUTING -p tcp --dport &lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt; -j REDIRECT --to-ports &lt;span style=&#34;color:#ae81ff&#34;&gt;9091&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/bin/true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, we also need to make sure iptables is installed, then we can enable the service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install iptables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install iptables
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Enable it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now authportfwd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;configuration&#34;&gt;Configuration&lt;/h3&gt;
&lt;p&gt;Now we need to write our &lt;code&gt;configuration.yml&lt;/code&gt;. It&amp;rsquo;s stored in &lt;code&gt;/etc/authelia/configuration.yml&lt;/code&gt;. The package should have installed a default, so now we just need to modify it. The &lt;a href=&#34;https://www.authelia.com/integration/prologue/get-started/&#34;&gt;Getting Started Guide&lt;/a&gt; has great tips here. I configured it to use TLS with the default Certbot configuration, see below for Certbot itself.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what I used (this is a diff):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;--- /etc/authelia/configuration.yml.default     2024-05-27 15:27:17.203817464 +0000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+++ /etc/authelia/configuration.yml     2024-05-27 21:42:31.879622715 +0000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -21,7 +21,8 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; # certificates_directory: &amp;#39;/config/certificates/&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ## The theme to display: light, dark, grey, auto.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-# theme: &amp;#39;light&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+#All hail dark mode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+theme: &amp;#39;dark&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ## Set the default 2FA method for new users and for when a user has a preferred method configured that has been
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ## disabled. This setting must be a method that is enabled.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -31,7 +32,7 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ## Server Configuration
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-# server:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+server:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;   ## The address for the Main server to listen on in the address common syntax.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## Formats:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ##  - [&amp;lt;scheme&amp;gt;://]&amp;lt;hostname&amp;gt;[:&amp;lt;port&amp;gt;][/&amp;lt;path&amp;gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -50,12 +53,12 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;   # disable_healthcheck: false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## Authelia by default doesn&amp;#39;t accept TLS communication on the server port. This section overrides this behaviour.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-  # tls:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+  tls:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;     ## The path to the DER base64/PEM format private key.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # key: &amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    key: &amp;#39;/etc/letsencrypt/live/auth.apalrd.net/privkey.pem&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## The path to the DER base64/PEM format public certificate.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # certificate: &amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    certificate: &amp;#39;/etc/letsencrypt/live/auth.apalrd.net/fullchain.pem&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## The list of certificates for client authentication.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     # client_certificates: []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -94,7 +97,7 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## Server Endpoints configuration.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## This section is considered advanced and it SHOULD NOT be configured unless you&amp;#39;ve read the relevant documentation.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-  # endpoints:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+  endpoints:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;     ## Enables the pprof endpoint.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     # enable_pprof: false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -102,10 +105,10 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;     # enable_expvars: false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## Configure the authz endpoints.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # authz:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-      # forward-auth:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-        # implementation: &amp;#39;ForwardAuth&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-        # authn_strategies: []
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    authz:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+      forward-auth:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+        implementation: &amp;#39;ForwardAuth&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+        authn_strategies: []
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;       # ext-authz:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         # implementation: &amp;#39;ExtAuthz&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         # authn_strategies: []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -183,7 +186,7 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;   disable: false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## The issuer name displayed in the Authenticator application of your choice.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-  # issuer: &amp;#39;authelia.com&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+  issuer: &amp;#39;apalrd.net&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## The TOTP algorithm to use.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## It is CRITICAL you read the documentation before changing this option:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -274,7 +277,7 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;     # jwt_algorithm: &amp;#39;HS256&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## The secret key used to sign and verify the JWT.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    jwt_secret: &amp;#39;a_very_important_secret&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    jwt_secret: &amp;#39;NearbyOverhangParadoxSulphuric&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## Elevated Session flows. Adjusts the flow which require elevated sessions for example managing credentials, adding,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## removing, etc.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -506,8 +509,8 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;   ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## Important: Kubernetes (or HA) users must read https://www.authelia.com/t/statelessness
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-  # file:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # path: &amp;#39;/config/users_database.yml&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+  file:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    path: &amp;#39;/etc/authelia/users_database.yml&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;     # watch: false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     # search:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       # email: false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -621,7 +624,9 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;   ## Default policy can either be &amp;#39;bypass&amp;#39;, &amp;#39;one_factor&amp;#39;, &amp;#39;two_factor&amp;#39; or &amp;#39;deny&amp;#39;. It is the policy applied to any
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## resource if there is no policy to be applied to the user.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   default_policy: &amp;#39;deny&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+  rules:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    - domain: &amp;#39;*.apalrd.net&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+      policy: &amp;#39;one_factor&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;   # networks:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     # - name: &amp;#39;internal&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     #   networks:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -718,14 +723,14 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## Cookies configures the list of allowed cookie domains for sessions to be created on.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## Undefined values will default to the values below.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-  # cookies:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-  #   -
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+  cookies:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    -
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;       ## The name of the session cookie.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-      # name: &amp;#39;authelia_session&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+      name: &amp;#39;authelia_session&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ## The domain to protect.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ## Note: the Authelia portal must also be in that domain.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-      # domain: &amp;#39;example.com&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+      domain: &amp;#39;apalrd.net&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ## Required. The fully qualified URI of the portal to redirect users to on proxies that support redirections.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ## Rules:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -733,7 +738,7 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;       ##   - The above &amp;#39;domain&amp;#39; option MUST either:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ##      - Match the host portion of this URI.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ##      - Match the suffix of the host portion when prefixed with &amp;#39;.&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-      # authelia_url: &amp;#39;https://auth.example.com&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+      authelia_url: &amp;#39;https://auth.apalrd.net&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ## Optional. The fully qualified URI used as the redirection location if the portal is accessed directly. Not
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ## configuring this option disables the automatic redirection behaviour.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -881,9 +886,9 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ## This mechanism prevents attackers from brute forcing the first factor. It bans the user if too many attempts are made
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ## in a short period of time.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-# regulation:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+regulation:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;   ## The number of failed login attempts before user is banned. Set it to 0 to disable regulation.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-  # max_retries: 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+  max_retries: 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## The time range during which the user can attempt login before being banned in the duration common syntax. The user
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## is banned if the authentication failed &amp;#39;max_retries&amp;#39; times in a &amp;#39;find_time&amp;#39; seconds window.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -896,11 +901,11 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; ## Storage Provider Configuration
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ## The available providers are: `local`, `mysql`, `postgres`. You must use one and only one of these providers.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-# storage:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+storage:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;   ## The encryption key that is used to encrypt sensitive information in the database. Must be a string with a minimum
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## length of 20. Please see the docs if you configure this with an undesirable key and need to change it, you MUST use
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## the CLI to change this in the database if you want to change it from a previously configured value.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-  # encryption_key: &amp;#39;you_must_generate_a_random_string_of_more_than_twenty_chars_and_configure_this&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+  encryption_key: &amp;#39;MoviePassingUntitledBacteriaStapleMatriarchAftermathChubby&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## Local (Storage Provider)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -910,9 +915,9 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;   ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## Important: Kubernetes (or HA) users must read https://www.authelia.com/t/statelessness
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-  # local:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+  local:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;     ## Path to the SQLite3 Database.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # path: &amp;#39;/config/db.sqlite3&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    path: &amp;#39;/etc/authelia/db.sqlite3&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ## MySQL / MariaDB (Storage Provider)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -1064,34 +1069,34 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;   ##        (only works for unauthenticated connections)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ##   - validate the SMTP server x509 certificate during the TLS handshake against the hosts trusted certificates
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ##     (configure in tls section)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-  # smtp:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+  smtp:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;     ## The address of the SMTP server to connect to in the address common syntax.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # address: &amp;#39;smtp://127.0.0.1:25&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    address: &amp;#39;smtp://YourMailProvider:587&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## The connection timeout in the duration common syntax.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     # timeout: &amp;#39;5 seconds&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## The username used for SMTP authentication.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # username: &amp;#39;test&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    username: &amp;#39;adventure@apalrd.net&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## The password used for SMTP authentication.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## Can also be set using a secret: https://www.authelia.com/c/secrets
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # password: &amp;#39;password&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    password: &amp;#39;SuperSecret&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## The sender is used to is used for the MAIL FROM command and the FROM header.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## If this is not defined and the username is an email, we use the username as this value. This can either be just
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## an email address or the RFC5322 &amp;#39;Name &amp;lt;email address&amp;gt;&amp;#39; format.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # sender: &amp;#39;Authelia &amp;lt;admin@example.com&amp;gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    sender: &amp;#39;Authelia &amp;lt;adventure@apalrd.net&amp;gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## HELO/EHLO Identifier. Some SMTP Servers may reject the default of localhost.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # identifier: &amp;#39;localhost&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    identifier: &amp;#39;auth.apalrd.net&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## Subject configuration of the emails sent. {title} is replaced by the text from the notifier.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     # subject: &amp;#39;[Authelia] {title}&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## This address is used during the startup check to verify the email configuration is correct.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## It&amp;#39;s not important what it is except if your email server only allows local delivery.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-    # startup_check_address: &amp;#39;test@authelia.com&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+    startup_check_address: &amp;#39;adventure@apalrd.net&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ## By default we require some form of TLS. This disables this check though is not advised.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     # disable_require_tls: false
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since it&amp;rsquo;s a diff and the file is absolutely massive, I suggest you first copy my diff into a file (say &lt;code&gt;diff.patch&lt;/code&gt;), edit the things which are relevant to you, and then apply it with &lt;code&gt;patch /etc/authelia/configuration.yml &amp;lt; diff.patch&lt;/code&gt;. You might need to &lt;code&gt;apt install patch&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;initial-user-file&#34;&gt;Initial User File&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve created an initial users file (&lt;code&gt;/etc/authelia/users_database.yml&lt;/code&gt;), by taking my username and hashing a password. Here&amp;rsquo;s the file, and how to hash your own password. Of course, if you have SMTP configured, you can let users change their own passwords later. Delete the original and recreate.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;users&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;apalrd&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;disabled&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;displayname&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;apalrd&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$argon2id$v=19$m=65536,t=3,p=4$6D0CA3wVZ7AwvLG6VM7L3w$PqbNjQPhCxD9VoWz2hb+XBKcTOCC1KRb46FRNjg6l6I&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#This corresponds to CorrectHorseBatteryStaple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;email&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;adventure@apalrd.net&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;groups&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;admins&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;karen&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;disabled&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;displayname&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;karen&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$argon2id$v=19$m=65536,t=3,p=4$Gb28FoQveOUloo8zpWWYgg$Kb3kJJU9mMznSIM2nDDVtuBvhiwF+SdQwoqoF3v80Rg&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#This corresponds to karen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And to generate your own password, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;authelia crypto hash generate argon2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#It will prompt you for a password&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;tls-certificate&#34;&gt;TLS Certificate&lt;/h3&gt;
&lt;p&gt;We need a TLS cert for Authelia. Authelia is more than capable of handling TLS on its own (without a reverse proxy in front of it), but it&amp;rsquo;s not capable of doing ACME protocol cert renewal, so I&amp;rsquo;m setting up Certbot to do it for us. We aren&amp;rsquo;t going to use port 80 for Authelia, so Certbot can have it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install certbot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install certbot -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Rewnew the first time manually, this will configure renewal in the future, and restart Authelia when it does renew&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;certbot certonly --standalone -d auth.apalrd.net --deploy-hook &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/usr/bin/systemctl restart authelia&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Answer the questions, it will be automatic in the future&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;testing&#34;&gt;Testing&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Enable the services now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now authelia
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Certbot is automatic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You should be able to navitate to your auth site, and it should let you login at this point.&lt;/p&gt;
&lt;h1 id=&#34;protected-service-example&#34;&gt;Protected Service Example&lt;/h1&gt;
&lt;p&gt;Here I&amp;rsquo;m going to setup a service to be protected by Authelia, using Caddy as my reverse proxy of choice.&lt;/p&gt;
&lt;h3 id=&#34;caddy&#34;&gt;Caddy&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m installing Caddy directly on the LXC container that runs the service (Frigate in this case). However, there&amp;rsquo;s nothing stopping you from adding this to the same Caddyfile / Caddy instance you used earlier (don&amp;rsquo;t duplicate the global section at the top, of course).&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the Caddyfile I am using with Frigate:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The Caddyfile is an easy way to configure your Caddy web server.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Global section for automatic TLS via Let&amp;#39;s Encrypt (requires an email)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;email &amp;#34;adventure@apalrd.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Frigate server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;corona.apalrd.net {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Authenticate via Authelia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;forward_auth https://auth.apalrd.net {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#ae81ff&#34;&gt;uri /api/authz/forward-auth&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#ae81ff&#34;&gt;copy_headers Remote-User Remote-Groups Remote-Email Remote-Name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;#Only include this if you are using a self-signed or staging cert at Authelia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;#transport http {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#75715e&#34;&gt;#tls_insecure_skip_verify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;#}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Reverse proxy to localhost (Frigate only binds to v4 sockets)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;reverse_proxy [127.0.0.1]:5000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want to restrict access to the &lt;code&gt;/config&lt;/code&gt; endpoint to users in the &lt;code&gt;admins&lt;/code&gt; group, you can use the following bit of yaml in your Authelia config to filter on that URL. Remember that rules are processed in order! If you add a default-allow rule on your domain like I did above, then it will all ow everyone anyway, so delete that one and make more specific rules now that you know what you are doing.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow admins with two factor auth to edit configs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;domain&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;corona.apalrd.net&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;policy&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;two_factor&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;subject&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;group:admins&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;resources&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^/config([/?].*)?$&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Catch anyone else trying to get to config and deny them&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;domain&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;corona.apalrd.net&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;policy&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;deny&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;resources&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^/config([/?].*)?$&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Catch any other resources on this domain and require one factor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;domain&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;corona.apalrd.net&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;policy&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;one_factor&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also found in this specific case that the javascript frontend rewrites the URL to /config instead of requesting that page, so it will initially load, but changing the configuration (the api endpoints) will still fail.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Relaying Traffic to Self-Host with CGNAT</title>
      <link>https://www.apalrd.net/posts/2024/network_relay/</link>
      <pubDate>Thu, 16 May 2024 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/network_relay/</guid>
      <description>This video started as the answer to a simple question - how can I self-host a service for my friends and family, behind cgnat, without requiring them to install any apps (like tunnels)? This video turned into a bunch of different ways to proxy IPv4 to IPv6, so you can receive IPv6 traffic natively and bring in legacy traffic from a VPS which does have public IPv4.
While I&amp;rsquo;m giving you a lot of different examples and methods here, you can mix and match a lot of them to fit your needs.</description>
      <content>&lt;p&gt;This video started as the answer to a simple question - how can I self-host a service for my friends and family, behind cgnat, without requiring them to install any apps (like tunnels)? This video turned into a bunch of different ways to proxy IPv4 to IPv6, so you can receive IPv6 traffic natively and bring in legacy traffic from a VPS which does have public IPv4.&lt;/p&gt;
&lt;p&gt;While I&amp;rsquo;m giving you a lot of different examples and methods here, you can mix and match a lot of them to fit your needs. For example, you can use snid for your TLS traffic (possibly listening on multiple ports for e.g. HTTPS and MQTTS), along with HAProxy or Tayga for the rest of your traffic. You can add in a Wireguard tunnel if you want, but since we are relaying to public IPv6s, it&amp;rsquo;s not needed.&lt;/p&gt;
&lt;p&gt;Anyway, come along on this adventure!&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#comparison-table&#34;&gt;Comparison Table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#option-1---snid&#34;&gt;Option 1 - SNID&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#option-2---haproxy&#34;&gt;Option 2 - HAProxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#option-3---v4-to-v6-port-forwarding-with-tayga&#34;&gt;Option 3 - Tayga&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#option-4---wireguard&#34;&gt;Option 4 - Wireguard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#bonus---asciimation-test-setup&#34;&gt;Bonus Asciimation Test Setup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/aAzdn9cqYRY&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2024/network_relay/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;comparison-table&#34;&gt;Comparison Table&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th style=&#34;text-align:center&#34;&gt;Pure IPv6&lt;/th&gt;
&lt;th style=&#34;text-align:center&#34;&gt;Cloudflare&lt;/br&gt;Tunnel&lt;/th&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#option-1---snid&#34;&gt;SNID&lt;/a&gt;&lt;/th&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#option-2---haproxy&#34;&gt;HAProxy&lt;/a&gt;&lt;/th&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#option-3---v4-to-v6-port-forwarding-with-tayga&#34;&gt;Tayga&lt;/a&gt;&lt;/th&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/network_relay/#option-4---wireguard&#34;&gt;Wireguard&lt;/a&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free / Open Source Software&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free (Hosting)&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;1&lt;/sup&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;2&lt;/sup&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;2&lt;/sup&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;2&lt;/sup&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;2&lt;/sup&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works with IPv6 Clients&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works with IPv4 Clients&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uses Standard Port Numbers&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;3,5&lt;/sup&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;3&lt;/sup&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;3&lt;/sup&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requires Server Name / DNS&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;sup&gt;4&lt;/sup&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;5&lt;/sup&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requires IPv6 Origin&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Direct Route (via v6)&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;5,6&lt;/sup&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;6&lt;/sup&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;?&lt;sup&gt;6&lt;/sup&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Direct Route (via v4)&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local Certificates&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supports HTTP/HTTPS&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supports HTTP/3 (QUIC)&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supports TLS (non-HTTPS)&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supports TCP (non-TLS)&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supports UDP&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Footnotes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cloudflare Tunnels are free but require sign-up with credit card. They also have an unknown bandwidth limit, as they are &amp;lsquo;designed for HTML / web sites and not streaming video&amp;rsquo;. Depending on your use case this may or may not be fine.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;m aware that Oracle has a free tier but I don&amp;rsquo;t trust them at all. Also, to do NAT46, you need at least a routed /96 to your VPS, and not all cloud providers offer this (DigitalOcean in particular has awful IPv6 support). Try &lt;a href=&#34;https://www.hetzner.com/cloud/&#34;&gt;Hetzner&lt;/a&gt; of &lt;a href=&#34;https://www.mythic-beasts.com/servers/virtual&#34;&gt;Mythic Beasts&lt;/a&gt; for good IPv6. &amp;lsquo;Good&amp;rsquo; in this case means a /64 subnet &lt;em&gt;routed&lt;/em&gt; (not on-link) to your server. You can tell if it&amp;rsquo;s routed if their gateway IP is within your /64 or not, routed will have a &amp;lsquo;far&amp;rsquo; gateway (or link-local).&lt;/li&gt;
&lt;li&gt;With these methods, since they don&amp;rsquo;t know the Server Name Identifier (SNI), you can only use the &amp;lsquo;standard&amp;rsquo; port for one backend. This is a limitation of the DNS name not being transmitted over non-TLS protocols. You are of course free to use nonstandard ports for additional copies of the same service (i.e. multiple SSH servers).&lt;/li&gt;
&lt;li&gt;You must host your domain with Cloudflare to use Cloudflare Tunnels for free&lt;/li&gt;
&lt;li&gt;HAProxy supports both TLS SNI forwarding of TCP as well as pure TCP proxying&lt;/li&gt;
&lt;li&gt;Direct Routing via v6 is only possible if you use the same port number on the v4 gateway and v6 origin. If you are using multiple services on the same port on different IPv6 addresses, you will run into port limitations on the v4 address. TLS connections do not suffer from this, as the server name is specified in the connections. If your software supports SRV records, you can use multiple SRV records to point to the v6 origin + port and the v4 gateway + port.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, you can mix and match these on the same VPS! For example, use snid on port 443 for TLS, plus HAProxy or Tayga on other ports! And, while I&amp;rsquo;m showing how to set these up in a VPS to route around CGNAT, you can also set most of these up at your non-CGNAT router as an IPv4 to IPv6 transition mechanism.&lt;/p&gt;
&lt;h1 id=&#34;option-1---snid&#34;&gt;Option 1 - SNID&lt;/h1&gt;
&lt;p&gt;This comes to us from &lt;a href=&#34;https://www.agwa.name/blog/post/using_sni_proxying_and_ipv6_to_share_port_443&#34;&gt;AGWA&amp;rsquo;s Blog Post&lt;/a&gt;, and you can find the binaries on &lt;a href=&#34;https://github.com/AGWA/snid&#34;&gt;His Github&lt;/a&gt;. He explains the concept in great detail there.&lt;/p&gt;
&lt;p&gt;Anyway, here&amp;rsquo;s the systemd service I wrote to go with it. I installed the static binary (Golang is awesome!) into &lt;code&gt;/usr/local/bin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Download the binary, then &lt;code&gt;chmod +x&lt;/code&gt; it so it&amp;rsquo;s executable. Nothing else to install!&lt;/p&gt;
&lt;p&gt;Not to replicate his docs here, but here&amp;rsquo;s what I used for each option:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;listen tcp:0.0.0.0:443&lt;/code&gt; - Listen only on IPv4, since IPv6 will go direct. If you want to listen on multiple ports, add this multiple times (i.e. 443 for HTTPS and 3389 for RDP). Backend connections use the same destination port of the listener they came in on.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mode nat46&lt;/code&gt; - Encode the whole damn IPv4 space into our IPv6 prefix. The VPS has a /64, so this is fine.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nat46-prefix 2001:db8::4646:0:0&lt;/code&gt; - I&amp;rsquo;m already using suffix ::1 for my SSH management, so use 4646:: for NAT46&lt;/li&gt;
&lt;li&gt;&lt;code&gt;backend-cidr 2001:db8::/48&lt;/code&gt; - Put in your home IPv6 prefix here. Prevents you from becoming an open proxy on the internet, only allows connections that are within this range.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So create &lt;code&gt;/etc/systemd/system/snid.service&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;SNI TLS Proxy Daemon
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;network-online.target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr/local/bin/snid -listen tcp:0.0.0.0:443 -mode nat46 -nat46-prefix 2601:db8:6969:420:4646:: -backend-cidr 2001:db8::/48
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Restart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;always
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We also need to add a route for our whole /96 prefix to lo, so the kernel will accept packets for it. I added this line to my &lt;code&gt;/etc/network/interfaces&lt;/code&gt; on Debian:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# control-alias eth0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iface eth0 inet6 static
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Was /64, changed to /128 so we don&amp;#39;t send packets on-link for other addresses&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    address 2601:db8:6969:420::1/128
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    dns-nameservers 2601:fe::fe 2601:fe::9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gateway fe80::1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Add local route to the translation prefix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    post-up ip route add local 2601:db8:6969:420:4646::/96 dev lo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    post-down ip route del local 2601:db8:6969:420:4646::/96 dev lo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, when we are done, we need to apply both of these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;systemctl daemon-reload&lt;/code&gt; every time you change the &lt;code&gt;snid.service&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemctl enable --now snid&lt;/code&gt; to enable and start it&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemctl restart snid&lt;/code&gt; if you change the service file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemctl status snid&lt;/code&gt; to see how it&amp;rsquo;s going&lt;/li&gt;
&lt;li&gt;&lt;code&gt;journalctl -xeu snid&lt;/code&gt; to see how it&amp;rsquo;s going in more detail&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ifdown eth0 &amp;amp;&amp;amp; ifup eth0&lt;/code&gt; to reload /etc/network/interfaces (or just reboot)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;option-2---haproxy&#34;&gt;Option 2 - HAProxy&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ve already made a video on this topic - &lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/&#34;&gt;you can find it here.&lt;/a&gt; That page goes through a lot of the theory if you are curious.&lt;/p&gt;
&lt;p&gt;tl;dr install it with &lt;code&gt;apt update &amp;amp;&amp;amp; apt install haproxy -y&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Then edit the config file &lt;code&gt;/etc/haproxy/haproxy.cfg&lt;/code&gt;. Here are some example configs for you. I left the Debian defaults unmodified and added my sections at the end.&lt;/p&gt;
&lt;h3 id=&#34;http-redirect-to-https-direct-response-to-client&#34;&gt;HTTP Redirect to HTTPS (Direct response to client)&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Listen on port 80, layer 7 (HTTP)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Redirect everything to https&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# That leaves the client to reconnect properly,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# and means we don&amp;#39;t need to proxy HTTP, just HTTPS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;frontend www&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;bind :80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;http-request redirect scheme https&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;http-proxy-to-origin-layer-7&#34;&gt;HTTP Proxy to Origin (Layer 7)&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Layer 7 HTTP proxying (insecure), to backend servers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;frontend www&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;bind :80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# We are building the name of the backend from the &amp;#39;host&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# field in the request plus the literal &amp;#39;_http&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# See backends for an example of how to name them&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;use_backend %[req.hdr(host),lower,word(1,:)]_http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Backends for HTTP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;backend test1.apalrd.net_http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;server test1_http 2601:40e:69:69:0:0:0:feed:80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;backend test2.apalrd.net_http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;server test2_http 2601:40e:69:69:0:0:0:beef:80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;https-proxy-to-origin-layer-4-tls-forwarding&#34;&gt;HTTPS Proxy to Origin (Layer 4 TLS Forwarding)&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Layer 4 TCP SNI proxy example&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;frontend www-tls&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Layer 4 (TCP) mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Use TCPlog mode instead of HTTPlog&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;option tcplog&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Listen on TCP 443 (HTTP/1.1 and HTTP/2)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;bind :443&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Wait for SSL Hello before forwarding&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;tcp-request inspect-delay 5s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;tcp-request content accept if { req_ssl_hello_type 1 }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Select backends for each server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Similar method to above, but using &amp;#39;_tls&amp;#39; on the end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;use_backend %[req_ssl_sni,lower,word(1,:)]_tls&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Backends for TLS servers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;backend test1.apalrd.net_tls&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;server test1_tls 2601:40e:69:69:0:0:0:feed:443&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;backend test2.apalrd.net_tls&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;server test2_tls 2601:40e:69:69:0:0:0:beef:443&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;tcp-proxy-to-origin-layer-4-port-forward&#34;&gt;TCP Proxy to Origin (Layer 4 Port Forward)&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Frontend for SSH on port 2222&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;frontend ssh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;option tcplog&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;bind :2222&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;default_backend ssh_server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#This is 1 incoming port -&amp;gt; 1 outgoing port (no SNI with TCP)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;backend ssh_server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;server test1_ssh 2601:40e:69:69:0:0:0:feed:22&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;tcp-load-balance-to-origin-layer-4-balancing&#34;&gt;TCP Load Balance to Origin (Layer 4 Balancing)&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Frontend for RDP on port 3389. Works with any TCP protocol which can be load balanced.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Other examples include databases, etc.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;frontend rdp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;bind :3389&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;default_backend rdp_servers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Choose one of the RDP servers based on least connections&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;backend rdp_servers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;mode tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Roundrobin is also a good option&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;balance leastconn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;server test1_rdp 2601:40e:69:69:0:0:0:feed:3389&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;server test2_rdp 2601:40e:69:69:0:0:0:feed:3389&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;option-3---v4-to-v6-port-forwarding-with-tayga&#34;&gt;Option 3 - v4 to v6 Port Forwarding with Tayga&lt;/h1&gt;
&lt;p&gt;Tayga is a tool which can directly translate IPv4 and IPv6 packets at layer 3, so it works for any higher layer protocol (TCP, UDP, and more). Using Tayga, we will create IPv4 -&amp;gt; IPv6 address mappings, and then we can &amp;lsquo;port forward&amp;rsquo; from our one public IPv4 to multiple internal IPv6 addresses.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve setup Tayga previously to do NAT64 (where clients access the IPv4 internet over IPv6), and this is a different method of configuration. Anyway, here&amp;rsquo;s the install steps:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install Tayga&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install tayga -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Remove the old-ass init.d script&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm /etc/init.d/tayga
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Remove the old configuration file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm /etc/tayga.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a new configuration file (&lt;code&gt;/etc/tayga.conf&lt;/code&gt;)! It&amp;rsquo;s pretty simple here. I&amp;rsquo;m using 192.168.233.0/24 to hold the translation addresses, so you can translate to 252 hosts (-1 network, -1 broadcast, -1 for linux and -1 for tayga). You can use a larger subnet if you want to translate more hosts. This subnet is only used within the VPS.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The name of the tun device (leave as-is)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tun-device nat64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Tayga&amp;#39;s IPv4 address on the translation network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ipv4-addr 192.168.233.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# IPv4 translation prefix - used as src addr in IPv6 after translation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Pull a random /96 out of your VPS prefix for this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Our /64 literally gives us enough to have 4 billion IPv4 internets&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Just don&amp;#39;t overlap with snid if you are using that too&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prefix 2a01:4f9:c010:919d:64::/96
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# If you need to ping Tayga, take the ipv4-addr above and merge it with your prefix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# In this case, that would be:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 2a01:4f9:c010:919d:64::c0a8:e902&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Map a single IPv4 on our translation v4 subnet to a public IPv6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Remember we can&amp;#39;t use the first (network) and last (broadcast) in the subnet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# And we also used the first and second real addresses for Linux and Tayga. So start at 3. &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 192.168.233.3 2001:db8:6969:420::1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 192.168.233.4 2001:db8:6969:421::6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a modern systemd service unit (&lt;code&gt;/etc/systemd/system/tayga.service&lt;/code&gt;) for this guy. Note that I&amp;rsquo;m setting up a bunch of port forwards here! We are doing &amp;rsquo;normal&amp;rsquo; iptables port forwarding from the public v4 address to the translation addresses, then letting Tayga translate them v4-&amp;gt;v6.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Tayga NAT64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;network-online.target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Start Tayga in debug mode (let systemd daemonize it)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr/sbin/tayga --config /etc/tayga.conf -d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Restart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;always
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Do port forwarding after start / before stop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make sure you have a Add and Del rule for each&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStartPost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;iptables -t nat -A PREROUTING -i eth0 -p tcp --dport &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;  -j DNAT --to-destination 192.168.233.3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStopPre&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;iptables -t nat -D PREROUTING -i eth0 -p tcp --dport &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;  -j DNAT --to-destination 192.168.233.3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#You can of course copy/paste that as many times as you want&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Configure tunnel interface after start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStartPost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ip link set nat64 up
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStartPost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ip addr add 192.168.233.1/24 dev nat64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Update with the IP prefix you gave Tayga, take the first address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStartPost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ip addr add 2a01:4f9:c010:919d:64::1/96 dev nat64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#No need to undo as the nat64 interface and its config is destroyed when tayga exits&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Enable IP forwarding (no need to modify)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStartPre&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/bin/bash -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;echo 1 &amp;gt; /proc/sys/net/ipv4/conf/all/forwarding&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStartPre&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/bin/bash -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;echo 1 &amp;gt; /proc/sys/net/ipv6/conf/all/forwarding&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, when we are done, we need to apply the changes and start tayga&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;systemctl daemon-reload&lt;/code&gt; every time you change the &lt;code&gt;tayga.service&lt;/code&gt; file (not after tayga.conf though)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemctl enable --now tayga&lt;/code&gt; to enable and start it&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemctl restart tayga&lt;/code&gt; if you change the service file or tayga.conf&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemctl status tayga&lt;/code&gt; to see how it&amp;rsquo;s going&lt;/li&gt;
&lt;li&gt;&lt;code&gt;journalctl -xeu tayga&lt;/code&gt; to see how it&amp;rsquo;s going in more detail&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;option-4---wireguard&#34;&gt;Option 4 - Wireguard&lt;/h1&gt;
&lt;p&gt;Here I&amp;rsquo;m going to create a simple tunnel between my opnsense system at home and my VPS. Then I can port forward across the tunnel.&lt;/p&gt;
&lt;p&gt;First we need to install wireguard tools (&lt;code&gt;apt update &amp;amp;&amp;amp; apt install wireguard-tools -y&lt;/code&gt;). Next, create a config on your OPNsense system, and then we will generate a client on OPNsense and copy it into the VPS.&lt;/p&gt;
&lt;p&gt;Finally, we will add all of our iptables rules into the &lt;code&gt;wg0.conf&lt;/code&gt; so they run automatically when the tunnel goes up and down:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Need to enable IP forwarding&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;PostUp = /bin/bash -c &amp;#34;echo 1 &amp;gt; /proc/sys/net/ipv4/conf/all/forwarding&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;PostUp = /bin/bash -c &amp;#34;echo 1 &amp;gt; /proc/sys/net/ipv6/conf/all/forwarding&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Do port forwarding after start / before stop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Make sure you have a Add and Del rule for each&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;PostUp=iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 23  -j DNAT --to-destination 172.27.14.233&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;PostDown=iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 23  -j DNAT --to-destination 172.27.14.233&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Do Masquerade so packets return the right way&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;PostUp=iptables -t nat -A POSTROUTING -o wg0 -p tcp --dport 23 -d 172.27.14.233 -j SNAT --to-source 9.10.11.12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;PostDown=iptables -t nat -D POSTROUTING -o wg0 -p tcp --dport 23 -d 172.27.14.233 -j SNAT --to-source 9.10.11.12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# You can of course copy/paste that as many times as you want&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;bonus---asciimation-test-setup&#34;&gt;Bonus - ASCIIMation Test Setup&lt;/h1&gt;
&lt;p&gt;In my TCP example I setup an ASCIImation server. I initially copied a project from Github, found it didn&amp;rsquo;t have IPv6 support, patched it myself, then went to make a fork / PR and realized that someone had already made a v6 fork, so just use their fork.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/berghauz/ascii-telnet-server.git&#34;&gt;Here it is&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install Git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install git -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Clone repo somewhere&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /var/lib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/berghauz/ascii-telnet-server.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Create a system user+group for us to have less permissions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adduser --quiet --system --group vader
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also wrote a systemd unit (&lt;code&gt;/etc/systemd/system/asciimation.service&lt;/code&gt;) for it, and a user account for it. I have it bound to port 23, which requires elevated privilages to bind to low numbered ports, and systemd does this for us.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ASCIImation server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;network-online.target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vader
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Group&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vader
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Defaults to bind on :: on port 23, so no need to specify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr/bin/python3 /var/lib/ascii-telnet-server/ascii_telnet_server.py  -f /var/lib/ascii-telnet-server/sample_movies/sw1.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AmbientCapabilities&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;CAP_NET_BIND_SERVICE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Restart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;always
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Kwumsy H3 Stream Dock USB Protocol</title>
      <link>https://www.apalrd.net/posts/2024/studio_dock/</link>
      <pubDate>Fri, 12 Apr 2024 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/studio_dock/</guid>
      <description>So today I&amp;rsquo;m taking a look at the Kwumsy H3 &amp;lsquo;Stream Dock&amp;rsquo; No, not THAT Stream Deck, not a dock for the Steam Deck, there&amp;rsquo;s already enough name confusion. Basically, it tries to be a lower cost touchscreen alternative to the real Stream Deck, making use of the same addon format for wide addon support, and also somehow a USB-C laptop dock with Ethernet, USB 3, HDMI, and USB-PD passthrough.</description>
      <content>&lt;p&gt;So today I&amp;rsquo;m taking a look at the Kwumsy H3 &amp;lsquo;Stream Dock&amp;rsquo; No, not THAT Stream Deck, not a dock for the Steam Deck, there&amp;rsquo;s already enough name confusion. Basically, it tries to be a lower cost touchscreen alternative to the real Stream Deck, making use of the same addon format for wide addon support, and also somehow a USB-C laptop dock with Ethernet, USB 3, HDMI, and USB-PD passthrough.&lt;/p&gt;
&lt;p&gt;While all of the hardware works as expected, the software experience isn&amp;rsquo;t great. There are plenty of cases where it seems like the daemon doesn&amp;rsquo;t automatically detect the H3 on boot, or the icons don&amp;rsquo;t update. That said, I did a deep-dive into the USB protocol and it&amp;rsquo;s pretty trivial and nearly identical to the &amp;lsquo;real&amp;rsquo; Stream Deck protocol. I&amp;rsquo;m sure you can write your own software if you really want to or have a special use case for this thing.&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/8hgGcEk4tgs&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2024/studio_dock/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;pcap-files&#34;&gt;PCAP Files&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/studio_dock/init.pcapng&#34;&gt;Initializing the screen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/studio_dock/modeswitch.pcapng&#34;&gt;Mode Switching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/studio_dock/btnpress.pcapng&#34;&gt;Button Pressing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2024/studio_dock/btnpress2.pcapng&#34;&gt;Button Pressing 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Proxmox Backup Auto-Shutdown</title>
      <link>https://www.apalrd.net/posts/2024/pbs_hibernate/</link>
      <pubDate>Sat, 06 Apr 2024 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/pbs_hibernate/</guid>
      <description>Today I&amp;rsquo;m trying to reduce the power consumption of my Proxmox Backup Server. The HP Microserver is great for what I need, but it&amp;rsquo;s kinda loud and I&amp;rsquo;m working on optimizing my power bill. The homelab is the largest single consumer of electricity aside from the air conditioning in the summer, so it&amp;rsquo;s something I&amp;rsquo;m looking at heavily.
Anyway, I thought I could do this purely with systemd sleep / suspend initially.</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m trying to reduce the power consumption of my &lt;a href=&#34;https://www.apalrd.net/posts/2023/pbs_intro/&#34;&gt;Proxmox Backup Server&lt;/a&gt;. The HP Microserver is great for what I need, but it&amp;rsquo;s kinda loud and I&amp;rsquo;m working on optimizing my power bill. The homelab is the largest single consumer of electricity aside from the air conditioning in the summer, so it&amp;rsquo;s something I&amp;rsquo;m looking at heavily.&lt;/p&gt;
&lt;p&gt;Anyway, I thought I could do this purely with systemd sleep / suspend initially. Systemd can set up the system RTC to wake the system from suspend or hibernate at a specific time, and it&amp;rsquo;s easy to configure this by setting up a timer unit which is allowed to wake the system to happen. Of course, this requires the system to be able to suspend or hibernate.&lt;/p&gt;
&lt;p&gt;I tried doing S3 speep (normal suspend to RAM) and found that the Microserver doesn&amp;rsquo;t support this. I then didn&amp;rsquo;t have enough space on my 16G boot disk (microSD card) for a swap partition to hibernate to, and don&amp;rsquo;t want to mess with the partition tables on my zfs drives to add one there, so hibernate is out too. This leaves me with actually fully shutting the system down and booting back up in the future. Downside to this is the RTC won&amp;rsquo;t wake it back up, I need to have another system send a Wake on LAN magic packet. No big deal, I just need to make sure I send it early enough that the backups aren&amp;rsquo;t scheduled to start until after the server is fully booted.&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;Here&amp;rsquo;s the video if you want to listen to me say all of these things:
&lt;a href=&#34;https://youtu.be/o5KAt76Bg3w&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2024/pbs_hibernate/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;wake-on-lan&#34;&gt;Wake On LAN&lt;/h1&gt;
&lt;p&gt;I found the MACs of all of my interfaces. In this case, I&amp;rsquo;m using eno1, so I am using &lt;code&gt;70:10:6f:3e:d1:f8&lt;/code&gt;. You will of course need to find your own MAC address. This is also the hardware MAC, not the virtual MAC if you&amp;rsquo;re using a bond. I then installed the simple &lt;code&gt;wakeonlan&lt;/code&gt; utility with &lt;code&gt;apt install wakeonlan&lt;/code&gt;. It&amp;rsquo;s installed in &lt;code&gt;/usr/bin&lt;/code&gt; so I can call it directly from the systemd service unit.&lt;/p&gt;
&lt;h3 id=&#34;service-unit-to-wake-on-lan&#34;&gt;Service Unit to Wake On LAN&lt;/h3&gt;
&lt;p&gt;This just calls wakeonlan with the MAC address. Don&amp;rsquo;t enable the service, but you can &lt;code&gt;systemctl start wakebigstor&lt;/code&gt; to bootup the server if you want. I put the file in &lt;code&gt;/etc/systemd/system/wakebigstor.service&lt;/code&gt;. Bigstor is the name of the backup server.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Wake up Bigstor
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;oneshot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr/bin/wakeonlan 70:10:6f:3e:d1:f8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;default.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;timer-unit-to-call-service-unit&#34;&gt;Timer Unit to call Service Unit&lt;/h3&gt;
&lt;p&gt;Systemd timers are separate units from services, so here&amp;rsquo;s the timer unit that triggers the service unit at 19:05 local time daily. I put this one in &lt;code&gt;/etc/systemd/system/wakebigstor.timer&lt;/code&gt; and enabled and started it (&lt;code&gt;systemctl enable --now wakebigstor.timer&lt;/code&gt;). Again, don&amp;rsquo;t enable the service, just the timer.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Wakeup Bigstor
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RefuseManualStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RefuseManualStop&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Timer&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run at 19:05 (7pm local time)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OnCalendar&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;*-*-* 19:05:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;wakebigstor.service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;timers.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;autoshutdown&#34;&gt;Autoshutdown&lt;/h1&gt;
&lt;p&gt;This is 3 parts - a systemd timer that runs 5 hours after we start the server, to attempt shutdown (this gives clients 5 hours to start their backups), a systemd service unit that calls a bash script, and a bash script that waits until there are no more tasks running in proxmox-backup-manager.&lt;/p&gt;
&lt;h3 id=&#34;bash-script&#34;&gt;Bash Script&lt;/h3&gt;
&lt;p&gt;This script calls proxmox-backup-manager repeatedly. Hopefully you can understand my bash scripting. I put this file in &lt;code&gt;/usr/local/bin/autoshutdown&lt;/code&gt;. Don&amp;rsquo;t forget to &lt;code&gt;chmod +x&lt;/code&gt; it since it&amp;rsquo;s executable.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Count of times we have queried and there are tasks running&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;count&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Number of no-task intervals before we shutdown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;max&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Interval in seconds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;interval&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Continue until we shutdown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; true; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Check if we should shutdown until we see not &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;proxmox-backup-manager task list&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Continue to wait&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        count&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#There are no tasks running, so increment counter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        count&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt;count &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;No tasks running, time until shutdown is &lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;max &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; count&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; interval&lt;span style=&#34;color:#66d9ef&#34;&gt;))&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; seconds&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#If we reached the max count, then shutdown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;((&lt;/span&gt;count &amp;gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; max&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Time to shutdown!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            shutdown now
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Delay by interval to next check&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sleep &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$interval&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Exiting&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;service-unit&#34;&gt;Service Unit&lt;/h3&gt;
&lt;p&gt;And the service unit that calls autoshutdown goes in &lt;code&gt;/etc/systemd/system/autoshutdown.service&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Shutdown when there are no tasks left
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr/local/bin/autoshutdown
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;default.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;timer-unit&#34;&gt;Timer Unit&lt;/h3&gt;
&lt;p&gt;And it also has a timer, &lt;code&gt;/etc/systemd/system/autoshutdown.timer&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Shutdown
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RefuseManualStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RefuseManualStop&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Timer&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run at 22:00 local time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OnCalendar&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;*-*-* 22:00:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;autoshutdown.service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;timers.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When you are done, don&amp;rsquo;t forget to run &lt;code&gt;systemctl daemon-reload&lt;/code&gt; and &lt;code&gt;systemctl enable --now autoshutdown.timer&lt;/code&gt; (but &lt;em&gt;not&lt;/em&gt; the service unit, just the timer).&lt;/p&gt;
&lt;h1 id=&#34;mount-root-fs-noatime&#34;&gt;Mount Root FS noatime&lt;/h1&gt;
&lt;p&gt;To reduce writes to the SD card, I mounted the root fs with &lt;code&gt;noatime&lt;/code&gt;. The line in my &lt;code&gt;/etc/fstab&lt;/code&gt; now looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# &amp;lt;file system&amp;gt; &amp;lt;mount point&amp;gt;   &amp;lt;type&amp;gt;  &amp;lt;options&amp;gt;       &amp;lt;dump&amp;gt;  &amp;lt;pass&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# / was on /dev/sdh1 during installation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;UUID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;b58dfd0c-b6dc-4e44-a9b8-22ba3a5540d8 /               ext4    errors&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;remount-ro,noatime &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;move-logs-to-datastore-disks&#34;&gt;Move Logs to Datastore Disks&lt;/h1&gt;
&lt;p&gt;Logs are stored in &lt;code&gt;/var/log/proxmox-backup&lt;/code&gt; and a subdirectory for &lt;code&gt;tasks&lt;/code&gt; can grow qutite significantly, with my larger file backups taking hundreds of MB for a log. This is not great for my root SD card, so I want to move them to zfs. I&amp;rsquo;m going to keep the &lt;code&gt;api&lt;/code&gt; logs on root.&lt;/p&gt;
&lt;p&gt;The zfs fs is already mounted at &lt;code&gt;/mnt/datastore/backup&lt;/code&gt; (the datastore is named &lt;code&gt;backup&lt;/code&gt;), so I created a zfs dataset &lt;code&gt;backup/logs&lt;/code&gt;. I then rsync copied the logs into it &lt;code&gt;rsync -r -v /var/log/proxmox-backup/tasks /mnt/datastore/backup/logs/&lt;/code&gt;, deleted the original &lt;code&gt;rm -rf /var/log/proxmox-backup/tasks&lt;/code&gt; and symlinked it back back &lt;code&gt;ln -s /mnt/datastore/backup/logs/tasks /var/log/proxmox-backup/tasks&lt;/code&gt;. I then needed to fix permissions to user/group &lt;code&gt;backup:backup&lt;/code&gt; with &lt;code&gt;chown backup:backup -R /mnt/datastore/backup/logs&lt;/code&gt; and &lt;code&gt;chown backup:backup /var/log/proxmox-backup/tasks&lt;/code&gt;. After this, task logs were working correctly and backups were happy again.&lt;/p&gt;
&lt;h1 id=&#34;increase-zfs-arc-limit&#34;&gt;Increase ZFS ARC Limit&lt;/h1&gt;
&lt;p&gt;Since the system exists primarily to store the data in ZFS and has no large workload otherwise, I increased the ARC max from 50% of system RAM (Default) to 75%, in my case 12GB. I did this by first calculating the number of bytes in 12GB (12884901888) and storing this in a new file &lt;code&gt;/etc/modprobe.d/zfs.conf&lt;/code&gt; with the following contents:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;options zfs zfs_arc_max&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;12884901888&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This applies on the next boot.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>UGreen NASync DXP4800 Plus Teardown</title>
      <link>https://www.apalrd.net/posts/2024/storage_ugreen/</link>
      <pubDate>Thu, 28 Mar 2024 00:32:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/storage_ugreen/</guid>
      <description>I did a full teardown of this unit, see the video below. This page also has the &amp;rsquo;extra info&amp;rsquo; (pci, cpu, ..) for you.
Video Click on the thumbnail to view the video on Youtube Hardware Info All of this was taken via an Debian 12 system (Bookworm / kernel 6.1), so your kernel may be configured slightly differently
lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 39 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 6 On-line CPU(s) list: 0-5 Vendor ID: GenuineIntel BIOS Vendor ID: Intel(R) Corporation Model name: Intel(R) Pentium(R) Gold 8505 BIOS Model name: Intel(R) Pentium(R) Gold 8505 To Be Filled By O.</description>
      <content>&lt;p&gt;I did a full teardown of this unit, see the video below. This page also has the &amp;rsquo;extra info&amp;rsquo; (pci, cpu, ..) for you.&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;Click on the thumbnail to view the video on Youtube
&lt;a href=&#34;https://youtu.be/R8t-Wqx_E3U&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2024/storage_ugreen/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;hardware-info&#34;&gt;Hardware Info&lt;/h1&gt;
&lt;p&gt;All of this was taken via an Debian 12 system (Bookworm / kernel 6.1), so your kernel may be configured slightly differently&lt;/p&gt;
&lt;h2 id=&#34;lscpu&#34;&gt;lscpu&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Architecture:                       x86_64
CPU op-mode(s):                     32-bit, 64-bit
Address sizes:                      39 bits physical, 48 bits virtual
Byte Order:                         Little Endian
CPU(s):                             6
On-line CPU(s) list:                0-5
Vendor ID:                          GenuineIntel
BIOS Vendor ID:                     Intel(R) Corporation
Model name:                         Intel(R) Pentium(R) Gold 8505
BIOS Model name:                    Intel(R) Pentium(R) Gold 8505 To Be Filled By O.E.M. CPU @ 4.3GHz
BIOS CPU family:                    11
CPU family:                         6
Model:                              154
Thread(s) per core:                 2
Core(s) per socket:                 5
Socket(s):                          1
Stepping:                           4
CPU(s) scaling MHz:                 13%
CPU max MHz:                        4400.0000
CPU min MHz:                        400.0000
BogoMIPS:                           4992.00
Flags:                              fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat
                                    pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx 
                                    pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good 
                                    nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni 
                                    pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr 
                                    pdcm sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave 
                                    avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb ssbd ibrs 
                                    ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad 
                                    fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap 
                                    clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves 
                                    split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify 
                                    hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni 
                                    vaes vpclmulqdq rdpid movdiri movdir64b fsrm md_clear serialize 
                                    arch_lbr ibt flush_l1d arch_capabilities
Virtualization:                     VT-x
L1d cache:                          176 KiB (5 instances)
L1i cache:                          288 KiB (5 instances)
L2 cache:                           3.3 MiB (2 instances)
L3 cache:                           8 MiB (1 instance)
NUMA node(s):                       1
NUMA node0 CPU(s):                  0-5
Vulnerability Gather data sampling: Not affected
Vulnerability Itlb multihit:        Not affected
Vulnerability L1tf:                 Not affected
Vulnerability Mds:                  Not affected
Vulnerability Meltdown:             Not affected
Vulnerability Mmio stale data:      Not affected
Vulnerability Retbleed:             Not affected
Vulnerability Spec rstack overflow: Not affected
Vulnerability Spec store bypass:    Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:           Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2:           Mitigation; Enhanced IBRS, IBPB conditional, RSB filling, PBRSB-eIBRS SW sequence
Vulnerability Srbds:                Not affected
Vulnerability Tsx async abort:      Not affected
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;CPU is very modern with virtualization support. 1 P-core (2 threads) + 4 E-cores (4 threads) gives us the weird number of 5 cores and 6 threads. Linux is of course very good at scheduling across P/E cores.&lt;/p&gt;
&lt;h2 id=&#34;lspci&#34;&gt;lspci&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;00:00.0 Host bridge: Intel Corporation Device 4619 (rev 04)
	IOMMU group: 1
00:02.0 VGA compatible controller: Intel Corporation Alder Lake-UP3 GT1 [UHD Graphics] (rev 0c) (prog-if 00 [VGA controller])
	IOMMU group: 0
00:06.0 PCI bridge: Intel Corporation 12th Gen Core Processor PCI Express x4 Controller #0 (rev 04) (prog-if 00 [Normal decode])
	IOMMU group: 2
00:06.2 PCI bridge: Intel Corporation 12th Gen Core Processor PCI Express x4 Controller #2 (rev 04) (prog-if 00 [Normal decode])
	IOMMU group: 3
00:0d.0 USB controller: Intel Corporation Alder Lake-P Thunderbolt 4 USB Controller (rev 04) (prog-if 30 [XHCI])
	IOMMU group: 4
00:14.0 USB controller: Intel Corporation Alder Lake PCH USB 3.2 xHCI Host Controller (rev 01) (prog-if 30 [XHCI])
	IOMMU group: 5
00:14.2 RAM memory: Intel Corporation Alder Lake PCH Shared SRAM (rev 01)
	IOMMU group: 5
00:15.0 Serial bus controller: Intel Corporation Alder Lake PCH Serial IO I2C Controller #0 (rev 01)
	IOMMU group: 6
00:16.0 Communication controller: Intel Corporation Alder Lake PCH HECI Controller (rev 01)
	IOMMU group: 7
00:1c.0 PCI bridge: Intel Corporation Device 51b8 (rev 01) (prog-if 00 [Normal decode])
	IOMMU group: 8
00:1c.4 PCI bridge: Intel Corporation Device 51bc (rev 01) (prog-if 00 [Normal decode])
	IOMMU group: 9
00:1d.0 PCI bridge: Intel Corporation Alder Lake PCI Express Root Port (rev 01) (prog-if 00 [Normal decode])
	IOMMU group: 10
00:1d.2 PCI bridge: Intel Corporation Device 51b2 (rev 01) (prog-if 00 [Normal decode])
	IOMMU group: 11
00:1f.0 ISA bridge: Intel Corporation Alder Lake PCH eSPI Controller (rev 01)
	IOMMU group: 12
00:1f.3 Audio device: Intel Corporation Alder Lake PCH-P High Definition Audio Controller (rev 01)
	IOMMU group: 12
00:1f.4 SMBus: Intel Corporation Alder Lake PCH-P SMBus Host Controller (rev 01)
	IOMMU group: 12
00:1f.5 Serial bus controller: Intel Corporation Alder Lake-P PCH SPI Controller (rev 01)
	IOMMU group: 12
02:00.0 Non-Volatile memory controller: Phison Electronics Corporation PS5013 E13 NVMe Controller (rev 01) (prog-if 02 [NVM Express])
	Subsystem: Phison Electronics Corporation PS5013-E13 PCIe3 NVMe Controller (DRAM-less)
	IOMMU group: 13
	Region 0: Memory at 80e00000 (64-bit, non-prefetchable) [size=16K]
	Capabilities: [80] Express (v2) Endpoint, MSI 00
		LnkCap:	Port #1, Speed 8GT/s, Width x4, ASPM L1, Exit Latency L1 unlimited
			ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp+
		LnkCtl:	ASPM Disabled; RCB 64 bytes, Disabled- CommClk+
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 8GT/s, Width x4
			TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
	Kernel driver in use: nvme
	Kernel modules: nvme

03:00.0 Ethernet controller: Aquantia Corp. Device 04c0 (rev 03)
	Subsystem: Aquantia Corp. Device 0001
	IOMMU group: 14
	Capabilities: [70] Express (v2) Endpoint, MSI 00
		LnkCap:	Port #0, Speed 16GT/s, Width x4, ASPM not supported
			ClockPM+ Surprise- LLActRep- BwNot- ASPMOptComp+
		LnkCtl:	ASPM Disabled; RCB 64 bytes, Disabled- CommClk+
			ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 8GT/s (downgraded), Width x2 (downgraded)
			TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
	Kernel driver in use: atlantic
	Kernel modules: atlantic

04:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983 (prog-if 02 [NVM Express])
	Subsystem: Samsung Electronics Co Ltd SSD 970 EVO
	IOMMU group: 15
	Capabilities: [70] Express (v2) Endpoint, MSI 00
		LnkCap:	Port #0, Speed 8GT/s, Width x4, ASPM L1, Exit Latency L1 &amp;lt;64us
			ClockPM+ Surprise- LLActRep- BwNot- ASPMOptComp+
		LnkCtl:	ASPM Disabled; RCB 64 bytes, Disabled- CommClk+
			ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 8GT/s, Width x4
			TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
	Kernel driver in use: nvme
	Kernel modules: nvme

05:00.0 SATA controller: ASMedia Technology Inc. Device 1164 (rev 02) (prog-if 01 [AHCI 1.0])
	Subsystem: ASMedia Technology Inc. Device 2116
	IOMMU group: 16
	Capabilities: [80] Express (v2) Endpoint, MSI 00
		LnkCap:	Port #0, Speed 8GT/s, Width x2, ASPM L0s L1, Exit Latency L0s &amp;lt;4us, L1 &amp;lt;64us
			ClockPM+ Surprise- LLActRep- BwNot- ASPMOptComp+
		LnkCtl:	ASPM Disabled; RCB 64 bytes, Disabled- CommClk+
			ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 8GT/s, Width x2
			TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
	Kernel driver in use: ahci
	Kernel modules: ahci

06:00.0 Ethernet controller: Intel Corporation Ethernet Controller I226-V (rev 08)
	Subsystem: Intel Corporation Ethernet Controller I226-V
	IOMMU group: 17
	Capabilities: [a0] Express (v2) Endpoint, MSI 00
		LnkCap:	Port #0, Speed 5GT/s, Width x1, ASPM L1, Exit Latency L1 &amp;lt;4us
			ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp+
		LnkCtl:	ASPM Disabled; RCB 64 bytes, Disabled- CommClk+
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 5GT/s, Width x1
			TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
	Kernel driver in use: igc
	Kernel modules: igc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The two NICs are an Intel i226 (2.5G) and Aquantia AQC113 (10G NBase-T). Neither are limited in PCIe bandwidth. SATA is via an ASMedia controller off PCIe. The extra NVMe drive I added (Samsung) is in a different IOMMU group, in fact both of the NICs and both of the SSDs are in their own IOMMU group if you want to pass any of them through to VMs.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>All About SUBNETTING your Networks! &#43; Setup in OPNsense</title>
      <link>https://www.apalrd.net/posts/2023/opnsense_subnet/</link>
      <pubDate>Wed, 06 Dec 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/opnsense_subnet/</guid>
      <description>You&amp;rsquo;ve probably heard all about creating multiple VLANs, for things like your IoT network, guest wifi, and more. But do you know what a VLAN actually is, and what the difference is between a VLAN and a Subnet? Today I&amp;rsquo;m going to cover the numbering of subnets in your network, and how to set up new subnet and VLAN interfaces in OPNsense. Come along on this adventure!
Contents Video Subnetes VLANs Video Subnets Starting in the last video, we have a basic network setup with the internet (green cable) and a &amp;lsquo;LAN&amp;rsquo; made up of only my laptop (black and yellow cable).</description>
      <content>&lt;p&gt;You&amp;rsquo;ve probably heard all about creating multiple VLANs, for things like your IoT network, guest wifi, and more. But do you know what a VLAN actually is, and what the difference is between a VLAN and a Subnet? Today I&amp;rsquo;m going to cover the numbering of subnets in your network, and how to set up new subnet and VLAN interfaces in OPNsense. Come along on this adventure!&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/opnsense_subnet/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/opnsense_subnet/#subnets&#34;&gt;Subnetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/opnsense_subnet/#vlans&#34;&gt;VLANs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/uKrxwySUH2I&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/opnsense_subnet/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;subnets&#34;&gt;Subnets&lt;/h2&gt;
&lt;p&gt;Starting in the last video, we have a basic network setup with the internet (green cable) and a &amp;lsquo;LAN&amp;rsquo; made up of only my laptop (black and yellow cable). This setup is represented by this diagram, with IP addresses:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Subnet Example 1&#34; src=&#34;https://www.apalrd.net/posts/2023/opnsense_subnet/subnet1.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s start by diving into what a subnet means.&lt;/p&gt;
&lt;p&gt;A Subnet is essentially an address plus a length, which describes how many bits of the address are part of the prefix and how many are part of the host.&lt;/p&gt;
&lt;p&gt;In this example, the IPv4 address of the laptop (10.212.46.10/24) would be interpreted as a 24-bit subnet, which means the first 24 bits become our prefix (10.212.46.0) and the last 8 become our host (10). In IPv6, the first 64 become the prefix (2001:db8:6969:5a01::) and the last 64 become the host (512b:d36f:d069:519a).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Subnet Example 2&#34; src=&#34;https://www.apalrd.net/posts/2023/opnsense_subnet/subnet2.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now I&amp;rsquo;ve added a network switch and some more clients to the network, and given them addresses. What happens when my laptop wants to ping my desktop? Since the prefix matches, it goes directly on-link and finds the host&amp;rsquo;s MAC address using NDP (the IPv6 equivalent of ARP in IPv4). This bypasses the firewall entirely.&lt;/p&gt;
&lt;p&gt;What happens if my laptop wants to ping an address on a different subnet? Since the prefix doesn&amp;rsquo;t match, the client will instead send the packet to the default router, and hope that the router can find the correct destination.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Subnet Example 3&#34; src=&#34;https://www.apalrd.net/posts/2023/opnsense_subnet/subnet3.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;vlans&#34;&gt;VLANs&lt;/h2&gt;
&lt;p&gt;In the last example, we had two different wires running all the way back to the router. The Yellow and Pink subnets need to be carried on separate sets of cabling, and using separate switches, since otherwise devices will try to get addresses on both subnets and it will be a mess.&lt;/p&gt;
&lt;p&gt;VLAN is short for &amp;lsquo;Virtual LAN&amp;rsquo;. While there are a ton of technologies which can implement virtual LANs, the most common over Ethernet is IEEE 802.1Q.&lt;/p&gt;
&lt;p&gt;Imagine this network topology. We would like to have all of our clients and all of our security cameras on two logically separate networks. We could do this by using two separate sets of cabling, and two sets of network switches, keeping them completely separate:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;VLAN Example 1&#34; src=&#34;https://www.apalrd.net/posts/2023/opnsense_subnet/vlan1.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;However, this costs money, especially since in a large network we might have more than just two networks to maintain. As we scale out the number of distinct networks we would like to operate, this gets unwieldly.&lt;/p&gt;
&lt;p&gt;The solution to this is to add a &amp;rsquo;tag&amp;rsquo; to identify which network it belongs to. As long as all of the switches are aware of this scheme, they can add tags to packets when they come in, and implement a virtual switch for each tag across the network. Trunk links carry all of the tags, so we can keep traffic separate even as it traverses a complex network of switches and devices.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;VLAN Example 2&#34; src=&#34;https://www.apalrd.net/posts/2023/opnsense_subnet/vlan2.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;Logically, however, these are still separate networks and are still isolated from each other as if they were separate physical switches and links. They do share bandwidth, but otherwise can&amp;rsquo;t interact with each other, assuming all of the devices on the network support VLAN tags. This is a Layer 2 solution, traffic we carry on a VLAN can be anything supported by Ethernet, such as Internet Protocol, but it&amp;rsquo;s not required to.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Proxmox Unprivilaged LXC Container Bind Mount UID/GID Mapping</title>
      <link>https://www.apalrd.net/posts/2023/tip_idmap/</link>
      <pubDate>Sun, 12 Nov 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/tip_idmap/</guid>
      <description>This is a snippet of my Personal Server Migration, but I thought it would be more useful as a stand-alone tutorial.
One of the challenges in dealing with unprivilaged LXC containers is that the UIDs/GIDs are mapped to 100000 in the host. This is a security feature, so the root user in the container doesn&amp;rsquo;t have root access if they are able to escape their container, but it&amp;rsquo;s also kinda a pain when sharing files between the host and container.</description>
      <content>&lt;p&gt;This is a snippet of my &lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_migrate/&#34;&gt;Personal Server Migration&lt;/a&gt;, but I thought it would be more useful as a stand-alone tutorial.&lt;/p&gt;
&lt;p&gt;One of the challenges in dealing with unprivilaged LXC containers is that the UIDs/GIDs are mapped to 100000 in the host. This is a security feature, so the root user in the container doesn&amp;rsquo;t have root access if they are able to escape their container, but it&amp;rsquo;s also kinda a pain when sharing files between the host and container. So, to solve this, I created a user and group on host and on guest with the same uid (in my case, 1000) to access my shares. I can then add users in the container to group 1000 so they have access to the files.&lt;/p&gt;
&lt;p&gt;So I added these lines to the LXC config ()&lt;code&gt;/etc/pve/lxc/&amp;lt;id?.conf&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;u 0 100000 1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;g 0 100000 1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;u 1000 1000 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;g 1000 1000 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;u 1001 101001 64535&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;g 1001 101001 64535&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just to walk through what this does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There are IDs 0 through 65535 (total of 65536 entires) which must exist on the guest, for both User and Group&lt;/li&gt;
&lt;li&gt;These lines configure how to map IDs in the host to IDs in the guest&lt;/li&gt;
&lt;li&gt;The first line maps 0 on guest -&amp;gt; 100000 on host quantity 1000 sequential IDs, for Users&lt;/li&gt;
&lt;li&gt;The second line does the same for Groups&lt;/li&gt;
&lt;li&gt;Then we map user 1000 on guest -&amp;gt; 1000 on host quantity 1 sequential ID, again for User then Group&lt;/li&gt;
&lt;li&gt;Finally we map user 1001 on guest -&amp;gt; 101001 on host quantity 64535 (65536 total - 1000 - 1 already mapped) for the rest of the IDs
We need to make sure that no IDs are listed twice on the guest side, there are no gaps on the guest side, and the total of UIDs and GIDs is 65536 on the guest side. The CT will fail to start if you get this wrong.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my case, I created a regular user + group (so not a system user) and it is 1000 on both sides, so I can map 1000 to 1000. If they are different, you&amp;rsquo;ll need to change them of course.&lt;/p&gt;
&lt;p&gt;To allow the host&amp;rsquo;s IDs to be passed into a container, we need to give permissions to a host user to do the mapping. Since root creates the container, the user root needs to be able to subuid / subgid for the users / groups that we are idmapping into the container. This is set by the files &lt;code&gt;/etc/subuid&lt;/code&gt; and &lt;code&gt;/etc/subgid&lt;/code&gt;. I added this line to both files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;root:1000:1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command allows the host user root to idmap {user, group} id 1000 quantity 1 sequential ID. Adjust as required for your setup.&lt;/p&gt;
&lt;p&gt;After doing this, I did a recursive chown of the data directories to 1000:1000 &lt;em&gt;on host&lt;/em&gt; and this also makes the guest&amp;rsquo;s user 1000 have access (since it&amp;rsquo;s idmapped).&lt;/p&gt;
&lt;p&gt;To actually pass the directory into the container, I use &lt;code&gt;pct&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pct set &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt; -mp0 /data/video,mp&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/mnt/video
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where &lt;code&gt;100&lt;/code&gt; is the ID of the container, &lt;code&gt;mp0&lt;/code&gt; is the mount point ID that Proxmox keeps track of, &lt;code&gt;/data/video&lt;/code&gt; is the path on host, and &lt;code&gt;/mnt/video&lt;/code&gt; is the path in the container.&lt;/p&gt;
&lt;p&gt;Good luck with your containers!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Unleash your Home Cameras with FRIGATE Self-Hosted AI Video Recorder! Install on Proxmox LXC</title>
      <link>https://www.apalrd.net/posts/2023/ultimate_frigate/</link>
      <pubDate>Thu, 09 Nov 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/ultimate_frigate/</guid>
      <description>Do you have security cameras at your house? Would you like to locally host all of your recording and analytics, to make sure nobody else has access to your video feeds and recordings? Would you also like to integrate with Home Assistant, the greatest open automation platform in the world? Then Frigate NVR is for you! In this video, I&amp;rsquo;m going to go in depth to setup Frigate in an LXC container, for maximum efficiency.</description>
      <content>&lt;p&gt;Do you have security cameras at your house? Would you like to locally host all of your recording and analytics, to make sure nobody else has access to your video feeds and recordings? Would you also like to integrate with Home Assistant, the greatest open automation platform in the world? Then Frigate NVR is for you! In this video, I&amp;rsquo;m going to go in depth to setup Frigate in an LXC container, for maximum efficiency. Using Podman Quadlet, I&amp;rsquo;m going to manage the Frigate container in a sane way with normal systemd and journalctl tools. And I&amp;rsquo;m going all-in on hardware passthrough, with my Coral TPU for advanced AI detections and person/cat/car counting, along with a basic Intel Quick Sync GPU to decode the video streams in hardware and reduce CPU load. So join me on this adventure!&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/#install-debian-lxc&#34;&gt;Install Debian LXC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/#install-frigate&#34;&gt;Install Frigate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/#install-caddy-reverse-proxy-for-tls&#34;&gt;Install Caddy Reverse Proxy for TLS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/#install-coral-tpu-drivers&#34;&gt;Install Coral TPU Drivers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/#passthrough-coral-tpu-to-container&#34;&gt;Passthrough Coral TPU to Container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/#passthrough-gpu-decode-to-container&#34;&gt;Passthrough GPU Decode to Container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/#my-frigate-config&#34;&gt;My Frigate Config&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;rsquo;s make Frigate work on the ultimate home server&lt;/p&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/sCkswrK0G3I&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;install-debian-lxc&#34;&gt;Install Debian LXC&lt;/h2&gt;
&lt;p&gt;Since I&amp;rsquo;d like to use some fairly recent features of Podman, we MUST start with debian 12 (Bookworm) or 13 (Trixie) when it is released. In addition, I added a second mount point at &lt;code&gt;/var/frigate&lt;/code&gt; for data. We need Nesting and FUSE enabled for this. I&amp;rsquo;m using a privilaged container since I am passing in devices.&lt;/p&gt;
&lt;p&gt;Be aware that enabling FUSE prevents Proxmox Backup (vzdump) from taking snapshot-style backups, it will get stuck trying to take the snapshot. You have to use suspend or stop mode. In this particular case, I&amp;rsquo;ve decided to not back up this container, since the only important file to recreate it is the config.yml for Frigate and the video files aren&amp;rsquo;t going to be backed up anyway.&lt;/p&gt;
&lt;p&gt;If you are on Debian Bookworm, you will need to upgrade to Trixie to have Podman Quadlet. If Trixie is already released, you can skip this step:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Replace bookworm with trixie in sources.list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Not needed if you are actually using Trixie (when it releases)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sed -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/bookworm/trixie/g&amp;#39;&lt;/span&gt; /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Update and dist-upgrade to Trixe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Answer yes to all prompts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt dist-upgrade -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, let&amp;rsquo;s install Podman, our container engine of choice:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install Podman&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install podman -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You also might want to set the timezone, so your Frigate recordings are in local time instead of UTC:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;timedatectl set-timezone &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;America/Detroit&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;install-frigate&#34;&gt;Install Frigate&lt;/h2&gt;
&lt;p&gt;Now we&amp;rsquo;re going to create the podman contaner file, which uses systemd syntax and lets us manage the container with systemd and avoid Docker nastiness.&lt;/p&gt;
&lt;p&gt;First up, create the folders for Frigate to mount:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create media and config directories&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /var/frigate/&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;media,config&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point, put your Frigate config file in &lt;code&gt;/var/frigate/config/config.yml&lt;/code&gt; in the container, read the frigate docs for that one (or see my own config later at the bottom).&lt;/p&gt;
&lt;p&gt;Our Quadlet unit file is &lt;code&gt;/etc/containers/systemd/frigate.container&lt;/code&gt; (You may need to create that directory, also):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Frigate video recorder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;network-online.target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Container&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Basic setup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ContainerName&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;frigate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Use LXC host networking&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#To avoid any Docker network nonsense&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Network&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;host
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#How to add environment variables like passwords&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Environment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;FRIGATE_RTSP_PASSWORD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Environment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;FRIGATE_MQTT_USER&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Environment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;FRIGATE_MQTT_PASSWORD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pass&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Mounted volumes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Volume&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/var/frigate/media:/media
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Volume&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/var/frigate/config:/config
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Volume&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/etc/localtime:/etc/localtime:ro
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#TempFS &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Mount&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tmpfs,target&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/tmp/cache,tmpfs-size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1000000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ShmSize&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;64m
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The image itself&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Image&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ghcr.io/blakeblackshear/frigate:stable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Auto-update from the registry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AutoUpdate&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;registry
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Restart automatically&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Restart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;always
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Give it a 15 minutes to start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Since any image pulls will take a long time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TimeoutStartSec&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;900&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Start on boot (default.target is &amp;#39;on boot&amp;#39;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi-user.target default.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally we can start the new service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The first time will take awhile since it pulls the image&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl start frigate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#We can&amp;#39;t systemctl enable it since these units are dynamically generated&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#So instead we WantedBy it, above&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And view logs with &lt;code&gt;journalctl -xeu frigate&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In case you&amp;rsquo;re curious or want to use Quadlet for your own containers, &lt;a href=&#34;https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html&#34;&gt;here&amp;rsquo;s a link to the docs on container units&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;install-caddy-reverse-proxy-for-tls&#34;&gt;Install Caddy Reverse Proxy for TLS&lt;/h2&gt;
&lt;p&gt;While it would be nice if the Frigate devs didn&amp;rsquo;t merge nginx with their own code so we could configure nginx for security, but we are stuck with their nginx config in their Docker image. As of now, this doesn&amp;rsquo;t even support IPv6, so we need some sort of front end proxy, and we also probably want a TLS certificate. I&amp;rsquo;ll show a self-signed cert in this example, but it&amp;rsquo;s also easy to use Let&amp;rsquo;s Encrypt.&lt;/p&gt;
&lt;p&gt;So, installing Caddy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install debian-keyring debian-archive-keyring apt-transport-https -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -1sLf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://dl.cloudsmith.io/public/caddy/stable/gpg.key&amp;#39;&lt;/span&gt; | gpg --dearmor -o /usr/share/keyrings/ caddy-stable-archive-keyring.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -1sLf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt&amp;#39;&lt;/span&gt; &amp;gt; /etc/apt/sources.list.d/caddy-stable.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install caddy -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the &lt;code&gt;/etc/caddy/Caddyfile&lt;/code&gt; I am using (delete the default and replace with this):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The Caddyfile is an easy way to configure your Caddy web server.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Don&amp;#39;t forget to put the hostname in DNS where it belongs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;corona.palnet.net {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Address of backend&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;reverse_proxy :5000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Settings for TLS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Internal means self-signed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;tls internal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And start it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now caddy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;install-coral-tpu-drivers&#34;&gt;Install Coral TPU Drivers&lt;/h2&gt;
&lt;p&gt;Since LXC containers share a kernel with the host, we need to install the Coral TPU drivers on the Proxmox host, NOT in the container. Since these drivers are also not in-tree, we need to install them via apt and compile them for the Proxmox kernel using dkms. So let&amp;rsquo;s do that now.&lt;/p&gt;
&lt;p&gt;Also, if you are using a USB TPU instead of PCIe, you can skip down to the host bind mount point. &lt;a href=&#34;https://coral.ai/docs/m2/get-started#2a-on-linux&#34;&gt;From the official Google docs&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add coral edgetpu repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb https://packages.cloud.google.com/apt coral-edgetpu-stable main&amp;#34;&lt;/span&gt; &amp;gt; /etc/apt/sources.list.d/coral-edgetpu.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add GPG key from Google&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Apt update to pull the package list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install the DKMS driver (we do *not* need the headers / libs since the container needs those)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install gasket-dkms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;FYI: Google can&amp;rsquo;t be bothered to update their repo with a build that works with recent Linux kernels&lt;/strong&gt;, so as of Proxmox 8.1 / Linux 6.5, the gasket-dkms package that we need is broken. The code has long been fixed in the &lt;a href=&#34;https://github.com/google/gasket-driver&#34;&gt;Github repo&lt;/a&gt; (thanks to open source contributors helping Google for free), but Google hasn&amp;rsquo;t built and published the binaries. Until then, you&amp;rsquo;ll have to compile it yourself, or &lt;a href=&#34;https://coral.ai/support/&#34;&gt;contact their support&lt;/a&gt; and tell them to fix it.&lt;/p&gt;
&lt;p&gt;In the meantime, the amazing Proxmox community has &lt;a href=&#34;https://forum.proxmox.com/threads/update-error-with-coral-tpu-drivers.136888/#post-608975&#34;&gt;a solution to get it to work&lt;/a&gt;, and the Linux community yeeted gasket out of the kernel for being unmaintained by Google. So you might want to migrate away from coral.ai before they end up on the &lt;a href=&#34;https://killedbygoogle.com/&#34;&gt;Killed By Google&lt;/a&gt; list.&lt;/p&gt;
&lt;p&gt;Also, a very nice Github user @feranick has published deb packages you can use for now, do this instead of the real instructions above until Google fixes their life:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Download package&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://github.com/feranick/gasket-driver/releases/download/1.0-18.2/gasket-dkms_1.0-18.2_all.deb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install with apt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install ./gasket*.deb -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In theory we should be able to &lt;code&gt;modprobe apex&lt;/code&gt; now. However, if you get an error like this, you&amp;rsquo;ll need to take a slight detour:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dkms: autoinstall &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; kernel 6.2.16-19-pve was skipped since the kernel headers &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; this kernel &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; not seem to be installed.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That means we don&amp;rsquo;t have headers installed. We can install them with &lt;code&gt;apt install pve-headers&lt;/code&gt;, but that will install the latest headers, not the headers for our version of Proxmox. The safest way to deal with this is to completely upgrade the Proxmox system and then install headers for the latest kernel version, to make sure the minor versions are entirely correct (i.e. the 6.2.16-19-pve).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install pve-headers -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt full-upgrade -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now reboot, so the new kernel image is used (otherwise there will be a discrepancy between the kernel it is trying to build / the headers, and the running kernel)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Then tell dkms to build and install the new modules (they are already installed, just not for this particular kernel version):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dkms autoinstall
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, after this, you an &lt;code&gt;modprobe apex&lt;/code&gt;. At this point, you should have a &lt;code&gt;/dev/apex_0&lt;/code&gt; for your TPU.&lt;/p&gt;
&lt;h2 id=&#34;passthrough-coral-tpu-to-container&#34;&gt;Passthrough Coral TPU to Container&lt;/h2&gt;
&lt;p&gt;Now that we have that device, let&amp;rsquo;s pass it through to the container. Make sure the LXC container is &lt;em&gt;not running&lt;/em&gt; and then edit its config file (&lt;code&gt;/etc/pve/lxc/&amp;lt;id&amp;gt;.conf&lt;/code&gt;) to add this at the end:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lxc.cgroup2.devices.allow: c 120:0 rwm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lxc.mount.entry: /dev/apex_0 dev/apex_0 none bind,optional,create&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course if you have multiple TPUs you can add all of the apex devices here.&lt;/p&gt;
&lt;p&gt;Now, start the container and we will deal with passing the device into Frigate.&lt;/p&gt;
&lt;p&gt;Under the &lt;code&gt;[Container]&lt;/code&gt; section of the frigate unit file, we need to add this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Pass-through Coral TPU&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AddDevice&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/dev/apex_0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, in our &lt;code&gt;config.yml&lt;/code&gt; for Frigate, add the line to configure the Coral TPU:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;detectors&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;coral1&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;edgetpu&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;device&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pci:0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can edit the &lt;code&gt;config.yml&lt;/code&gt; from within the Frigate UI if you want.&lt;/p&gt;
&lt;h2 id=&#34;passthrough-gpu-decode-to-container&#34;&gt;Passthrough GPU Decode to Container&lt;/h2&gt;
&lt;p&gt;I only have an Intel GPU to test currently, so here&amp;rsquo;s the config I am using. It should be &lt;em&gt;similar&lt;/em&gt; but not identical for AMD GPUs. Nvidia can fuck right off with their proprietary container driver mess, I&amp;rsquo;m not helping you guys with that one.&lt;/p&gt;
&lt;p&gt;First, we pass through the hardware to the container from Proxmox. Assuming you only have one GPU, it will be renderD128. If you have more, you can figure out which is which on your own. Shutdown the container and add these lines to the end of the container config (&lt;code&gt;/etc/pve/lxc/&amp;lt;id&amp;gt;.conf&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lxc.cgroup2.devices.allow: c 226:128 rwm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we need to add the device and also the perfmon capability to the Podman unit in the &lt;code&gt;[Container]&lt;/code&gt; section:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add device passthrough for render node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AddDevice&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/dev/dri/renderD128
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add capability for the container to monitor GPU performance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AddCapability&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;CAP_PERFMON
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you are not using the iHD driver, you might need one of these options:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Environment=LIBVA_DRIVER_NAME=&amp;#34;radeonsi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Environment=LIBVA_DRIVER_NAME=&amp;#34;i965&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, we need to configure Frigate to actually use these, by adding a new section to the &lt;code&gt;config.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Use hardware acceleration for ffmpeg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;ffmpeg&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;hwaccel_args&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;preset-intel-qsv-h264&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Other options are preset-intel-qsv-h265&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#For AMD cards use preset-vaapi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are using a very modern Intel CPU, you might need to enable the &amp;lsquo;guc&amp;rsquo; microcode loading. Create the file &lt;code&gt;/etc/modprobe.d/i915.conf&lt;/code&gt; and write in the following contents, then reboot:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;options i915 enable_guc&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I have no idea exactly which CPUs and kernel versions are affected.&lt;/p&gt;
&lt;p&gt;If you want to make sure your GPU is working, you can install either &lt;code&gt;intel_gpu_top&lt;/code&gt; from the &lt;code&gt;intel-gpu-tools&lt;/code&gt; package (Intel) or &lt;code&gt;radeontop&lt;/code&gt; from the &lt;code&gt;radeontop&lt;/code&gt; package and run it in the container.&lt;/p&gt;
&lt;h2 id=&#34;my-frigate-config&#34;&gt;My Frigate Config&lt;/h2&gt;
&lt;p&gt;This is sanitized, but close to what I actually have&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#MQTT server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;mqtt&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;telstar.palnet.net&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Use environment variable for these&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;user&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{FRIGATE_MQTT_USER}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{FRIGATE_MQTT_PASSWORD}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#One single PCIe edge TPU&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;detectors&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;coral1&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;edgetpu&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;device&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pci:0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Use hardware acceleration with h264 and intel quicksync vieo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;ffmpeg&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;hwaccel_args&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;preset-intel-qsv-h264&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Recording options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;record&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;enabled&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Keep all recordings for 2 days&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;retain&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;days&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;all&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Keep event recordings for 10 days&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;events&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;pre_capture&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;post_capture&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;retain&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;default&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;objects&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;person&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Cat is special&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;cat&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Camera configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;cameras&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Back door camera&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;back_door&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ffmpeg&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;inputs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rtsp://admin:{FRIGATE_RTSP_PASSWORD}@keyhole4.palnet.net:554/cam/realmonitor?channel=1&amp;amp;subtype=00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;roles&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;detect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;record&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;rtmp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;detect&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;width&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2560&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;height&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1440&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Per camera object and filter settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;objects&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# Track persons and cats in only&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;track&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;person&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;cat   &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Front door camera&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;front_door&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ffmpeg&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;inputs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rtsp://admin:{FRIGATE_RTSP_PASSWORD}@keyhole3.palnet.net:554/cam/realmonitor?channel=1&amp;amp;subtype=00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;roles&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;detect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;record&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;rtmp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;detect&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;width&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2560&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;height&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1440&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Per camera object and filter settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;objects&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# Track persons and cats in only&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;track&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;person&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;cat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Front Yard camera&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;front_yard&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ffmpeg&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;inputs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rtsp://admin:{FRIGATE_RTSP_PASSWORD}@keyhole2.palnet.net:554/cam/realmonitor?channel=1&amp;amp;subtype=00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;roles&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;record&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;rtmp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rtsp://admin:{FRIGATE_RTSP_PASSWORD}@keyhole2.palnet.net:554/cam/realmonitor?channel=1&amp;amp;subtype=01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;roles&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;detect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;detect&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;width&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;704&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;height&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;480&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Per camera object and filter settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;objects&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# Track persons and cats in only&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;track&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;person&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;car&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Driveway Camera (2 resolutions)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;driveway&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ffmpeg&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;inputs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rtsp://admin:{FRIGATE_RTSP_PASSWORD}@keyhole1.palnet.net:554/cam/realmonitor?channel=1&amp;amp;subtype=00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;roles&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;record&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rtsp://admin:{FRIGATE_RTSP_PASSWORD}4@keyhole1.palnet.net:554/cam/realmonitor?channel=1&amp;amp;subtype=02&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;roles&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;detect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;rtmp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;detect&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;width&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1280&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;height&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;720&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Per camera object and filter settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;objects&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# Track everything&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;track&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;person&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;car&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;cat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Driveway Cars Camera&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;driveway_cars&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ffmpeg&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;inputs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rtsp://admin:{FRIGATE_RTSP_PASSWORD}@keyhole5.palnet.net:554/cam/realmonitor?channel=1&amp;amp;subtype=00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;roles&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;record&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;rtmp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rtsp://admin:{FRIGATE_RTSP_PASSWORD}@keyhole5.palnet.net:554/cam/realmonitor?channel=1&amp;amp;subtype=01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;roles&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;detect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;detect&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;width&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;704&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;height&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;480&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Per camera object and filter settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;objects&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# Track everything&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;track&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;person&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;car&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;cat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Installing Mikrotik RouterOS on Proxmox VE easily</title>
      <link>https://www.apalrd.net/posts/2023/tip_routeros/</link>
      <pubDate>Mon, 06 Nov 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/tip_routeros/</guid>
      <description>I&amp;rsquo;ve been using Mikrotik RouterOS for awhile now, both using their hardware and their virtual image (Cloud Hosted Router). It&amp;rsquo;s a great product for routing and firewalling, while it&amp;rsquo;s not a NGFW it&amp;rsquo;s an absolutely amazing router and their L2/L3 switches are also a great value for the price.
So anyway, I often setup images of the latest CHR in Proxmox VE for testing things. I create vmbr bridges in Proxmox to point-to-point link multiple CHRs, and can lab out complex network setups.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve been using Mikrotik RouterOS for awhile now, both using their hardware and their virtual image (Cloud Hosted Router). It&amp;rsquo;s a great product for routing and firewalling, while it&amp;rsquo;s not a NGFW it&amp;rsquo;s an absolutely amazing router and their L2/L3 switches are also a great value for the price.&lt;/p&gt;
&lt;p&gt;So anyway, I often setup images of the latest CHR in Proxmox VE for testing things. I create vmbr bridges in Proxmox to point-to-point link multiple CHRs, and can lab out complex network setups. Since CHR is free with a 1mbps throughput limit, it&amp;rsquo;s perfectly adequate to lab with only the free VMs.&lt;/p&gt;
&lt;p&gt;So here&amp;rsquo;s the script I use to download and setup a Proxmox VM template for the latest version of RouterOS, from which I can clone and add network interfaces to.&lt;/p&gt;
&lt;p&gt;Make sure to paste in the latest download link from the &lt;a href=&#34;https://mikrotik.com/download&#34;&gt;Mikrotik download site&lt;/a&gt;. You want the latest stable Cloud Hosted Router - Raw Image. As of this writing, it&amp;rsquo;s ROS V7.11.2.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://download.mikrotik.com/routeros/7.11.2/chr-7.11.2.img.zip&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;unzip chr-7.11.2.img.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qm create &lt;span style=&#34;color:#ae81ff&#34;&gt;940&lt;/span&gt; --name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-mikrotik-ros-7.11.2&amp;#34;&lt;/span&gt; --ostype l26
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qm set &lt;span style=&#34;color:#ae81ff&#34;&gt;940&lt;/span&gt; --net0 virtio,bridge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vmbr0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qm set &lt;span style=&#34;color:#ae81ff&#34;&gt;940&lt;/span&gt; --serial0 socket --vga serial0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Yes, really, this is how littke RAM it needs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qm set &lt;span style=&#34;color:#ae81ff&#34;&gt;940&lt;/span&gt; --memory &lt;span style=&#34;color:#ae81ff&#34;&gt;256&lt;/span&gt; --cores &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; --cpu host
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Import the disk as scsi0, default boot order, resize up to 8G&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qm set &lt;span style=&#34;color:#ae81ff&#34;&gt;940&lt;/span&gt; --scsi0 local-zfs:0,import-from&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;pwd&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/chr-7.11.2.img&amp;#34;&lt;/span&gt;,discard&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;on
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qm set &lt;span style=&#34;color:#ae81ff&#34;&gt;940&lt;/span&gt; --boot order&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;scsi0 --scsihw virtio-scsi-single
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qm disk resize &lt;span style=&#34;color:#ae81ff&#34;&gt;940&lt;/span&gt; scsi0 8G
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make it a template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qm template &lt;span style=&#34;color:#ae81ff&#34;&gt;940&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you followed my &lt;a href=&#34;https://www.apalrd.net/posts/2023/pve_cloud/&#34;&gt;Easy Mode Cloud-Init Templates tutorial&lt;/a&gt;, 940 will be a number that fits well with that numbering scheme.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Building a TELEPROMPTER with a Raspberry Pi</title>
      <link>https://www.apalrd.net/posts/2023/studio_teleprompter/</link>
      <pubDate>Fri, 03 Nov 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/studio_teleprompter/</guid>
      <description>Come along as I 3D print my own teleprompter! Hopefully improving my production quality, I guess you guys will be the judge of that.
And the zip file for the parts (STL, 3MF, and FreeCAD originals) (CC-BY-SA)</description>
      <content>&lt;p&gt;Come along as I 3D print my own teleprompter! Hopefully improving my production quality, I guess you guys will be the judge of that.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/V-tsVKjjme4&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/studio_teleprompter/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/studio_teleprompter/studio_teleprompter.zip&#34;&gt;And the zip file for the parts (STL, 3MF, and FreeCAD originals) (CC-BY-SA)&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>A $9 Introduction to the RISC-V Future of Computing</title>
      <link>https://www.apalrd.net/posts/2023/riscv_duo/</link>
      <pubDate>Mon, 09 Oct 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/riscv_duo/</guid>
      <description>Is RISC-V the future of computing? I sure hope so. So I tracked down one of the cheapest Linux-capable SBCs that supports this architecture, the Milk-V Duo. For a retail price of $9, this little guy offers a RV64 Linux environment complete with busybox, Ethernet, and a wide assortment of IO rivaling some microcontrollers. Today I&amp;rsquo;m going to steup the board and start learning about RISC-V computing!
Fundamentally, the RISC-V architecture is a document which describes the binary machine lanuage of a 32, 64, or 128 bit processor with integer and optional floating point support, but it&amp;rsquo;s also symbolic of the shift to open computing for the future, and as a computer engineer I&amp;rsquo;m excited to learn more about it.</description>
      <content>&lt;p&gt;Is RISC-V the future of computing? I sure hope so. So I tracked down one of the cheapest Linux-capable SBCs that supports this architecture, the Milk-V Duo. For a retail price of $9, this little guy offers a RV64 Linux environment complete with busybox, Ethernet, and a wide assortment of IO rivaling some microcontrollers. Today I&amp;rsquo;m going to steup the board and start learning about RISC-V computing!&lt;/p&gt;
&lt;p&gt;Fundamentally, the RISC-V architecture is a document which describes the binary machine lanuage of a 32, 64, or 128 bit processor with integer and optional floating point support, but it&amp;rsquo;s also symbolic of the shift to open computing for the future, and as a computer engineer I&amp;rsquo;m excited to learn more about it.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/riscv_duo/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/riscv_duo/#test-code&#34;&gt;Test Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/riscv_duo/#ipv6-enabled-sd-card-image&#34;&gt;IPv6-enabled SD Card Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/riscv_duo/#no-iom-gpu-sd-card-image&#34;&gt;No-IOM SD Card Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/riscv_duo/#swap-on-sd-card&#34;&gt;Swap on SD Card&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/z-GoLDQHYsE&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/riscv_duo/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;test-code&#34;&gt;Test Code&lt;/h2&gt;
&lt;p&gt;I compiled 3 test programs in 5 different 64-bit architectures (AMD, ARM, RISC-V, PowerPC, and MIPS). &lt;a href=&#34;https://github.com/apalrd/riscv-morse/&#34;&gt;You can find the code and the resulting assembly here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;ipv6-enabled-sd-card-image&#34;&gt;IPv6-enabled SD Card Image&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d like to use my IPv6-enabled SD Card image, &lt;a href=&#34;https://github.com/apalrd/milkv-duo-buildroot-sdk/releases/tag/v1.0.4.1&#34;&gt;I&amp;rsquo;ve released it on my github here&lt;/a&gt;. I&amp;rsquo;ve also submitted a pull request which you can &lt;a href=&#34;https://github.com/milkv-duo/duo-buildroot-sdk/pull/15&#34;&gt;check the status of here&lt;/a&gt;, so you can go back to their releases once it&amp;rsquo;s merged.&lt;/p&gt;
&lt;h2 id=&#34;no-iom-gpu-sd-card-image&#34;&gt;No-IOM (GPU) SD Card Image&lt;/h2&gt;
&lt;p&gt;I also have a build with both IPv6 and the IOM (which does graphics processing) disabled, if you need more memory and don&amp;rsquo;t need the camera features. &lt;a href=&#34;https://github.com/apalrd/milkv-duo-buildroot-sdk/releases/tag/v1.0.4.2&#34;&gt;It&amp;rsquo;s also on my github&lt;/a&gt;. No PR for this one, but you can look at the &lt;code&gt;no-iom&lt;/code&gt; branch in my repo to see the changes.&lt;/p&gt;
&lt;p&gt;Memory before:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#ae81ff&#34;&gt;total        used        free      shared  buff/cache   available&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Mem&lt;/span&gt;:          &lt;span style=&#34;color:#ae81ff&#34;&gt;29236&lt;/span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;14172&lt;/span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;8336&lt;/span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;6728&lt;/span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;12260&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Swap&lt;/span&gt;:             &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;           &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;           &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Memory after:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#ae81ff&#34;&gt;total        used        free      shared  buff/cache   available&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Mem&lt;/span&gt;:          &lt;span style=&#34;color:#ae81ff&#34;&gt;56680&lt;/span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;14132&lt;/span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;35844&lt;/span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;6704&lt;/span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;38668&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Swap&lt;/span&gt;:             &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;           &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;           &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;swap-on-sd-card&#34;&gt;Swap on SD Card&lt;/h2&gt;
&lt;p&gt;The default SD card image has a 256M space allocated for swap, but it&amp;rsquo;s not formatted/mounted. You can do that fairly easily:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkswap /dev/mmcblk0p3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;swapon /dev/mmcblk0p3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the future you just need to run the &lt;code&gt;swapon&lt;/code&gt; command to enable the partition that&amp;rsquo;s already formatted. Looking at &lt;code&gt;free&lt;/code&gt;, we get swap now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#ae81ff&#34;&gt;total        used        free      shared  buff/cache   available&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Mem&lt;/span&gt;:          &lt;span style=&#34;color:#ae81ff&#34;&gt;56680&lt;/span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;14216&lt;/span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;35264&lt;/span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;7200&lt;/span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;38596&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Swap&lt;/span&gt;:        &lt;span style=&#34;color:#ae81ff&#34;&gt;262140&lt;/span&gt;           &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;262140&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you should have enough memory for some real work! It&amp;rsquo;s just super slow SD card memory lol.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Packet Capture in Proxmox</title>
      <link>https://www.apalrd.net/posts/2023/tip_pcap/</link>
      <pubDate>Sun, 01 Oct 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/tip_pcap/</guid>
      <description>When you&amp;rsquo;re troubleshooting network issues, it&amp;rsquo;s often extremely helpful to view and analyze packet captures. The de-facto tool for this is the open-source Wireshark, which has an extensive protocol decoding capability. So, as a Proxmox user, it would be nice to be able to analyze VM networking issues using Wireshark.
Unfortunately for us, Wireshark is a graphical application and Proxmox&amp;rsquo;s web UI doesn&amp;rsquo;t support it. However, we can use the command-line tool tcpdump to create a pcap file, and then analyze that file in Wireshark.</description>
      <content>&lt;p&gt;When you&amp;rsquo;re troubleshooting network issues, it&amp;rsquo;s often extremely helpful to view and analyze packet captures. The de-facto tool for this is the open-source &lt;a href=&#34;https://www.wireshark.org/&#34;&gt;Wireshark&lt;/a&gt;, which has an extensive protocol decoding capability. So, as a Proxmox user, it would be nice to be able to analyze VM networking issues using Wireshark.&lt;/p&gt;
&lt;p&gt;Unfortunately for us, Wireshark is a graphical application and Proxmox&amp;rsquo;s web UI doesn&amp;rsquo;t support it. However, we can use the command-line tool &lt;code&gt;tcpdump&lt;/code&gt; to create a pcap file, and then analyze that file in Wireshark.&lt;/p&gt;
&lt;p&gt;To do this, we need to know what interface on the Proxmox system corresponds to the net interface on our VM. Looking at the VM&amp;rsquo;s Hardware pane, we can see the &lt;code&gt;net0&lt;/code&gt; and &lt;code&gt;net1&lt;/code&gt; interfaces in this example. Take note of that number, it&amp;rsquo;s important.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;VM Hardware Pane&#34; src=&#34;https://www.apalrd.net/posts/2023/tip_pcap/vm_settings.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;For &lt;code&gt;net0&lt;/code&gt; of VM 501, the Linux device we need to capture will be named &lt;code&gt;tap501i0&lt;/code&gt;. This is located between the Proxmox firewall and the VM, if you have the firewall enabled (you probably should use it, it&amp;rsquo;s a great tool). Conceptually it looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Firewall Diagram&#34; src=&#34;https://www.apalrd.net/posts/2023/tip_pcap/fwdiagram.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;So, finally, to capture traffic, run &lt;code&gt;tcpdump&lt;/code&gt; from the Proxmox shell.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;TCPdump command&#34; src=&#34;https://www.apalrd.net/posts/2023/tip_pcap/tcpdump.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;For this example, the command is &lt;code&gt;tcpdump -i tap501i0 -n -w &amp;lt;filename&amp;gt;.pcap&lt;/code&gt;. You can use whatever file name you want. Use Ctrl+C when you are all done.&lt;/p&gt;
&lt;p&gt;To copy the file off, you can use &lt;code&gt;scp&lt;/code&gt;, or store move the file to a network location you have access to. Network storage in Proxmox is mounted at /mnt/pve/&lt;storage name&gt;, fyi.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.tcpdump.org/manpages/tcpdump.1.html&#34;&gt;Man Page for tcpdump in case you need it&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>REALLY Persistent Ethernet Interfaces on Linux</title>
      <link>https://www.apalrd.net/posts/2023/tip_link/</link>
      <pubDate>Mon, 25 Sep 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/tip_link/</guid>
      <description>So Linux has adopted Persistent Device Naming, which is a really great thing for most systems. Unlike the old days where we just had eth0 and eth1 and eth2 etc (which at least has no spaces unlike Local Area Connection 6 that another OS uses), whose order depended on driver initialization in the kernel. Most people just had eth0 and were happy, and most people will still just have one Ethernet interface and will still be happy.</description>
      <content>&lt;p&gt;So Linux has adopted Persistent Device Naming, which is a really great thing for most systems. Unlike the old days where we just had &lt;code&gt;eth0&lt;/code&gt; and &lt;code&gt;eth1&lt;/code&gt; and &lt;code&gt;eth2&lt;/code&gt; etc (which at least has no spaces unlike &lt;code&gt;Local Area Connection 6&lt;/code&gt; that another OS uses), whose order depended on driver initialization in the kernel. Most people just had &lt;code&gt;eth0&lt;/code&gt; and were happy, and most people will still just have one Ethernet interface and will still be happy.&lt;/p&gt;
&lt;p&gt;But with more complex setups, this persistent naming can be a problem, especially as PCIe devices come and go and change the bus layout. I&amp;rsquo;d really like truly persistent naming, tied to the specific MAC address or something, that won&amp;rsquo;t ever change no matter what else I do with the system.&lt;/p&gt;
&lt;p&gt;To be fair to persistent device names, for most people who are not making regular hardware changes, they are a good thing. The hierarchy of naming prefers onboard naming when possible (i.e. provided by the UEFI / HW), followed by the device path. This device path is consistent across reboots, but adding or removing hardware can cause items in the list to move up and down, changing their path ID (i.e. &lt;code&gt;enp4&lt;/code&gt; becomes &lt;code&gt;enp5&lt;/code&gt; after adding another PCIe card). But at least replacing hardware with identical hardware will keep the path IDs the same, so we can replace NICs or really anything else in the system without messing up our network configuration.&lt;/p&gt;
&lt;h2 id=&#34;solution&#34;&gt;Solution&lt;/h2&gt;
&lt;p&gt;The solution is to rename these devices on our own terms instead of the udev methodology. We can match hardware based on IDs such as the MAC address, which identifies a singular NIC, and use this to assign a name of our own. Now it&amp;rsquo;s up to us to modify this file if we ever replace a NIC, but at least other things in the system won&amp;rsquo;t change our name.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://manpages.debian.org/bookworm/udev/systemd.link.5.en.html&#34;&gt;Here&amp;rsquo;s the documentation for systemd link units, it&amp;rsquo;s incredible really.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So given that information, I constructed the absolute minimal link file for my Proxmox system. We can&amp;rsquo;t use any name that the system might assign automatically (such as ethX, enoX, enpX, &amp;hellip;) or we are in for trouble. I was originally going to name them &lt;code&gt;geX&lt;/code&gt; for gigabit ethernet and &lt;code&gt;xgX&lt;/code&gt; for 10/25Gig, but Proxmox&amp;rsquo;s web UI was not a fan of this and refused to do any networking administration since it couldn&amp;rsquo;t figure out what type those were by parsing the &lt;code&gt;/etc/network/interfaces&lt;/code&gt; file. So, I settled on &lt;code&gt;enge0&lt;/code&gt; for my onboard gigabit Ethernet and &lt;code&gt;enxg1&lt;/code&gt; for the port on the 25 gig card that I&amp;rsquo;m using (enxg0 is the other port on the card, since these used to be function 0 and function 1 of the device).  Remember that &lt;code&gt;enx&lt;/code&gt; is used by devices identified by their MAC address and nothing else (usually USB NICs), so don&amp;rsquo;t use that. &lt;code&gt;eno&lt;/code&gt;, &lt;code&gt;enp&lt;/code&gt;, and &lt;code&gt;ens&lt;/code&gt; are all used by udev as well.&lt;/p&gt;
&lt;p&gt;We now need to write a unit file for each interface we want to have a really permanent name, and it needs to start with a number less than 99, since 99-default.link will set the interface to regular persistent naming.&lt;/p&gt;
&lt;p&gt;That results in a file like &lt;code&gt;/etc/systemd/network/10-ge0.link&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Match]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;MACAddress&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;12:34:56:78:9a:bc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Link]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;enge0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add one for each, in my case I added 3. Make sure you get the MAC right. Now go into &lt;code&gt;/etc/network/interfaces&lt;/code&gt; and replace the old name with the new one. On reboot, udev should do its thing, call systemd-link, which will do it&amp;rsquo;s thing, and everything should magically come up.&lt;/p&gt;
&lt;p&gt;My &lt;code&gt;/etc/network/interfaces&lt;/code&gt; on Proxmox now looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# network interface settings; autogenerated&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Please do NOT modify this file directly, unless you know what&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# you&amp;#39;re doing.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# I know what I&amp;#39;m doing so I edited it manually&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auto lo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface lo inet loopback&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Real gigabit NIC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auto enge0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface enge0 inet6 manual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Dual port Mellanox NIC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auto enxg0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface enxg0 inet6 static&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;address fd69:beef:cafe:6::70/64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Dual port Mellanox NIC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auto enxg1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface enxg1 inet6 manual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Bond primary LAN NICs for failover&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auto bond0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface bond0 inet manual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;bond-slaves enge0 enxg1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;bond-miimon 100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;bond-mode active-backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;bond-primary enxg1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Primary VM bridge to LAN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auto vmbr0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface vmbr0 inet static&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;address 172.27.1.70/20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;gateway 172.27.0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;bridge-ports bond0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;bridge-stp off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;bridge-fd 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;bridge-vlan-aware yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;bridge-vids 2-4094&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface vmbr0 inet6 static&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;address 2001:db8:6969:420::70/64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;gateway 2001:db8:6969:420::1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And they show up Proxmox UI too!
&lt;img alt=&#34;Proxmox UI&#34; src=&#34;https://www.apalrd.net/posts/2023/tip_link/proxmox.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;And of course &lt;code&gt;ip a&lt;/code&gt; shows the interfaces as expected!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;3: enge0&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;lt;NO-CARRIER,BROADCAST,MULTICAST,SLAVE,UP&amp;gt; mtu 1500 qdisc pfifo_fast master bond0 state DOWN group default qlen 1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;link/ether 26:a9:1e:5e:7f:5d brd ff:ff:ff:ff:ff:ff permaddr a8:a1:59:22:48:32&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;7: enxg0&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc mq state UP group default qlen 1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;link/ether b8:ce:f6:ae:38:e4 brd ff:ff:ff:ff:ff:ff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;inet6 fd69:beef:cafe:6::70/64 scope global &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;valid_lft forever preferred_lft forever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;inet6 fe80::bace:f6ff:feae:38e4/64 scope link &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;valid_lft forever preferred_lft forever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;8: enxg1&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;lt;BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP&amp;gt; mtu 1500 qdisc mq master bond0 state UP group default qlen 1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;link/ether 26:a9:1e:5e:7f:5d brd ff:ff:ff:ff:ff:ff permaddr b8:ce:f6:ae:38:e5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;9: bond0&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;lt;BROADCAST,MULTICAST,MASTER,UP,LOWER_UP&amp;gt; mtu 1500 qdisc noqueue master vmbr0 state UP group default qlen 1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;link/ether 26:a9:1e:5e:7f:5d brd ff:ff:ff:ff:ff:ff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;10: vmbr0&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc noqueue state UP group default qlen 1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;link/ether 26:a9:1e:5e:7f:5d brd ff:ff:ff:ff:ff:ff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;inet 172.27.1.70/20 scope global vmbr0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;valid_lft forever preferred_lft forever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;inet6 2001:db8:6969:420::70/64 scope global &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;valid_lft forever preferred_lft forever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;inet6 fe80::24a9:1eff:fe5e:7f5d/64 scope link &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;valid_lft forever preferred_lft forever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So now I&amp;rsquo;m free to add/remove PCIe cards at will (this system gets used for a lot of testing random devices) and not worry about what that will do to my main NIC.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Migrating my PERSONAL SERVER from TrueNAS to Proxmox</title>
      <link>https://www.apalrd.net/posts/2023/ultimate_migrate/</link>
      <pubDate>Wed, 20 Sep 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/ultimate_migrate/</guid>
      <description>Today I&amp;rsquo;m taking my 10 servers and hopefully working that list down to just 7! JUST SEVEN! So, driven by my desire to consolidate my critical services into one box so I can lab away with the rest of the boxes, I am taking the time to shut down some of the most critical servers in the house and re-home them, then disassemble the parts for the next project.
Come along with me on this adventure!</description>
      <content>&lt;p&gt;Today I&amp;rsquo;m taking my 10 servers and hopefully working that list down to just 7! JUST SEVEN!
So, driven by my desire to consolidate my critical services into one box so I can lab away with the rest of the boxes, I am taking the time to shut down some of the most critical servers in the house and re-home them, then disassemble the parts for the next project.&lt;/p&gt;
&lt;p&gt;Come along with me on this adventure!&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_migrate/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_migrate/#my-servers&#34;&gt;My Servers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_migrate/#unprivilaged-container-bind-mount-uidgid-mapping&#34;&gt;Unprivilaged Container Bind Mount UID/GID Mapping&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_migrate/#large-dataset-backups-to-proxmox-backup-server&#34;&gt;Large Dataset Backups to Proxmox Backup Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_migrate/#sanoid-for-snapshots&#34;&gt;Sanoid for Snapshots&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_migrate/#shadow-copy-with-sanoid&#34;&gt;Shadow Copy with Sanoid&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/_D6VVlqWwSA&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_migrate/thumbnail.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;my-servers&#34;&gt;My Servers&lt;/h1&gt;
&lt;p&gt;So anyway here&amp;rsquo;s the list of what I have now and their current jobs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Iridium - TrueNAS SCALE - It&amp;rsquo;s just doing Samba, nothing else at this point. I kinda hate the TrueNAS dev&amp;rsquo;s highly restrictive attitude.&lt;/li&gt;
&lt;li&gt;Minilab - my Ryzen 2400G mini-PC - It&amp;rsquo;s doing &lt;em&gt;mission critical&lt;/em&gt; VMs and CTs like Home Assistant. It also has some Coral TPU cards for Frigate.&lt;/li&gt;
&lt;li&gt;Terra - This is the Terramaster NAS from another video. It&amp;rsquo;s currently only used for filming videos, but it&amp;rsquo;s cheap and low-power.&lt;/li&gt;
&lt;li&gt;Corona - Runs Frigate and was formerly a VM on Minilab, but I moved it to the ZimaBoard so I can do a test of different acceleration methods for an upcoming video.&lt;/li&gt;
&lt;li&gt;Megalab - This is the PC on a box that you see in a lot of my vieos.&lt;/li&gt;
&lt;li&gt;pve1,pve2,pve3 - This is my 3-node cluster from the cluster series&lt;/li&gt;
&lt;li&gt;My firewall router running OPNsense - nothing will change here&lt;/li&gt;
&lt;li&gt;Bigstor, my Proxmox Backup Server (also feat. LTO Tapes) - nothing will change here either&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today, I have a few tasks all happening at once, to minimize downtime:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Purge everything off Terra and remove the spinning drive pool and drives&lt;/li&gt;
&lt;li&gt;Migrate all of the workloads on Minilab to Terra and bring them back up, especially home automation, with minimal downtime&lt;/li&gt;
&lt;li&gt;Spin down the TrueNAS SCALE server and migrate those Samba datasets to a container in Proxmox on Minilab, similar to my &lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_nas/&#34;&gt;Pretty Good NAS&lt;/a&gt; video.&lt;/li&gt;
&lt;li&gt;Properly deal with file permissions when passing datasets into a container via bind mounts, since I glossed over permissions in the previous video.&lt;/li&gt;
&lt;li&gt;Setup proper backups to my &lt;a href=&#34;https://www.apalrd.net/posts/2023/pbs_intro/&#34;&gt;Proxmox Backup Server&lt;/a&gt; from the Cockpit+Samba container, in a way that is scalable and lets me configure the frequency and stuff for each dataset, and get the full benefit of file-based recovery from PBS.&lt;/li&gt;
&lt;li&gt;Setup snapshots of the zfs dataset in Proxmox (like I had in TrueNAS), more for accidental deletion prevention than long term backups. These should be done extrmely frequently.&lt;/li&gt;
&lt;li&gt;Setup Shadow Copy so I can access accidentally deleted files myself without going to the backup server&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m not including separate sections in the blog on the pruging / migration since it was unremarkable. I shutdown the VM/CT on Minilab, ran a backup in the Proxmox UI to the PBS server, and restored the backup on Terra. It just worked.&lt;/p&gt;
&lt;p&gt;Likewise, importing the zfs pool from TrueNAS to Proxmox was also fairly straightforward, I did a &lt;code&gt;zpool import -f&lt;/code&gt; to get the name of the pool and then &lt;code&gt;zpool import -f poolname&lt;/code&gt; to import it despite warnings that it was exported on a different system. All done, it imports automatically now. No need to even mention the names of the disks, zfs figures it all out.&lt;/p&gt;
&lt;h1 id=&#34;unprivilaged-container-bind-mount-uidgid-mapping&#34;&gt;Unprivilaged Container Bind Mount UID/GID Mapping&lt;/h1&gt;
&lt;p&gt;One of the challenges in dealing with unprivilaged LXC containers is that the UIDs/GIDs are mapped to 100000 in the host. This is a security feature, so the root user in the container doesn&amp;rsquo;t have root access if they are able to escape their container, but it&amp;rsquo;s also kinda a pain when sharing files between the host and container. So, to solve this, I created a user and group on host and on guest with the same uid (in my case, 1000) to access my shares. I can then map the Samba users in the container to this group to get permissions to the files.&lt;/p&gt;
&lt;p&gt;So I added these lines to the LXC config (in my case &lt;code&gt;/etc/pve/lxc/104.conf&lt;/code&gt;, replace &lt;code&gt;104&lt;/code&gt; with your CT ID):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;u 0 100000 1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;g 0 100000 1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;u 1000 1000 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;g 1000 1000 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;u 1001 101001 64535&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.idmap&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;g 1001 101001 64535&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just to walk through what this does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There are IDs 0 through 65535 (total of 65536 entires) which must exist on the guest, for both User and Group&lt;/li&gt;
&lt;li&gt;These lines configure how to map IDs in the host to IDs in the guest&lt;/li&gt;
&lt;li&gt;The first line maps 0 on guest -&amp;gt; 100000 on host quantity 1000 sequential IDs, for Users&lt;/li&gt;
&lt;li&gt;The second line does the same for Groups&lt;/li&gt;
&lt;li&gt;Then we map user 1000 on guest -&amp;gt; 1000 on host quantity 1 sequential ID, again for User then Group&lt;/li&gt;
&lt;li&gt;Finally we map user 1001 on guest -&amp;gt; 101001 on host quantity 64535 (65536 total - 1000 - 1 already mapped) for the rest of the IDs
We need to make sure that no IDs are listed twice on the guest side, there are no gaps on the guest side, and the total of UIDs and GIDs is 65536 on the guest side. The CT will fail to start if you get this wrong.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my case, I created a regular user + group (so not a system user) and it is 1000 on both sides, so I can map 1000 to 1000. If they are different, you&amp;rsquo;ll need to change them of course.&lt;/p&gt;
&lt;p&gt;To allow the host&amp;rsquo;s IDs to be passed into a container, we need to give permissions to a host user to do the mapping. Since root creates the container, the user root needs to be able to subuid / subgid for the users / groups that we are idmapping into the container. This is set by the files &lt;code&gt;/etc/subuid&lt;/code&gt; and &lt;code&gt;/etc/subgid&lt;/code&gt;. I added this line to both files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;root:1000:1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command allows the host user root to idmap {user, group} id 1000 quantity 1 sequential ID. Adjust as required for your setup.&lt;/p&gt;
&lt;p&gt;After doing this, I did a recursive chown of the data directories to 1000:1000 &lt;em&gt;on host&lt;/em&gt; and this also makes the guest&amp;rsquo;s user 1000 have access (since it&amp;rsquo;s idmapped).&lt;/p&gt;
&lt;p&gt;To actually pass the directory into the container, I use &lt;code&gt;pct&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pct set &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt; -mp0 /data/video,mp&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/mnt/video
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where &lt;code&gt;100&lt;/code&gt; is the ID of the container, &lt;code&gt;mp0&lt;/code&gt; is the mount point ID that Proxmox keeps track of, &lt;code&gt;/data/video&lt;/code&gt; is the path on host, and &lt;code&gt;/mnt/video&lt;/code&gt; is the path in the container.&lt;/p&gt;
&lt;h1 id=&#34;large-dataset-backups-to-proxmox-backup-server&#34;&gt;Large Dataset Backups to Proxmox Backup Server&lt;/h1&gt;
&lt;p&gt;One challenge with Proxmox Backup Server is that it&amp;rsquo;s not particularly good at large host backups. It&amp;rsquo;s very optimied for VMs, where the qemu dirty bitmask is used to know which static blocks have changed and must be reuploaded, but for file-based backups it reads all of the files and uploads chunks which have changed. This &amp;lsquo;read all the files&amp;rsquo; takes awhile. I also have different backup requirements for each of my datasets, and PBS has a requirement that all backups for a single VM/CT/Host are done together, since all of the differend disks end up as different entries in the same backup.&lt;/p&gt;
&lt;p&gt;So, with all of these requirements, I wrote some systemd scripts to do my large dataset file backups. Instead of doing a single backup of all of the datasets, I name each backup &amp;lsquo;host&amp;rsquo; after the dataset - so in PBS it shows up as host/video, host/media, &amp;hellip; instead of host/iridium with separate datasets for video and media. This means I can backup each dataset on its own time, separately. I&amp;rsquo;m happy with this. I also structured all of my datasets so they are located at /mnt/&lt;name&gt;, which means I can rely on this path in the backup scripts (name -&amp;gt; path translation means adding /mnt in front, no path lookups).&lt;/p&gt;
&lt;p&gt;First step is to install the Proxmox Backup Client &lt;em&gt;within the container&lt;/em&gt;. Proxmox provides a Debian repository for the backup client only, which you can add &lt;a href=&#34;https://pbs.proxmox.com/docs/installation.html#debian-package-repositories&#34;&gt;following their instructions&lt;/a&gt;. Then &lt;code&gt;apt install proxmox-backup-client&lt;/code&gt;. Yay! Now create an API user and key and all that jazz and get ready to copy it into the backup script.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the systemd script I wrote to do a single backup. It&amp;rsquo;s instanced, so it has @ at the end, and you pass a parameter for the backup you want to do (i.e. pbs-client@video). It goes in &lt;code&gt;/etc/systemd/system/pbs-client@.service&lt;/code&gt;. Make sure your backup user has read permissions to the data at least.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Description&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Run Backups&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;oneshot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run as backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;User&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Group&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Allow up to 15% CPU&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CPUQuota&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;15%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Environment&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;PBS_REPOSITORY=user@pbs@dns_name.lan:datastore&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Environment&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;PBS_PASSWORD=api_key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Environment&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;PBS_FINGERPRINT=&amp;#34;fingerprint&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run proxmox backup client for the passed directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ExecStart&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;proxmox-backup-client backup %i.pxar:/mnt/%i --all-file-systems true --backup-id &amp;#34;%i&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WantedBy&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;default.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After a &lt;code&gt;systemctl daemon-reload&lt;/code&gt; you are ready to do manual backups! Just &lt;code&gt;systemctl start pbs-client@video&lt;/code&gt; and it will create a backup id &amp;lsquo;video&amp;rsquo; with the file &amp;lsquo;video.pxar&amp;rsquo; from the path &amp;lsquo;/mnt/video&amp;rsquo;. Since Cockpit is amazing, you can watch the progress by going to the Services tab, finding that specific service, and viewing the logs. Awesome!&lt;/p&gt;
&lt;p&gt;Now we just need to time it to run regularly. Here&amp;rsquo;s a unit I use for that (&lt;code&gt;/etc/systemd/system/pbs-video.timer&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Backup Video Data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RefuseManualStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RefuseManualStop&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Timer&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run at 4am EST / 09 UTC some days&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OnCalendar&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Mon,Wed,Fri *-*-* 09:00:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;pbs-client@video.service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Install&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;timers.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now enable the timer with &lt;code&gt;systemctl enable pbs-video.timer&lt;/code&gt; and it will run on schedule. You can again monitor it from the Cockpit services tab.&lt;/p&gt;
&lt;h1 id=&#34;sanoid-for-snapshots&#34;&gt;Sanoid for Snapshots&lt;/h1&gt;
&lt;p&gt;Avoiding the issue of delegating zfs permissions into a container, I am installing &lt;a href=&#34;https://github.com/jimsalterjrs/sanoid&#34;&gt;Sanoid&lt;/a&gt; on the Proxmox host to take snapshots of the datasets used by the container. It&amp;rsquo;s a tool designed to take snapshots of zfs datasets basically, and it&amp;rsquo;s good at it. It&amp;rsquo;s also in the Debian repos, so we can just &lt;code&gt;apt install sanoid&lt;/code&gt; and edit the config file. Since this is mostly for Shadow Copy, I&amp;rsquo;m using the &amp;lsquo;frequently&amp;rsquo; snapshots due to naming convention quirks making it harder to use all of the different time steps in Shadow Copy.&lt;/p&gt;
&lt;p&gt;Users can still mount their own snapshots by browsing to the &lt;code&gt;.zfs&lt;/code&gt; folder in any directory, including within the container, and permissions are maintained for snapshots. So the container can now read snapshots of its own mounts, automatically.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the &lt;code&gt;/etc/sanoid/sanoid.conf&lt;/code&gt; snippet:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;# you can also handle datasets recursively in an atomic way without the possibility to override settings for child datasets.
[data/video]
        use_template = production
        recursive = zfs
[data/media]
        use_template = production
        recursive = zfs


#############################
# templates below this line #
#############################

# name your templates template_templatename. you can create your own, and use them in your module definitions above.

# Using a lot of frequently at 30min for Shadow Copy, since it isn&amp;#39;t a fan of the differently named snapshots.
[template_production]
        frequently = 144
        frequent_period = 30
        hourly = 0
        daily = 30
        monthly = 3
        yearly = 0
        autosnap = yes
        autoprune = yes
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;shadow-copy-with-sanoid&#34;&gt;Shadow Copy with Sanoid&lt;/h1&gt;
&lt;p&gt;In Cockpit File Sharing, I enabled the &amp;lsquo;Shadow Copy&amp;rsquo; and &amp;lsquo;MacOS Share&amp;rsquo; options, since I want Shadow copy and also want the shares to work well with my iphone and mac. Here are the &amp;lsquo;advanced options&amp;rsquo; for each share:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;shadow:snapdir&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;.zfs/snapshot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;shadow:sort&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;desc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;shadow:format&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;autosnap_%Y-%m-%d_%H:%M:%S_frequently&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vfs objects&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;catia fruit streams_xattr shadow_copy2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fruit:encoding&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;native&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fruit:metadata&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fruit:zero_file_id&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fruit:nfs_aces&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of note, the shadow:format means it will be taking Sanoid&amp;rsquo;s &lt;code&gt;frequently&lt;/code&gt; snapshots as the source of Shadow Copy. This works well, I am pleased.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Mellanox NICs with VLAN-Aware Bridges on Linux</title>
      <link>https://www.apalrd.net/posts/2023/tip_mellanox/</link>
      <pubDate>Thu, 14 Sep 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/tip_mellanox/</guid>
      <description>A Discord member of mine came to me with an interesting problem - enbling the VLAN-aware bridge in Proxmox would cause all network traffic on the physical card to stop, entirely. Definitely a frustrating issue, especially since the kernel logs made no sense.
The Problem Here&amp;rsquo;s what he sent from dmesg:
[ 32.732509] mlx5_core 0000:19:00.1: mlx5e_vport_context_update_vlans:179:(pid 13470): netdev vlans list size (4080) &amp;gt; (512) max vport list size, some vlans will be dropped [ 32.</description>
      <content>&lt;p&gt;A Discord member of mine came to me with an interesting problem - enbling the VLAN-aware bridge in Proxmox would cause all network traffic on the physical card to stop, entirely. Definitely a frustrating issue, especially since the kernel logs made no sense.&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what he sent from dmesg:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-log&#34; data-lang=&#34;log&#34;&gt;[   32.732509] mlx5_core 0000:19:00.1: mlx5e_vport_context_update_vlans:179:(pid 13470): netdev vlans list size (4080) &amp;gt; (512) max vport list size, some vlans will be dropped
[   32.735782] mlx5_core 0000:19:00.1: mlx5e_vport_context_update_vlans:179:(pid 13470): netdev vlans list size (4081) &amp;gt; (512) max vport list size, some vlans will be dropped
[   32.739011] mlx5_core 0000:19:00.1: mlx5e_vport_context_update_vlans:179:(pid 13470): netdev vlans list size (4082) &amp;gt; (512) max vport list size, some vlans will be dropped
[   32.742247] mlx5_core 0000:19:00.1: mlx5e_vport_context_update_vlans:179:(pid 13470): netdev vlans list size (4083) &amp;gt; (512) max vport list size, some vlans will be dropped
[   32.745550] mlx5_core 0000:19:00.1: mlx5e_vport_context_update_vlans:179:(pid 13470): netdev vlans list size (4084) &amp;gt; (512) max vport list size, some vlans will be dropped
[   32.748835] mlx5_core 0000:19:00.1: mlx5e_vport_context_update_vlans:179:(pid 13470): netdev vlans list size (4085) &amp;gt; (512) max vport list size, some vlans will be dropped
[   32.751987] mlx5_core 0000:19:00.1: mlx5e_vport_context_update_vlans:179:(pid 13470): netdev vlans list size (4086) &amp;gt; (512) max vport list size, some vlans will be dropped
[   32.755209] mlx5_core 0000:19:00.1: mlx5e_vport_context_update_vlans:179:(pid 13470): netdev vlans list size (4087) &amp;gt; (512) max vport list size, some vlans will be dropped
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So somehow the mlx5 driver is unhappy with how many VLANs he&amp;rsquo;s tagging (all of them), and only wants to pass 512. But even when he reduced that number, it still didn&amp;rsquo;t work. For reference, this is what a &lt;code&gt;/etc/network/interfaces&lt;/code&gt; looks like with this configuration in Proxmox:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Network adapter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auto enp6s0f1np1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface enp6s0f1np1 inet manual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Proxmox bridge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auto vmbr0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface vmbr0 inet6 static&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;address 2001:db8:beef:cafe::6969/64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;gateway 2001:db8:beef:cafe::420&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bridge-ports enp6s0f1np1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bridge-stp off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bridge-fd 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bridge-vlan-aware yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;bridge-vids 2-4094&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note the &lt;code&gt;bridge-vlan-aware&lt;/code&gt; and &lt;code&gt;bridge-vids&lt;/code&gt; tags. In this case, the bridge supports VLANs, and VIDs 2-4094 are tagged (so vlan 1 is untagged). He tried reducing this number to 255, still no dice.&lt;/p&gt;
&lt;p&gt;What made this even more interesting is we happen to have the exact same card! A Mellanox Connect-X4 dual 25G, both Dell branded as well! So I hopped on my test setup to figure out what the heck was going on, since my setup is working perfectly fine.&lt;/p&gt;
&lt;h2 id=&#34;the-solution&#34;&gt;The Solution&lt;/h2&gt;
&lt;p&gt;After searching the forums, we found two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nvidia are total assholes of the Linux community, their support forums just said &amp;lsquo;oh it looks like you&amp;rsquo;re using the Linux kernel drivers, we can&amp;rsquo;t help unless you use our proprietary drivers&amp;rsquo;. &lt;a href=&#34;https://www.youtube.com/watch?v=iYWzMvlj2RQ&#34;&gt;Linus was right to hate them!&lt;/a&gt; (&amp;ldquo;Nvidia has been one of the worst trouble spots we&amp;rsquo;ve had with hardware manufacturers&amp;rdquo;).&lt;/li&gt;
&lt;li&gt;Someone managed to fix it despite their non-help by enabling promiscuous mode.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So now that the problem is psuedo-solved, why does my setup work when his does not when we are using identical cards with the same kernel version (Linux 6.2.16-12-pve and Proxmox VE 8.0.4)? Maybe my dmesg will help:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-log&#34; data-lang=&#34;log&#34;&gt;[   17.708193] device bond0 entered promiscuous mode
[   68.300117] device enp6s0f1np1 entered promiscuous mode
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&amp;rsquo;m using a bond, and the bond sets its slaves into promiscuous mode. In my case, I&amp;rsquo;m using an active-backup bond between my 25G link and the 1G on the motherboard as a backup. He&amp;rsquo;s not using a bond, so no promiscuous mode, so Mellanox driver does weird things and can&amp;rsquo;t handle vlans properly.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the solution: &lt;code&gt;ip link set dev enp6s0f1np1 promisc on&lt;/code&gt;
We can add that to our &lt;code&gt;/etc/network/interfaces&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Network adapter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auto enp6s0f1np1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface enp6s0f1np1 inet manual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Enable promiscuous mode on the slave interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;post-up ip link set dev $IFACE promisc on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;even-more-solution&#34;&gt;Even More Solution&lt;/h2&gt;
&lt;p&gt;While this got the traffic flowing again, he was still getting a bunch of vlans list size &amp;gt; 512 errors after expanding the bridge-vids back to 4094. So, yes it fixed the initial issue, but it&amp;rsquo;s still trying to offload all vlans and not succeeding. If you still get that error in &lt;code&gt;dmesg&lt;/code&gt;, then maybe this additional fix will work for you (it wasn&amp;rsquo;t necessary for me, with the bond, so the bond appears to also disable hardware offload of vlans): &lt;code&gt;ethtool -K enp6s0f1np1 rx-vlan-filter off&lt;/code&gt;. If you just want to see the status, you can use &lt;code&gt;ethtool -k enp6s0f1np1&lt;/code&gt; (note the little k to read, big K to write). The new &lt;code&gt;/etc/network/interfaces&lt;/code&gt; would be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Network adapter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auto enp6s0f1np1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;iface enp6s0f1np1 inet manual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Enable promiscuous mode on the slave interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;post-up ip link set dev $IFACE promisc on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Disable RX VLAN filtering in hardware offload&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;pre-up ethtool -K $IFACE rx-vlan-filter off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Hope the tip helps you!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Gitea: Easy Self-Hosted Git Repositories!</title>
      <link>https://www.apalrd.net/posts/2023/ultimate_gitea/</link>
      <pubDate>Thu, 07 Sep 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/ultimate_gitea/</guid>
      <description>Contents Video Installation Configure HTTPS Self-Signed Configure HTTPS Let&amp;rsquo;s Encrypt Video Installation I&amp;rsquo;m using an LXC container in Proxmox running Debian 12. You&amp;rsquo;re free to use any other Debian 12 system, and the instructions should still work. It&amp;rsquo;s not particularly resource intensive, but you can monitor it to see if you need to increase the RAM/CPU allocations. I also added a second mount point to /var/lib/gitea, which is where all of the Gitea data will be stored.</description>
      <content>&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_gitea/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_gitea/#installation&#34;&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_gitea/#configure-https-self-signed&#34;&gt;Configure HTTPS Self-Signed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_gitea/#configure-https-lets-encrypt&#34;&gt;Configure HTTPS Let&amp;rsquo;s Encrypt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/NaKExFTCKtg&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_gitea/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m using an LXC container in Proxmox running Debian 12. You&amp;rsquo;re free to use any other Debian 12 system, and the instructions should still work. It&amp;rsquo;s not particularly resource intensive, but you can monitor it to see if you need to increase the RAM/CPU allocations. I also added a second mount point to &lt;code&gt;/var/lib/gitea&lt;/code&gt;, which is where all of the Gitea data will be stored. This just makes it easier to put the data and OS on separate storage locations, restore the entire Gitea install on another system later, or back it up separately.&lt;/p&gt;
&lt;p&gt;Here are the commands to setup Gitea. Make sure you go to the &lt;a href=&#34;https://dl.gitea.com/gitea/&#34;&gt;download site&lt;/a&gt; and get the link to te latest version. The download is the binary (it&amp;rsquo;s a Go static binary), so there&amp;rsquo;s nothing to unzip, and no file extension. You probably want linux-amd64.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install git -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Get the correct download link for the latest version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://dl.gitea.com/gitea/1.20.3/gitea-1.20.3-linux-amd64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Move the binary to bin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv gitea* /usr/local/bin/gitea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make executable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod +x /usr/local/bin/gitea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Ensure it works&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gitea --version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create the user/group for gitea to operate as&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adduser --system --group --disabled-password --home /etc/gitea gitea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Config directory was created by adduser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create directory structure (mountpoint should be /var/lib/gitea)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /var/lib/gitea/&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;custom,data,log&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R gitea:gitea /var/lib/gitea/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod -R &lt;span style=&#34;color:#ae81ff&#34;&gt;750&lt;/span&gt; /var/lib/gitea/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown root:gitea /etc/gitea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod &lt;span style=&#34;color:#ae81ff&#34;&gt;770&lt;/span&gt; /etc/gitea
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After that, we need a Systemd Service: (&lt;code&gt;/etc/systemd/system/gitea.service&lt;/code&gt;)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Gitea (Git with a cup of tea)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;syslog&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;network&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Service]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Uncomment the next line if you have repos with lots of files and get a HTTP 500 error because of that&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# LimitNOFILE=524288:524288&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RestartSec&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;notify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gitea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Group&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gitea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The mount point we added to the container&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WorkingDirectory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/var/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;gitea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create directory in /run&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RuntimeDirectory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gitea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/usr/&lt;/span&gt;local&lt;span style=&#34;color:#e6db74&#34;&gt;/bin/gi&lt;/span&gt;tea web &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;config &lt;span style=&#34;color:#e6db74&#34;&gt;/etc/gi&lt;/span&gt;tea&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;app&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ini
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Restart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;always
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Environment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;USER&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gitea HOME&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/var/&lt;/span&gt;lib&lt;span style=&#34;color:#e6db74&#34;&gt;/gitea/&lt;/span&gt;data GITEA_WORK_DIR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/var/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;gitea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WatchdogSec&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Capabilities to bind to low-numbered ports&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CapabilityBoundingSet&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;CAP_NET_BIND_SERVICE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AmbientCapabilities&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;CAP_NET_BIND_SERVICE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Install]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then run it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now gitea
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you can access it via &lt;IP&gt;:3000 to do the intial setup.&lt;/p&gt;
&lt;h2 id=&#34;configure-https-self-signed&#34;&gt;Configure HTTPS (Self-Signed)&lt;/h2&gt;
&lt;p&gt;And finally, configure Gitea to use HTTPS and the usual ports (80/443) using a self-signed cert (or one you provide, old-school) by editing &lt;code&gt;/etc/gitea/app.ini&lt;/code&gt;. I&amp;rsquo;ve provided a &lt;code&gt;diff&lt;/code&gt; below, the &lt;code&gt;+-&lt;/code&gt; indicates what lines to add and remove.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [server]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+PROTOCOL=https
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+REDIRECT_OTHER_PORT=true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+CERT_FILE = /etc/gitea/cert.pem
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+KEY_FILE  = /etc/gitea/key.pem
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; SSH_DOMAIN = gitea.palnet.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; DOMAIN = gitea.palnet.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-HTTP_PORT = 80
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+HTTP_PORT = 443
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; ROOT_URL = https://gitea.palnet.net/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; APP_DATA_PATH = /var/lib/gitea/data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; DISABLE_SSH = false
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then generate a self-signed certificate and restart the server:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Cd to the gitea directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc/gitea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#sign cert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gitea cert --host teapot.apalrd.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Give gitea user read permissions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown root:gitea cert.pem key.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod &lt;span style=&#34;color:#ae81ff&#34;&gt;640&lt;/span&gt; cert.pem key.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Restart gitea&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl restart gitea
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To temporarily ignore certificates in Git (for testing), you can use the option &lt;code&gt;-c http.sslVerify=false&lt;/code&gt; to &lt;code&gt;git&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;configure-https-lets-encrypt&#34;&gt;Configure HTTPS (Let&amp;rsquo;s Encrypt)&lt;/h2&gt;
&lt;p&gt;To use Let&amp;rsquo;s Encrypt you need a few different options in &lt;code&gt;/etc/gitea/app.ini&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [server]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+PROTOCOL=https
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+REDIRECT_OTHER_PORT=true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+ENABLE_ACME=true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+ACME_ACCEPTTOS=true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+ACME_DIRECTORY=https
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+ACME_URL=https://acme-staging-v02.api.letsencrypt.org/directory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+ACME_EMAIL=adventure@apalrd.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; SSH_DOMAIN = gitea.palnet.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; DOMAIN = gitea.palnet.net
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-HTTP_PORT = 80
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+HTTP_PORT = 443
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; ROOT_URL = https://gitea.palnet.net/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; APP_DATA_PATH = /var/lib/gitea/data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; DISABLE_SSH = false
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I have the URL set to the let&amp;rsquo;s encrypt staging repository as an example, you can use the directory URL of &lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/&#34;&gt;your own private CA&lt;/a&gt;, or leave it out entirely to use the let&amp;rsquo;s encrypt production server, which is the default if you leave the option out entirely. And then of course restart:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Restart gitea&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl restart gitea
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If Gitea can&amp;rsquo;t get a cert from Let&amp;rsquo;s Encrypt it &lt;em&gt;will&lt;/em&gt; crash and you will have to look at &lt;code&gt;journactl -xeu gitea&lt;/code&gt; to figure it out. Very frustrating. So make sure the Let&amp;rsquo;s Encrypt challenges will work (port 80 + 443 are correctly allowed by your network firewall)&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Should I use TAPE BACKUP in 2023? LTO-5 Drive with Proxmox Backup Server</title>
      <link>https://www.apalrd.net/posts/2023/pbs_tape/</link>
      <pubDate>Mon, 21 Aug 2023 00:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/pbs_tape/</guid>
      <description>As promised in a previous video about my Proxmox Backup Server, I have a Quantum LTO-5 tape drive that I&amp;rsquo;m going to try and use to implement a proper 3-tier backup strategy with offsite tapes.
I&amp;rsquo;m currently using Linode&amp;rsquo;s object storage for backing up my personal data (~200G), and not backing up the video files outside of the two existing copies (on the storage server and the PBS server). With the affordability of tapes, I can keep the video files and personal data off-site reliably.</description>
      <content>&lt;p&gt;As promised in a previous video about my Proxmox Backup Server, I have a Quantum LTO-5 tape drive that I&amp;rsquo;m going to try and use to implement a proper 3-tier backup strategy with offsite tapes.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m currently using Linode&amp;rsquo;s object storage for backing up my personal data (~200G), and not backing up the video files outside of the two existing copies (on the storage server and the PBS server). With the affordability of tapes, I can keep the video files and personal data off-site reliably.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/f6vhrbD9WkA&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/pbs_tape/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>MOVING My Website from Static Hosting to Caddy!</title>
      <link>https://www.apalrd.net/posts/2023/studio_website/</link>
      <pubDate>Fri, 28 Jul 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/studio_website/</guid>
      <description>I&amp;rsquo;ve been using Linode&amp;rsquo;s object hosting for my website for ~2 years now, and it&amp;rsquo;s time for a change. I&amp;rsquo;m not unhappy with Linode, but object hosting isn&amp;rsquo;t for me any more and I&amp;rsquo;d like to move up to a virtual private server. Object hosting is a fantastic way to get started with a static website for a low cost, but I want better backend analytics and more control of the whole process, so I&amp;rsquo;m setting up my own VPS using Caddy.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve been using Linode&amp;rsquo;s object hosting for my website for ~2 years now, and it&amp;rsquo;s time for a change. I&amp;rsquo;m not unhappy with Linode, but object hosting isn&amp;rsquo;t for me any more and I&amp;rsquo;d like to move up to a virtual private server. Object hosting is a fantastic way to get started with a static website for a low cost, but I want better backend analytics and more control of the whole process, so I&amp;rsquo;m setting up my own VPS using Caddy. At the same time, I&amp;rsquo;m setting up a privacy-respecting analytics system (Goatcounter) to read the web server log files and tell me how many viewers are enjoying my website. So, come along on this adventure!&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/studio_website/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/studio_website/#caddyfile&#34;&gt;Caddyfile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/studio_website/#caddy-service-override&#34;&gt;Caddy Service Override&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/studio_website/#goatcounter-service&#34;&gt;Goatcounter Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/studio_website/#web-rebuild-service-and-timer&#34;&gt;Web Rebuild Service and Timer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/Bcy6YRygIgA&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/studio_website/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;caddyfile&#34;&gt;Caddyfile&lt;/h1&gt;
&lt;p&gt;Caddyfile is a super simple syntax, easy to understand and use. Default options are very good for most people.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The Caddyfile is an easy way to configure your Caddy web server.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;www&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;apalrd&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;net {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Set this path to your site&amp;#39;s directory.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        root &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/var/&lt;/span&gt;apalrd&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;net&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;public
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Enable the static file server.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        file_server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Allow gzip encoding&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        encode gzip zstd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Use TLS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        tls &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;adventure@apalrd.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Log to the usual place&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                output file &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/run/access/access-www-apalrd-net.log&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        roll_keep_for &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        roll_size &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;MiB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                format transform &lt;span style=&#34;color:#e6db74&#34;&gt;`{request&amp;gt;remote_ip} - {request&amp;gt;user_id} [{ts}] &amp;#34;{request&amp;gt;method} {request&amp;gt;uri} {request&amp;gt;proto}&amp;#34; {status} {size} &amp;#34;{request&amp;gt;headers&amp;gt;Referer&amp;gt;[0]}&amp;#34; &amp;#34;{request&amp;gt;headers&amp;gt;User-Agent&amp;gt;[0]}&amp;#34;`&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        time_format &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;02/Jan/2006:15:04:05 -0700&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Global redirects&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apalrd&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;net:80 {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        redir https:&lt;span style=&#34;color:#e6db74&#34;&gt;//&lt;/span&gt;www&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;apalrd&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;net{uri} permanent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apalrd&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;net:443 {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        redir https:&lt;span style=&#34;color:#e6db74&#34;&gt;//&lt;/span&gt;www&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;apalrd&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;net{uri} permanent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        tls &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;adventure@apalrd.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Stats server redirects to Goatcounter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;stats&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;apalrd&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;net {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        reverse_proxy localhost:8081
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        tls &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;adventure@apalrd.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        encode gzip zstd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Refer to the Caddy docs for more information:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# https://caddyserver.com/docs/caddyfile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;caddy-service-override&#34;&gt;Caddy Service Override&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### Editing /etc/systemd/system/caddy.service.d/override.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### Anything between here and the comment below will become the new contents of the file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Service]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add a directory &amp;#39;access&amp;#39; for runtime, systemd will add it to /run and deal with permissions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RuntimeDirectory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;access
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Replace Exec with the /usr/local/bin versions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/usr/&lt;/span&gt;local&lt;span style=&#34;color:#e6db74&#34;&gt;/bin/c&lt;/span&gt;addy run &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;environ &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;config &lt;span style=&#34;color:#e6db74&#34;&gt;/etc/c&lt;/span&gt;addy&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;Caddyfile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecReload&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecReload&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/usr/&lt;/span&gt;local&lt;span style=&#34;color:#e6db74&#34;&gt;/bin/c&lt;/span&gt;addy reload &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;config &lt;span style=&#34;color:#e6db74&#34;&gt;/etc/c&lt;/span&gt;addy&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;Caddyfile &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;force
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### Lines below this comment will be discarded&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I need to reduce the lifetime of these log files so they don&amp;rsquo;t continue to accumulate on the system, since IP addresses are considered personally-identifying information by modern privacy standards, even if the US where I&amp;rsquo;m located doesn&amp;rsquo;t actually have any sort of protections for personal information. The log files need to include the IP address so Goatcounter can feed it into a geo-IP database to guess the country of the viewer, and after that they are discarded. Once the data makes it to the Goatcounter database it&amp;rsquo;s been sufficiently anonymized that it&amp;rsquo;s no longer sensitive.&lt;/p&gt;
&lt;p&gt;I chose to create a directory in /run for caddy, which is surprisingly easy with Systemd. I&amp;rsquo;m always amazed at how much of Linux relies on systemd and how good it is at well really everything it touches. Since /run is a RAM disk on modern Linux systems, I don&amp;rsquo;t have to worry about data encryption at rest, and the backup system will skip over mount points by default so the entire /run disk won&amp;rsquo;t end up in backups. Caddy will prevent the logs from getting over 10MB, and Goatcounter should be watching for changes every few seconds.&lt;/p&gt;
&lt;h1 id=&#34;goatcounter-service&#34;&gt;Goatcounter Service&lt;/h1&gt;
&lt;p&gt;Now I just need a systemd service for Goatcounter itself, plus the import daemon which I made as a template to make my life easier when I end up adding that link shortener someday. Let me tell you, systemd units are wildly powerful. I also took a moment to appreciate the Goatcounter developer&amp;rsquo;s shared hate for Docker.&lt;/p&gt;
&lt;p&gt;Goatcounter main service:
&lt;code&gt;/etc/systemd/system/goatcounter.service&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Goatcounter statistics system
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;network&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;online&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Service]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;www&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;admin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Group&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;www&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/usr/&lt;/span&gt;local&lt;span style=&#34;color:#e6db74&#34;&gt;/bin/go&lt;/span&gt;atcounter serve &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;listen localhost:8081 &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;db sqlite3:&lt;span style=&#34;color:#e6db74&#34;&gt;///var/&lt;/span&gt;apalrd&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;stats&lt;span style=&#34;color:#e6db74&#34;&gt;/db/go&lt;/span&gt;atcounter&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;sqlite3 &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;tls none
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Restart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;always
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Install]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Logging service:
&lt;code&gt;/etc/systemd/system/goatcounter-logs@.service&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Goatcounter statistics system
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;network&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;online&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;target caddy&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Service]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Obviously put in your own API key, you get it from your user account in Goatcounter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Combined log format is Apache style, Common Log Format + Referrer + User-Agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Environment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;GOATCOUNTER_API_KEY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;caddy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Group&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;caddy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/usr/&lt;/span&gt;local&lt;span style=&#34;color:#e6db74&#34;&gt;/bin/go&lt;/span&gt;atcounter &lt;span style=&#34;color:#f92672&#34;&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	import &lt;span style=&#34;color:#f92672&#34;&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;follow &lt;span style=&#34;color:#f92672&#34;&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;combined &lt;span style=&#34;color:#f92672&#34;&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;site&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://stats.apalrd.net&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;exclude &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;path:glob:/assets/*&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;exclude &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;status:404&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;exclude redirect &lt;span style=&#34;color:#f92672&#34;&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;exclude &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;path:glob:/img/*&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;/run/&lt;/span&gt;access&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;access&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;%i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Install]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m storing access totals for each page on the site, plus a breakdown by operating system, browser, and country for the site as a whole. It&amp;rsquo;s free to view at &lt;a href=&#34;https://stats.apalrd.net&#34;&gt;stats.apalrd.net&lt;/a&gt;, so enjoy!&lt;/p&gt;
&lt;h1 id=&#34;web-rebuild-service-and-timer&#34;&gt;Web Rebuild Service and Timer&lt;/h1&gt;
&lt;p&gt;Last step is to make the website periodically check for updates and re-sync. I&amp;rsquo;ve chosen to have this happen daily. I wrote a systemd service file that regenerates the site when started, basically by doing a &lt;code&gt;git pull&lt;/code&gt; followed by a &lt;code&gt;hugo -v&lt;/code&gt;. Of course, to trigger this remotely over SSH I just need to tell systemctl to run this service. How easy!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Rebuild Website Tasks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Service]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;oneshot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run as www-admin which has permissions to this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;www&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;admin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Group&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;www&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WorkingDirectory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/var/&lt;/span&gt;apalrd&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;net&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run git-pull here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;git pull
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Next run Hugo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;hugo &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;v
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Install]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;default&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running &lt;code&gt;systemctl start webrebuild&lt;/code&gt; gives me this beautiful log in &lt;code&gt;journalctl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 git[&lt;span style=&#34;color:#ae81ff&#34;&gt;34589&lt;/span&gt;]: Already up to date&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]: Start building sites &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;…&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]: hugo v0&lt;span style=&#34;color:#ae81ff&#34;&gt;.111.3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;extended linux&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;amd64 BuildDate&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2023&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;03&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;T08:41:31Z VendorInfo&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;debian:0&lt;span style=&#34;color:#ae81ff&#34;&gt;.111.3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]: INFO &lt;span style=&#34;color:#ae81ff&#34;&gt;2023&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/07/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt; syncing static files to &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]:                    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; EN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]: &lt;span style=&#34;color:#f92672&#34;&gt;-------------------+------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]:   Pages            &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;251&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]:   Paginator pages  &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;46&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]:   Non&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;page files   &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;254&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]:   Static files     &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]:   Processed images &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]:   Aliases          &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;62&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]:   Sitemaps         &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]:   Cleaned          &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 hugo[&lt;span style=&#34;color:#ae81ff&#34;&gt;34590&lt;/span&gt;]: Total in &lt;span style=&#34;color:#ae81ff&#34;&gt;771&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Jul &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt; web&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ash1 systemd[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]: webrebuild&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;service: Deactivated successfully&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that the service works, I can add a timer unit to trigger it regularly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Rebuild website daily
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RefuseManualStart&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RefuseManualStop&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Timer]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run 180 seconds after boot for the first time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OnBootSec&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;180&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run at 9am EST / 4am UTC daily&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OnCalendar&lt;span style=&#34;color:#f92672&#34;&gt;=*-*-*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;04&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;00&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Unit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;webrebuild&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Install]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;timers&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;end&#34;&gt;End&lt;/h2&gt;
&lt;p&gt;I hope you enjoyed this overview of how my website is hosted in the background. Sanitized versions of the configs are all posted on my blog if you are looking to replicate this setup. Of course, feel free to reach out to my Discord if you&amp;rsquo;d like ot hang out with like minded people, and as always, I&amp;rsquo;ll see you on the next adventure!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Layer 4 vs Layer 7 Reverse Proxies: Using HAProxy to front Web Services (for IPv4 to v6 Transition)</title>
      <link>https://www.apalrd.net/posts/2023/network_haproxy/</link>
      <pubDate>Thu, 20 Jul 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/network_haproxy/</guid>
      <description>A common challenge in web design and network architecture is grouping multiple web services in a single host, or behind a single IP address. This is especially true with IPv4 due to the scarcity of addresses. The solution to this is a reverse proxy or load balancer. Essentially, this takes connections from clients and dispatches them to the correct server based on the domain name or URL in the request. In this video, I&amp;rsquo;m going to explain what a layer 4 or layer 7 load balancer even is, and setup a layer 4 example using HAProxy.</description>
      <content>&lt;p&gt;A common challenge in web design and network architecture is grouping multiple web services in a single host, or behind a single IP address. This is especially true with IPv4 due to the scarcity of addresses. The solution to this is a reverse proxy or load balancer. Essentially, this takes connections from clients and dispatches them to the correct server based on the domain name or URL in the request. In this video, I&amp;rsquo;m going to explain what a layer 4 or layer 7 load balancer even is, and setup a layer 4 example using HAProxy. So come along on this adventure!&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/#transport-layers-of-http&#34;&gt;Transport Layers of HTTP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/#haproxy-setup&#34;&gt;HAProxy Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/#installing-haproxy&#34;&gt;HAProxy - Install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/#configuring-haproxy&#34;&gt;HAProxy - Configure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/#default-config&#34;&gt;HAProxy - Configure - Default Config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/#http-config---redirect-to-https&#34;&gt;HAProxy - Configure - HTTP Redirect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/#http-config---layer-7-proxy&#34;&gt;HAProxy - Configure - HTTP Layer 7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/#https-config---layer-4-sni-proxy&#34;&gt;HAProxy - Configure - HTTPS Layer 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_haproxy/#logging&#34;&gt;HAProxy - Logging&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;h1 id=&#34;transport-layers-of-http&#34;&gt;Transport Layers of HTTP&lt;/h1&gt;
&lt;p&gt;So to understand load balancers and reverse proxies, let&amp;rsquo;s take a look at what a normal modern web session looks like:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Example: A web session inside a TLS tunnel inside a TCP socket&#34; src=&#34;https://www.apalrd.net/posts/2023/network_haproxy/diagram_1.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Example: A web session inside a TLS tunnel inside a TCP socket&lt;/div&gt;
&lt;p&gt;With HTTP/1.1, the HTTP commands are tunneled inside a TLS session, and the TLS session is itself inside a TCP socket. To setup the connection, the web browser sends out a TCP SYN and the 3-way handshake is done, and once the tunnel is open the client can send the Client Hello message to begin establishing the TLS session. Once that&amp;rsquo;s done, within the TLS session the HTTP commands can be sent and information can be exchanged.&lt;/p&gt;
&lt;p&gt;In this case, TCP is our layer 4 transport protocol, establishing a long-lived tunnel out of layer 3 IP packets. Within the transport is our TLS sesssion and HTTP session, which are generally grouped together as the application layer, or layer 7.&lt;/p&gt;
&lt;p&gt;Our proxy will sit somewhere in this chain and intercept messages so we can modify them or dispatch them to the correct back end server. In short, if we are interrupting the TLS session, we are proxying at layer 7, and if we are passing through the TLS messages unmodified we are proxying at layer 4. Since all of this happens at layer 4 and above, we can also use a proxy to change the layer 3 protocol from IPv4 to IPv6, meaning we can keep our internal network entirely IPv6 as long as the first proxy the client hits supports IPv4.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Example: Layer 4 TCP proxy&#34; src=&#34;https://www.apalrd.net/posts/2023/network_haproxy/diagram_2.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Example: Layer 4 TCP proxy&lt;/div&gt;
&lt;p&gt;So with layer 4, TCP comes in, TCP goes out, and the only thing we can see is the Client Hello before everything is encrypted. Thankfully the Client Hello includes the SNI, or the domain name of the site, but not the full URL. This is just enough information for us to choose a server based on its domain, and let the server handle the TLS side of the transaction.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Example: Layer 7 HTTPS proxy&#34; src=&#34;https://www.apalrd.net/posts/2023/network_haproxy/diagram_3.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Example: Layer 7 HTTPS proxy&lt;/div&gt;
&lt;p&gt;But with a layer 7 proxy we are intercepting the TLS sessions. At a minimum, our layer 7 proxy needs to have the TLS certificate and key so users can authenticate to us. We also have the opportunity to inspect the entire HTTP request, convert from HTTP/1.1 to HTTP/2 or HTTP/3, and possibly connect to the backend server via a separate TLS session or via unencrypted HTTP. Since we can inspect the entire URL in every query, we can redirect different paths to different servers, rewrite paths, rewrite responses, cache things, and basically change whatever we want. Even if we aren&amp;rsquo;t changing or caching anything, we can also use this architecture to move cryptography off of the application servers, helping spread the load around the whole system.&lt;/p&gt;
&lt;p&gt;While either of these could be called a &amp;rsquo;load-balancer&amp;rsquo; or &amp;lsquo;reverse-proxy&amp;rsquo;, a layer 4 proxy would be more likely to be called a load balancer, while a layer 7 proxy would be more likely to be called a reverse proxy.&lt;/p&gt;
&lt;p&gt;In case you&amp;rsquo;re confused on why this is a &amp;lsquo;reverse&amp;rsquo; proxy, a normal or &amp;lsquo;forward&amp;rsquo; proxy would act on the other side, between a group of clients and the internet. This can also be a layer 4 or layer 7 proxy, and is often used to give clients heavily filtered, monitored, or cached access to the internet.&lt;/p&gt;
&lt;h1 id=&#34;haproxy-setup&#34;&gt;HAProxy Setup&lt;/h1&gt;
&lt;p&gt;For my setup, I&amp;rsquo;m using a layer 4 TCP proxy for secure connections and a layer 7 HTTP proxy for insecure connections. I could also just have a blanket redirect in the proxy that tells all HTTP users to go to HTTPS, so I threw in the config for that bit too. My backends are all IPv6, so IPv6 clients can go straight to the web server while IPv4 clients all have to go through the proxy since they are all sharing the same v4 address.&lt;/p&gt;
&lt;h2 id=&#34;installing-haproxy&#34;&gt;Installing HAProxy&lt;/h2&gt;
&lt;p&gt;This one&amp;rsquo;s crazy simple. We just install it from &lt;code&gt;apt&lt;/code&gt;!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install haproxy -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configuring-haproxy&#34;&gt;Configuring HAProxy&lt;/h2&gt;
&lt;p&gt;Feel free to pick and choose the config snippets from the next section as you&amp;rsquo;re building your config. Some of these examples are mutually exclusive, so read the notes carefully! The file is &lt;code&gt;/etc/haproxy/haproxy.cfg&lt;/code&gt; by the way.&lt;/p&gt;
&lt;h3 id=&#34;default-config&#34;&gt;Default Config&lt;/h3&gt;
&lt;p&gt;I left the default config from Debian alone, so here it is in case you&amp;rsquo;re curious. I added all of my config after this.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;#Default global configuration from Debian upstream
global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

#Defaults, also from Debian upstream
defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;http-config---redirect-to-https&#34;&gt;HTTP Config - Redirect to HTTPS&lt;/h3&gt;
&lt;p&gt;This is an HTTP config which redirects everything to HTTPS, so we don&amp;rsquo;t also need to proxy HTTP/1.1 over port 80&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;# Listen on port 80, layer 7 (HTTP)
# Redirect everything to https
# That leaves the client to reconnect properly,
# and means we don&amp;#39;t need to proxy HTTP, just HTTPS
frontend www
        mode http
        bind :80
        http-request redirect scheme https
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;http-config---layer-7-proxy&#34;&gt;HTTP Config - Layer 7 Proxy&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s a version of the HTTP config which actually does proxy port 80, if you want to continue to support non-TLS connections and/or HTTP-01 ACME challenges (Caddy supports TLS-ALPN-01 so it can work over 443 without 80 proxied).&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;# For port 80, we can do layer 7 (HTTP)
# Since it&amp;#39;s insecure, there&amp;#39;s no reason to do layer 7
# since there are no certs or encryption to interrupt
frontend www
        mode http
        bind :80
        # We are building the name of the backend from the &amp;#39;host&amp;#39;
        # field in the request plus the literal &amp;#39;_http&amp;#39;
        # See backends for an example of how to name them
        use_backend %[req.hdr(host),lower,word(1,:)]_http

# Backends for HTTP
backend test1.apalrd.net_http
        mode http
        server test1_http 2601:40e:69:69:0:0:0:feed:80
backend test2.apalrd.net_http
        mode http
        server test2_http 2601:40e:69:69:0:0:0:beef:80
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;https-config---layer-4-sni-proxy&#34;&gt;HTTPS Config - Layer 4 SNI Proxy&lt;/h3&gt;
&lt;p&gt;And of course, the layer 4 SNI proxy for TLS works similarly, but at layer 4 instead of layer 7&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;# For port 443, we want to do a TCP proxy so
# we don&amp;#39;t have to terminate the TLS session. 
# Since we are only doing this for IPv4 clients,
# We don&amp;#39;t want the private keys both here (for v4)
# and on the real server (for v6).
frontend www-tls
        # Layer 4 (TCP) mode
        mode tcp
        # Use TCPlog mode instead of HTTPlog
        option tcplog
        # Listen on TCP 443 (HTTP/1.1 and HTTP/2)
        bind :443

        # Wait for SSL Hello before forwarding
        tcp-request inspect-delay 5s
        tcp-request content accept if { req_ssl_hello_type 1 }

        # Select backends for each server
        # Similar method to above, but using &amp;#39;_tls&amp;#39; on the end
        use_backend %[req_ssl_sni,lower,word(1,:)]_tls

# Backends for TLS servers
backend test1.apalrd.net_tls
        mode tcp
        server test1_tls 2601:40e:69:69:0:0:0:feed:443
backend test2.apalrd.net_tls
        mode tcp
        server test2_tls 2601:40e:69:69:0:0:0:beef:443
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;logging&#34;&gt;Logging&lt;/h2&gt;
&lt;p&gt;HAProxy uses rsyslog by default to log, so we won&amp;rsquo;t get a log file unless we install that package too. So, let&amp;rsquo;s do that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install rsyslog -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now rsyslog
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you should find an &lt;code&gt;/var/log/haproxy.log&lt;/code&gt; file for you to explore! Be aware that it may fill up and you should probably take care of that.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>The Power of Zero-Trust Architecture: Building a Secure Internal Network with Nebula</title>
      <link>https://www.apalrd.net/posts/2023/network_nebula/</link>
      <pubDate>Thu, 13 Jul 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/network_nebula/</guid>
      <description>Imagine if we could establish a level of trust that in our network, we can verify with certainty that a computer really is who it says it is. By bringing mutual authentication and trust into networking, we can better make security decisions on when connections should be allowed. This can enable our services to talk to each other securely over the global internet, and reduce the dependence on a a trusted perimeter.</description>
      <content>&lt;p&gt;Imagine if we could establish a level of trust that in our network, we can verify with certainty that a computer really is who it says it is. By bringing mutual authentication and trust into networking, we can better make security decisions on when connections should be allowed. This can enable our services to talk to each other securely over the global internet, and reduce the dependence on a a trusted perimeter. This mututal trust is the foundation of a zero-trust security model. In this video, I&amp;rsquo;m going to walk through the basics of zero-trust security, the choices I&amp;rsquo;ve made to implement it in my own network. One of those choies is Nebula, an open-source zero trust overlay network designed for highly scalable distributed networks. Come along on this adventure!&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#zero-trust-architecture&#34;&gt;Zero Trust Architecutre&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#my-zero-trust-setup&#34;&gt;My Zero Trust Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#what-is-nebula&#34;&gt;What is Nebula?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#standing-up-a-network&#34;&gt;Standing up a Network&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#mapping-out-the-network&#34;&gt;Mapping Out the Network&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#install-nebula&#34;&gt;Install Nebula&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#setup-the-certificate-authority&#34;&gt;Setup the Certificate Authority&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#create-and-sign-node-certificates&#34;&gt;Create and Sign Node Certificates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#setup-the-lighthouse&#34;&gt;Setup the Lighthouse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#setup-the-client-on-linux&#34;&gt;Setup the Client on Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#relaying&#34;&gt;Relaying&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#security&#34;&gt;Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_nebula/#links-and-conclusion&#34;&gt;Links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/aImSCypCsuw&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/network_nebula/thumbnail.png&#34;&gt;&lt;/a&gt;
This absolutely beautiful image comes from NASA and the James Webb Space Telescope. Go Science!&lt;/p&gt;
&lt;h1 id=&#34;zero-trust-architecture&#34;&gt;Zero Trust Architecture&lt;/h1&gt;
&lt;p&gt;If you&amp;rsquo;re into tech buzz words, you might have heard of a &amp;lsquo;zero trust architecture&amp;rsquo;. A lot of companies are certainly pushing  products in the space which take different approaches, but to understand it let&amp;rsquo;s first look at an example network that is certainly not zero-trust.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Example: A standard firewall router, with a bunch of services and clients in the network&#34; src=&#34;https://www.apalrd.net/posts/2023/network_nebula/diagram_1.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Example: A standard firewall router&lt;/div&gt;
&lt;p&gt;In this example, we consider the firewall to be our security plane. Users inside the network get access directly to services. In a lot of organizations, they are even running without encryption on internal services like this! I made a video on fixing that internal TLS cert issue, card up there. In general, we trust that devices belong on the network becuase they are within the security plane behind the firewall, but we probably also have some token of security like basic passwords to access systems.&lt;/p&gt;
&lt;p&gt;But what happens when an attacker is able to compromise a single laptop? Now they can hunt every single service we have running, bang at SSH to see if you actually changed the password on your Raspberry Pi&amp;rsquo;s, see all of your unencrypted security cameras which you thought were local only, etc. And all from one compromised machine! If only there was a way we could limit the blast radius of a single machine down to just the services it actually needs to talk to, hopefully reducing the chance that an attacker is able to spread laterally through our network.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Example: Siloing services and clients using subnets / VLANs&#34; src=&#34;https://www.apalrd.net/posts/2023/network_nebula/diagram_2.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Example: Siloing services and clients using subnets&lt;/div&gt;
&lt;p&gt;If we want better network security, we start to implement more subnets and VLANs. We are relying almost entirely on the firewall to filter what ports users should have access to, so we might need a whole lot of subnets to group everything by membership. This forces a ton of traffic to go through the firewall if we want really fine-grained firewall rules, which means we need a beefy firewall to handle all of the traffic across our network in one place.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Example: Some clients remote, outside of the firewall, and a server in the cloud is also remote&#34; src=&#34;https://www.apalrd.net/posts/2023/network_nebula/diagram_3.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Example: Some clients via a VPN&lt;/div&gt;
&lt;p&gt;When we start asking for remote access, this gets even more complicated. We start opening holes in our security plane to allow remote users in, via VPN tunnels. Usually this is secure, but it expands our security wall even further. If we are using cloud services, we might be spinning up new cloud instances of routers just to tunnel traffic via a VPN, so everything is within our secure perimeter.&lt;/p&gt;
&lt;p&gt;As an extreme example, we can connect every single device directly to the firewall, and force all traffic to go through it so we can filter it all. We might be able to do this on high end switches, but it&amp;rsquo;s an expensive proposition on a network of really any scale.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Example: Each node has a tiny firewall, and they are all connected together&#34; src=&#34;https://www.apalrd.net/posts/2023/network_nebula/diagram_4.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Example: Each node has a tiny firewall&lt;/div&gt;
&lt;p&gt;So zero-trust brings a simple distributed solution. We get rid of the central firewall, and move it to every single node. Okay, maybe we don&amp;rsquo;t get rid of it entirely, but we stop asuming that the firewall is a perfect line of defense. Now, the key tenet of zero trust is that we mutually authenticate both sides of every single connection before exchanging any data. Since we&amp;rsquo;ve mutually authenticated each other, we can rely on this strong cryptographically verified identity to know what should have access to what, without bringing in physical network changes.&lt;/p&gt;
&lt;h2 id=&#34;my-zero-trust-setup&#34;&gt;My Zero Trust Setup&lt;/h2&gt;
&lt;p&gt;Now, all of this sounds fantastic in concept. But, by moving the firewall to every node, we&amp;rsquo;ve created a bit of a configuration management hell for ourselves. How do we know what to trust? Who should be able to access what services?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Example: An overview of my network architecture&#34; src=&#34;https://www.apalrd.net/posts/2023/network_nebula/diagram_5.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;An overview of my network architecture&lt;/div&gt;
&lt;p&gt;This is the key question solved by zero-trust solutions, and each vendor or open source project will have a different answer. Here&amp;rsquo;s the solution I&amp;rsquo;m working with for my network currently:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For services to talk to other services, and for admin access to management UIs that aren&amp;rsquo;t for end-users, I&amp;rsquo;m using Nebula. This provides an overlay network with secure, authenticated access to anything at layer 3. That&amp;rsquo;s covered in this video.&lt;/li&gt;
&lt;li&gt;For services which users need to access, I&amp;rsquo;m going to deploy mutual TLS. This will authenticate users devices via hardware certificates. This gives me confidence that a user is logging in from their own device or security key without needing to install any software on their device. I&amp;rsquo;m actually already using this, but I&amp;rsquo;m still working on a good workflow for enrolling users so this is a topic for a future video.&lt;/li&gt;
&lt;li&gt;Of course, there are some cases where neither of these are a good choice, so I can continue to do segmentation in the traditional sense in parallel to the more modern approaches. Hopefully I can phase them out over time. In particular, I&amp;rsquo;m going to keep zero trust out of my security camera and home automation devices, as they are already struggling to implement IP at all. I&amp;rsquo;m also not going to use zero trust in the Ceph storage network, since it can&amp;rsquo;t afford to take the performance hit.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&amp;rsquo;m not going to setup a whole-network remote access VPN such as Wireguard, Tailscale, or OpenVPN. Implemented properly, a zero trust solution can remove the need for site to site VPNs between homelabs, datacenters, and cloud providers and also obsolete SD-WAN solutions. I will still use these things to give me unfiltered internet access on the go or avoid geo restrictions, but not as a security mechanism.&lt;/p&gt;
&lt;h2 id=&#34;what-is-nebula&#34;&gt;What is Nebula?&lt;/h2&gt;
&lt;p&gt;So when you think of a VPN, you probably think of a point to point connection, between you and a cloud provider, you and your home network, or office, or something like that. Nebula creates individual VPN tunnels directly between nodes on demand, allowing anyone participating in your private mesh to access services. To properly deploy it, you don&amp;rsquo;t just open up your whole network to Nebula and bring back the perimeter firewall model, you install it individually on all of the hosts you want to communicate with.&lt;/p&gt;
&lt;p&gt;Once everyone has Nebula installed, they don&amp;rsquo;t need any port forwarding to work. The Nebula transport works over both IPv4 and IPv6. Clients start with the public address or domain name of one or more Lighthouse nodes, and from the lighthouse they can discover all of the possible addresses of all other nodes, to establish secure tunnels on demand.&lt;/p&gt;
&lt;p&gt;Nebula also integrates a role-based firewall at every single node, where we can filter packets coming in and out of the node based on the group membership of the other node in the tunnel. Since the other nodes identity and group membership is cryptographically verified, no central source of authentication truth is needed, and the network can function without trusting anything but the root certificate.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Example Network used in this tutorial&#34; src=&#34;https://www.apalrd.net/posts/2023/network_nebula/diagram_6.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Example Network used in this tutorial&lt;/div&gt;
&lt;h1 id=&#34;standing-up-a-network&#34;&gt;Standing Up a Network&lt;/h1&gt;
&lt;p&gt;Finally understand what the big deal is with zero trust and Nebula? Lets&amp;rsquo;s stand up a network! For this example, I&amp;rsquo;m going to use my laptop, a Proxmox server, and a lighthouse. The lighthouse is the only node that needs a public IP address or port forward, and I&amp;rsquo;m going to set it up in a cheap Nanode instance on Linode. Why Linode? It&amp;rsquo;s what I&amp;rsquo;m already using. Hetzner is cheaper.&lt;/p&gt;
&lt;h2 id=&#34;mapping-out-the-network&#34;&gt;Mapping Out the Network&lt;/h2&gt;
&lt;p&gt;Before we start signing certs, we need to give each node a fully qualified domain name and IP address on the overlay. Nebula currently only supports IPv4 within the overlay, so we&amp;rsquo;re going to set aside a nice large space for all of our hosts to get randomly assigned addresses. Since the IPv4 world is full of bad practices, I&amp;rsquo;ve decided to go ahead and continue that and chose the perfect prefix for my network: 42. As you know, it&amp;rsquo;s the answer to life, the universe, and everything, so hopefully nobody minds that my private network is 42.69/16. For individual node addresses I&amp;rsquo;m using a random number generator in most cases.&lt;/p&gt;
&lt;p&gt;(In case you are actually thinking about using IPv4 squat space, &lt;a href=&#34;https://www.arin.net/blog/2015/11/23/to-squat-or-not-to-squat/&#34;&gt;you might want to read this article on the dangers of squat space&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Unlike normal IPv4, each node is a /32 and the network is fully routed, so there are no concerns about subnetting it down and losing addresses everywhere to the network and broadcast and gateway. We truly have 65k host addresses.&lt;/p&gt;
&lt;p&gt;I also decided to place all of my nodes under the domain &lt;code&gt;neb.apalrd.net&lt;/code&gt;, which lets me delegate the Nebula network as an authoritative name server for that subdomain. It also makes it clear that addresses are within the nebula network.&lt;/p&gt;
&lt;h2 id=&#34;install-nebula&#34;&gt;Install Nebula&lt;/h2&gt;
&lt;p&gt;First, we need to get the Nebula binaries for our operating system. It&amp;rsquo;s the same process for every OS, so you&amp;rsquo;ll need to do this on the laptop, server, lightouse, all of them.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy the link from the lates release on Github: https://github.com/slackhq/nebula/releases/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://github.com/slackhq/nebula/releases/download/v1.7.2/nebula-linux-amd64.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Untar it into /usr/local/bin so it&amp;#39;s accessible (it&amp;#39;s just two binaries, nebula and nebula-cert)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar -xzf nebula-linux-amd64.tar.gz -C /usr/local/bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re in an LXC Container on Proxmox, you additionally need permissions to create your own tun devices, and need a privilaged LXC container. Add this to the container config, which will be &lt;code&gt;/etc/pve/lxc/&amp;lt;vmid&amp;gt;.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.cgroup2.devices.allow&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;c 10:200 rwm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lxc.mount.entry&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/dev/net dev/net none bind,create=dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re able to get permissions right on an unprivilaged container to use tun devices, let me know how and I can update the guide. I&amp;rsquo;ve already spent a long time on this lol&lt;/p&gt;
&lt;h2 id=&#34;setup-the-certificate-authority&#34;&gt;Setup the Certificate Authority&lt;/h2&gt;
&lt;p&gt;You can do this on any machine, even one that isn&amp;rsquo;t part of the Nebula network. You just need a way to copy the certs out later. They are really tiny, copy and paste works fine. You should NOT do this on the lighthouse, since that&amp;rsquo;s the most likely system to be compromised. I&amp;rsquo;m doing it on my laptop.&lt;/p&gt;
&lt;p&gt;This one is way easier than the x509 stuff we did in OpenSSL! Do this on whatever node you want to keep your key on, it can be any node.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Name it whatever you want&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nebula-cert ca --name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ApalrdsAdventures2023&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now keep &lt;code&gt;ca.key&lt;/code&gt; very private, and come up with a way to distribute &lt;code&gt;ca.crt&lt;/code&gt; to all nodes in the cluster. I use &lt;code&gt;cat&lt;/code&gt; and copy and paste the contents. Ansible would also probably make a good choice for this. Also remember that the CA expires after &lt;code&gt;8760h0m0s&lt;/code&gt;, but you can override this by setting the &lt;code&gt;-duration &amp;lt;time&amp;gt;&lt;/code&gt; flag with hours/mins/secs. Client certs cannot last loner than the CA cert.&lt;/p&gt;
&lt;h2 id=&#34;create-and-sign-node-certificates&#34;&gt;Create and Sign Node Certificates&lt;/h2&gt;
&lt;p&gt;In this example, I&amp;rsquo;m creating and signing a cert for my laptop, my Proxmox VE cluster, and the lighthouse.&lt;/p&gt;
&lt;p&gt;When you sign a Nebula cert, you are including group membership, hostname, and address in the cert. All of this is verified by other nodes, and is used later by DNS and the firewall, so get it right!&lt;/p&gt;
&lt;p&gt;So anyway here&amp;rsquo;s my rapid fire commands to generate the certs I needed (obviously change this for your own network)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nebula-cert sign -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;lighthouse1.neb.apalrd.net&amp;#34;&lt;/span&gt; -ip &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;42.69.0.1/16&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nebula-cert sign -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;spaceship3.neb.apalrd.net&amp;#34;&lt;/span&gt; -ip &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;42.69.73.46/16&amp;#34;&lt;/span&gt; --groups &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user,admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nebula-cert sign -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pvering1.neb.apalrd.net&amp;#34;&lt;/span&gt; -ip &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;42.69.212.1/16&amp;#34;&lt;/span&gt; --groups &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hypervisor,dev&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nebula-cert sign -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pvering2.neb.apalrd.net&amp;#34;&lt;/span&gt; -ip &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;42.69.212.2/16&amp;#34;&lt;/span&gt; --groups &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hypervisor,dev&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nebula-cert sign -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pvering3.neb.apalrd.net&amp;#34;&lt;/span&gt; -ip &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;42.69.212.3/16&amp;#34;&lt;/span&gt; --groups &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hypervisor,dev&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nebula-cert sign -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pvering4.neb.apalrd.net&amp;#34;&lt;/span&gt; -ip &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;42.69.212.4/16&amp;#34;&lt;/span&gt; --groups &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hypervisor,dev&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nebula-cert sign -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pvering5.neb.apalrd.net&amp;#34;&lt;/span&gt; -ip &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;42.69.212.5/16&amp;#34;&lt;/span&gt; --groups &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hypervisor,dev&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the future once the network is stood up, it&amp;rsquo;s more secure to generate the private key on the device and transfer the public key to the certificate authority to sign it. For now, I&amp;rsquo;m generating them all and distributing them during the initial setup, but will switch to the more secure process once I&amp;rsquo;ve gotten the basics functional.&lt;/p&gt;
&lt;p&gt;Also be very aware that your root key expires in a year, and your node keys by default expire a second before the root! So an automated process for rotating certs would be good. Something like Ansible, rotate them in your periodic update script or whatever. You can set the duration to anything from zero to the expiration of the CA&amp;rsquo;s cert using the &lt;code&gt;-duration&lt;/code&gt; flag similar to above. This post is already too long to set that up too.&lt;/p&gt;
&lt;p&gt;Anyway, the on-device keying process would be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Generate key on device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nebula-cert keygen -out-key laptop.key -out-pub laptop.pub
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Transfer laptop.pub to CA to be signed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sign cert on CA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nebula-cert sign -in-pub laptop.pub -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;spaceship3.neb.apalrd.net&amp;#34;&lt;/span&gt; -ip &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;42.69.73.46/16&amp;#34;&lt;/span&gt; --groups &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user,admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Transfer new crt back to device which generated the key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;setup-the-lighthouse&#34;&gt;Setup the Lighthouse&lt;/h2&gt;
&lt;p&gt;For this example, I&amp;rsquo;m running it on a Debian 12-based Nanode at Linode, with a public IPv4 and IPv6, at the name &lt;code&gt;ls1.apalrd.net&lt;/code&gt; in DNS (both A and quad-A records), plus an NS record at &lt;code&gt;neb.apalrd.net&lt;/code&gt; which points back to the lighthouse so my Nebula network resolves via public DNS (how fun!). All of these will be gone by the time the video comes out.&lt;/p&gt;
&lt;p&gt;Since we want DNS to work, you might need to disable systemd-resolved stub listener (which would have taken port 53) before we setup the lighthouse, and here&amp;rsquo;s how to do that on Debian. On some systems it might already be disabled, so if you get any errors you can safely ignore them here.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Write out a conf file change for resolved&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo DNSStubListener&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no &amp;gt;&amp;gt; /etc/systemd/resolved.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Restart service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl restart systemd-resolved
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For this node, we need the binaries, crt and key, the ca.crt (but NOT key), a simple lighthouse config, and a systemd service. Rename the crt and key to &lt;code&gt;host.crt&lt;/code&gt; and &lt;code&gt;host.key&lt;/code&gt;, and put them along with &lt;code&gt;ca.crt&lt;/code&gt; in &lt;code&gt;/etc/nebula&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the config (&lt;code&gt;/etc/nebula/config.yaml&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# PKI paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;pki&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;ca&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/nebula/ca.crt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;cert&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/nebula/host.crt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;key&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/nebula/host.key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Port settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;listen&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Default for this key is 0.0.0.0 which is v4-only and stupid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;[::]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;4242&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# No static hosts for lighthouses&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;static_host_map&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Lighthouse settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lighthouse&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;am_lighthouse&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Enable serving DNS to anyone (Even our external IP)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;serve_dns&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;dns&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Default for this key is 0.0.0.0 which is v4-only and stupid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;[::]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;53&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Firewall settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;firewall&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;outbound&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow all outbound traffic from this node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;inbound&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow icmp between any nebula hosts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;icmp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow DNS incoming since we are serving DNS at this lighthouse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;53&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;udp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the systemd service (&lt;code&gt;/etc/systemd/system/nebula.service&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Description&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Nebula overlay networking tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Wants&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;basic.target network-online.target nss-lookup.target time-sync.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;After&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;basic.target network.target network-online.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Before&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;sshd.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;SyslogIdentifier&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;nebula&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ExecReload&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/bin/kill -HUP $MAINPID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ExecStart&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/usr/local/bin/nebula -config /etc/nebula/config.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Restart&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WantedBy&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;multi-user.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, the commands to start it up (assuming you copied the cert/config files into &lt;code&gt;/etc/nebula&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Reload the daemon files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Start and enable the service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now nebula
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;setup-the-client-on-linux&#34;&gt;Setup the Client on Linux&lt;/h2&gt;
&lt;p&gt;In this example, I&amp;rsquo;m using a Proxmox VE 8.0 system. Again, need to copy our &lt;code&gt;host.crt&lt;/code&gt;, &lt;code&gt;host.key&lt;/code&gt;, and &lt;code&gt;ca.crt&lt;/code&gt; to &lt;code&gt;/etc/nebula&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The config for this node (&lt;code&gt;/etc/nebula/config.yml&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# PKI paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;pki&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;ca&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/nebula/ca.crt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;cert&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/nebula/host.crt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;key&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/nebula/host.key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Need a static host map, using the DNS name of the lighthouse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;static_host_map&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Put all of your lighthouses here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#39;42.69.0.1&amp;#39;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;lighthouse1.palnet.net:4242&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#This is completely undocumented&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#static_map is how to interpret static_host_map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#It defaults to ip4, trying to connect to the lighthouse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#using only ipv4. This sorta-kinda makes sense since the node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#knows its own public v6 already but not its public v4 (Via NAT)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#so connecting to the lighthouse via v4 lets it learn that&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#For ipv6-only hosts, change to `ip6` instead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;static_map&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;network&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ip4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Lighthouse config for clients&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lighthouse&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;hosts&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;42.69.0.1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Listen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;listen&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Default for this key is 0.0.0.0 which is v4-only and stupid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;[::]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Port of 0 means randomly choose, usually good for clients&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Want to set to 4242 for relays and lighthouses&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Firewall settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;firewall&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;outbound&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow all outbound traffic from this node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;inbound&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow icmp between any nebula hosts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;icmp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the Systemd service, I used the same one as the lighthouse, so the same file / commands apply here.&lt;/p&gt;
&lt;p&gt;If you want to put the keys in the config file directly instead of on-disk (might be easier for laptops or something idk) you can do it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;pki&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;ca&lt;/span&gt;: |&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    -----BEGIN NEBULA CERTIFICATE-----
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    CkgKFlRoZSBPbmUtSG91ciBOZWJ1bGEgQ0Eo/pL7jAYwjq/7jAY6IDIi7yqkRV9F
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    1+tozxvnHCmuuuwdArt7YbMMdCR4AYm/QAESQHBitbcetbJ06RQckqGi+hXJXd/U
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    TXKEul4TxP4Qxmd7g+cHDE6oYZhRwup+1xg/Sv9bMg2E2/LNXKV3rNf1Yw8=
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    -----END NEBULA CERTIFICATE-----&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you have multiple root certificates, you just add them together in one file and it will trust them all. If you have automation on your servers, it would be a good idea to rekey the root certificate periodically, and this can be used to keep old certs valid during the transition.&lt;/p&gt;
&lt;h2 id=&#34;relaying&#34;&gt;Relaying&lt;/h2&gt;
&lt;p&gt;Now this all works well, but what if my laptop roams to some public hotspot without IPv6? My servers only have IPv6, so they can&amp;rsquo;t peer with my laptop. The lighthouse can, since it has both v4 and v6, but that doesn&amp;rsquo;t help. So let&amp;rsquo;s go back to the configs for the lighthouse and server and enable peers of the server to relay through the lighthouse.&lt;/p&gt;
&lt;p&gt;When relaying, the &lt;em&gt;destination&lt;/em&gt; node must specify in its configuration which nodes are allowed to relay on its behalf, and the clients will use the list of allowed relays for a destination to try and connect if they are unable to connect directly. So if we are getting around NAT traversal that&amp;rsquo;s only a problem in one direction, or only care about sessions established from one side, we don&amp;rsquo;t need to add the relay to every single file. It&amp;rsquo;s still easy enough to add to everyone&amp;rsquo;s config.&lt;/p&gt;
&lt;p&gt;We also need to specify in the node configuration if the node is allowed to be a relay, but relays don&amp;rsquo;t actually care who they are relaying for, just that they are allowed to relay. So, the lighthouse is going to be my relay and my Proxmox systems (which are v6-only) are going to get the lighthouse added as an available relay. If you have troublesome nodes behind many layers of NAT the setup for them would be similar.&lt;/p&gt;
&lt;p&gt;Change to the lighthouse config (add this to the end):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#I can also be a relay&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;relay&lt;/span&gt;: 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;am_relay&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Change to the Proxmox server config (again add to the end):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#I can use the lighthouse as a relay&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;relay&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;relays&lt;/span&gt;: 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   - &lt;span style=&#34;color:#ae81ff&#34;&gt;42.69.0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;am_relay&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;use_relays&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, the laptop can connect happily to the server, via the lighthouse.&lt;/p&gt;
&lt;h2 id=&#34;security&#34;&gt;Security&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s see if we can understand how amazing the group-based distributed firewall is, let&amp;rsquo;s try a few examples. All of these need to go under the &lt;code&gt;firweall.inbound&lt;/code&gt; section as one list, don&amp;rsquo;t add a bunch of firewall sections to one file.&lt;/p&gt;
&lt;h3 id=&#34;allow-anyone-to-access-web-server&#34;&gt;Allow Anyone to access Web Server&lt;/h3&gt;
&lt;p&gt;In this case, anyone can access port 443, so we are only using Nebula for secure tunneling and relying on the server for user authentication. Also useful for services that are network-wide, like DNS. In this case, we use the &lt;code&gt;host&lt;/code&gt; field and it&amp;rsquo;s special value &lt;code&gt;any&lt;/code&gt;. If we want to allow HTTP/3 (QUIC), we can set &lt;code&gt;proto&lt;/code&gt; to &lt;code&gt;any&lt;/code&gt; instead of &lt;code&gt;tcp&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Firewall settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;firewall&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;inbound&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow anyone to web server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;allow-admins-to-web-ui&#34;&gt;Allow Admins to Web UI&lt;/h3&gt;
&lt;p&gt;Pretty basic rule, server-side we specify the port and groups which can access that port. In this case, Proxmox only does HTTP/1.1, so it&amp;rsquo;s TCP only.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Firewall settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;firewall&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;inbound&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow admins to the web UI of Proxmox systems&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8006&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;admin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;allow-admins-or-breakglass-to-web-ui&#34;&gt;Allow Admins OR Breakglass to Web UI&lt;/h3&gt;
&lt;p&gt;When we want to allow members of EITHER group, we write the rule twice. So, this would be the new rule:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Firewall settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;firewall&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;inbound&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow admins to the web UI of Proxmox systems&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8006&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;admin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow breakglass to the web UI of Proxmox systems&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8006&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;breakglass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;allow-admins-from-us-region-to-web-ui&#34;&gt;Allow Admins from US Region to Web UI&lt;/h3&gt;
&lt;p&gt;When we want members to have BOTH groups, we write the groups as a yaml list. So, the rule:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Firewall settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;firewall&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;inbound&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow admins from the us region to the web UI of Proxmox systems&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8006&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;groups&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;admin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;region-us&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;allow-a-port-range&#34;&gt;Allow a Port Range&lt;/h3&gt;
&lt;p&gt;Similar to the single-port, we can specify a range of ports.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Firewall settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;firewall&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;inbound&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Allow admins to the VNC port range&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5900-5999&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;proto&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;admin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;links-and-conclusion&#34;&gt;Links and Conclusion&lt;/h1&gt;
&lt;p&gt;Here&amp;rsquo;s some links which might help you if you need more reference information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/slackhq/nebula&#34;&gt;Github Page for Nebula&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nebula.defined.net/docs/&#34;&gt;Documentation for Nebula&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Using Proxmox METRICS In Your Homelab</title>
      <link>https://www.apalrd.net/posts/2023/pve_influx/</link>
      <pubDate>Fri, 07 Jul 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/pve_influx/</guid>
      <description>As an engineer, I LOVE looking at DATA! So today, I&amp;rsquo;m setting up my Proxmox system to push data to InfluxDB, where I can view it using Grafana. With this setup, I can keep track of how many resources all of my homelab services are using, which really helps when trying to size VMs, hosts, containers, etc.
Contents Video Install InfluxDB 2.0 Install Grafana Example Dashboard Using TLS Video Install InfluxDB 2.</description>
      <content>&lt;p&gt;As an engineer, I LOVE looking at DATA! So today, I&amp;rsquo;m setting up my Proxmox system to push data to InfluxDB, where I can view it using Grafana. With this setup, I can keep track of how many resources all of my homelab services are using, which really helps when trying to size VMs, hosts, containers, etc.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/pve_influx/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/pve_influx/#install-influxdb-20&#34;&gt;Install InfluxDB 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/pve_influx/#install-grafana&#34;&gt;Install Grafana&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/pve_influx/#example-dashboard&#34;&gt;Example Dashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/pve_influx/#using-tls&#34;&gt;Using TLS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/-RCE1dQUnEQ&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/pve_influx/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;install-influxdb-20&#34;&gt;Install InfluxDB 2.0&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.influxdata.com/influxdb/v2.7/install/?t=Linux#install-influxdb-as-a-service-with-systemd&#34;&gt;See here&lt;/a&gt; for the basic instructions and updated download links. We don&amp;rsquo;t have sudo, so here&amp;rsquo;s a rewriting of it without sudo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# We need a few things for this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install gpg apt-transport-https -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Load GPG fingerprint and debian repo from Influx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# influxdata-archive_compat.key GPG fingerprint:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#     9D53 9D90 D332 8DC7 D6C8 D3B9 D8FF 8E1F 7DF8 B07E&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget -q https://repos.influxdata.com/influxdata-archive_compat.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Verify integrity of key download&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;393e8779c89ac8d958f81f942f9ad7fb82a25e133faddaf92e15b16e6ac9ce4c influxdata-archive_compat.key&amp;#39;&lt;/span&gt; | sha256sum -c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Dearmor key into trusted.gpg.d&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat influxdata-archive_compat.key | gpg --dearmor &amp;gt; /etc/apt/trusted.gpg.d/influxdata-archive_compat.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add repo to influxdata.list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive_compat.gpg] https://repos.influxdata.com/debian stable main&amp;#39;&lt;/span&gt; &amp;gt; /etc/apt/sources.list.d/influxdata.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Actually apt update and install (or update)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install influxdb2 -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Start the servyce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now influxdb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want to check it, run &lt;code&gt;systemctl status influxdb&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now login to the host at port 8086 and initialize, setting the admin password here&lt;/p&gt;
&lt;h2 id=&#34;install-grafana&#34;&gt;Install Grafana&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://grafana.com/docs/grafana/latest/setup-grafana/installation/debian/&#34;&gt;See Here&lt;/a&gt; for the basic instructions from Grafana&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install the signing key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add repository to grafana.list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main&amp;#34;&lt;/span&gt; &amp;gt; /etc/apt/sources.list.d/grafana.list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#apt update and install (or update)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install grafana -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Start the server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now grafana-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now login at port 3000 with &lt;code&gt;admin/admin&lt;/code&gt; and change the password&lt;/p&gt;
&lt;h2 id=&#34;example-dashboard&#34;&gt;Example Dashboard&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://grafana.com/grafana/dashboards/15356-proxmox-flux/&#34;&gt;I used this dashboard for my example&lt;/a&gt;, but I&amp;rsquo;d love to see any customizations or dashboards you make!&lt;/p&gt;
&lt;h2 id=&#34;using-tls&#34;&gt;Using TLS&lt;/h2&gt;
&lt;p&gt;Since it&amp;rsquo;s a good idea to use TLS certificates but both InfluxDB and Grafana don&amp;rsquo;t automatically configure it and don&amp;rsquo;t generate self-signed certificates, it&amp;rsquo;s a bit of .. fun to get that setup. Here&amp;rsquo;s the guides from both Influx and Grafana on setting up their software with TLS certificates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.influxdata.com/influxdb/v2.0/security/enable-tls/&#34;&gt;InfluxDB - Enable TLS Encryption&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://grafana.com/docs/grafana/latest/setup-grafana/set-up-https/&#34;&gt;Grafana - Set Up HTTPS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Self-Hosted TRUST with your own Certificate Authority!</title>
      <link>https://www.apalrd.net/posts/2023/network_acme/</link>
      <pubDate>Wed, 14 Jun 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/network_acme/</guid>
      <description>TRUST. It&amp;rsquo;s what certificates are all about. How do we know that we can trust a server? We verify that the server has a certificate, and that the certificate is signed by someone we trust. That can be a well-known third party like Let&amp;rsquo;s Encrypt, or our own certificate authority. In this video, I&amp;rsquo;m going to cover the basics of setting up a root private key and signing certificates using OpenSSL, and running a certificate authority server.</description>
      <content>&lt;p&gt;TRUST. It&amp;rsquo;s what certificates are all about. How do we know that we can trust a server? We verify that the server has a certificate, and that the certificate is signed by someone we trust. That can be a well-known third party like Let&amp;rsquo;s Encrypt, or our own certificate authority. In this video, I&amp;rsquo;m going to cover the basics of setting up a root private key and signing certificates using OpenSSL, and running a certificate authority server. As a bonus, I&amp;rsquo;m using a Yubikey to store the certiicate authorities private keys, so they can&amp;rsquo;t be compromised without stealing the physical dongle (they CAN however be used to generate leaf certificates if the certificate authority is compromised). So follow along for a fun journey into the basics of setting up your public key infrastructure!&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#a-bit-about-pki&#34;&gt;A Bit About PKI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#certificate-authority-in-openssl&#34;&gt;Certificate Authority in OpenSSL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#setup-the-openssl-ca-config&#34;&gt;OpenSSL - Setup the OpenSSL CA Config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#generate-root-certificates&#34;&gt;OpenSSL - Generate Root Certificate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#generate-intermediate-certificate&#34;&gt;OpenSSL - Generate Intermediate Certificate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#add-intermediate-key-to-yubikey&#34;&gt;OpenSSL - Add Intermediate Key to Yubikey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#install-smallstep&#34;&gt;Install Smallstep&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#setup-debian&#34;&gt;Step - Setup Debian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#install-smallstep-cli&#34;&gt;Step - Install Smallstep CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#build-step-ca-from-source&#34;&gt;Step - Build Step-CA from source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#setup-step-ca&#34;&gt;Step - Setup Step-CA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#add-systemd-service&#34;&gt;Step - Add SystemD Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#enable-acme-challenges&#34;&gt;Step - Enable ACME Challenges&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#using-your-ca&#34;&gt;Using your CA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#trust-your-root&#34;&gt;Using your CA - Trust your Root&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#using-your-ca-in-caddy&#34;&gt;Using your CA - In Caddy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_acme/#references&#34;&gt;References&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/BKCj6A4CHV4&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/network_acme/thumbnail.webp&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;a-bit-about-pki&#34;&gt;A Bit About PKI&lt;/h1&gt;
&lt;p&gt;Public key encryption provides a secure method of transmitting data over insecure networks. It allows for secure communication by using a pair of keys: a public key for encryption and a private key for decryption. TLS (Transport Layer Security) certificates, which are based on public key encryption, ensure the authenticity and integrity of data exchanged between a server and a client. They provide trust and verification, protecting against unauthorized access, data tampering, and eavesdropping, thus establishing secure and encrypted connections.&lt;/p&gt;
&lt;p&gt;2-layer vs 3-layer CA&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2-layer
&lt;ol&gt;
&lt;li&gt;Root CA public trusted by users, private used to sign servers&lt;/li&gt;
&lt;li&gt;Leaf CA generated via ACME ~daily from servers&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;3-layer
&lt;ol&gt;
&lt;li&gt;Root CA public trusted by users, private kept entirely offline&lt;/li&gt;
&lt;li&gt;Intermediate CA public unused, private used to sign servers&lt;/li&gt;
&lt;li&gt;Leaf CA generated via ACME ~daily from servers&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Advantages to 2-layer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simple to setup&lt;/li&gt;
&lt;li&gt;Single private key can be kept in multiple places (backups, HSMs, &amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Advantages of 3-layer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Root CA can issue a CRL which can revoke intermediate certificates (although we will not do that in this tutorial!)&lt;/li&gt;
&lt;li&gt;Intermediate CA can be issued for less time than root, so you can manually renew intermediate CA periodically so if it&amp;rsquo;s lost the time for exposure isn&amp;rsquo;t as high&lt;/li&gt;
&lt;li&gt;Root CA private key can be kept entirely offline, and reissue intermediate CA certs without keeping the private key in multiple palces&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will be setting up a 3-layer CA where the root keys are generated by OpenSSL and kept entirely offline (how you do that is up to you, this tutorial is already long enough) and the intermediate certificates are kepy on the Yubikey and used to sign server and user certificates.&lt;/p&gt;
&lt;h1 id=&#34;certificate-authority-in-openssl&#34;&gt;Certificate Authority in OpenSSL&lt;/h1&gt;
&lt;p&gt;First, we are going to setup the certificate authority and generate our most precious private keys. To do this, we can use any Linux system with OpenSSL, such as Debian or Alpine. We also need the yubikey manager package installed. On Debian you can install this through apt with &lt;code&gt;apt install yubikey-manager&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You do NOT need to use the same system as your eventual Certificate authority to generate these private keys! You can use an ephemeral system like a live image, as long as you can copy off the resulting certificates (public keys) for the CA and the root public key somewhere safe for later. For ease, I&amp;rsquo;m going to create a new directory in &lt;code&gt;/root/ca&lt;/code&gt; on my eventual CA system to house the certificates and then delete them once all is done and backed up safe. Make sure you update any paths on your own system if you&amp;rsquo;re using a USB drive for your private keys, or copy them out later.&lt;/p&gt;
&lt;p&gt;This would also be a good time to set your &lt;a href=&#34;https://docs.yubico.com/yesdk/users-manual/application-piv/pin-puk-mgmt-key.html&#34;&gt;Yubikey PINs&lt;/a&gt;. The defaults are what an idiot would use on their luggage.&lt;/p&gt;
&lt;h2 id=&#34;setup-the-openssl-ca-config&#34;&gt;Setup the OpenSSL CA Config&lt;/h2&gt;
&lt;p&gt;We don&amp;rsquo;t need an intermediate CA config file since we are just generating the private key to be used by Smallstep, so certificates won&amp;rsquo;t be signed by OpenSSL using the intermedate key.&lt;/p&gt;
&lt;p&gt;Put the config file in &lt;code&gt;/root/ca/root.cnf&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# OpenSSL root CA configuration file.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[ ca ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# `man ca`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;default_ca&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;CA_root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[ CA_root ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Directory and file locations.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dir&lt;/span&gt;               &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/root/ca&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;certs&lt;/span&gt;             &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;$dir/certs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;crl_dir&lt;/span&gt;           &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;$dir/crl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;new_certs_dir&lt;/span&gt;     &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;$dir/newcerts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;database&lt;/span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;$dir/index.txt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;serial&lt;/span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;$dir/serial&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;RANDFILE&lt;/span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;$dir/private/.rand&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The root key and root certificate.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Match names with Smallstep naming convention&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;private_key&lt;/span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;$dir/root_ca_key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;certificate&lt;/span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;$dir/root_ca.crt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# For certificate revocation lists.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;crlnumber&lt;/span&gt;         &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;$dir/crlnumber&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;crl&lt;/span&gt;               &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;$dir/crl/ca.crl.pem&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;crl_extensions&lt;/span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;crl_ext&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;default_crl_days&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# SHA-1 is deprecated, so use SHA-2 instead.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;default_md&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;sha256&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;name_opt&lt;/span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;ca_default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cert_opt&lt;/span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;ca_default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;default_days&lt;/span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;25202&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;preserve&lt;/span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;policy&lt;/span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;policy_strict&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[ policy_strict ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The root CA should only sign intermediate certificates that match.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# See the POLICY FORMAT section of `man ca`.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;countryName&lt;/span&gt;             &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;match&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;organizationName&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;match&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;commonName&lt;/span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;supplied&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[ req ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Options for the `req` tool (`man req`).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;default_bits&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;4096&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;distinguished_name&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;req_distinguished_name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;string_mask&lt;/span&gt;         &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;utf8only&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# SHA-1 is deprecated, so use SHA-2 instead.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;default_md&lt;/span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;sha256&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Extension to add when the -x509 option is used.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x509_extensions&lt;/span&gt;     &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;v3_ca&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[ req_distinguished_name ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# See &amp;lt;https://en.wikipedia.org/wiki/Certificate_signing_request&amp;gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;commonName&lt;/span&gt;                      &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;Common Name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;countryName&lt;/span&gt;                     &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;Country Name (2 letter code)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;0.organizationName&lt;/span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;Organization Name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[ v3_ca ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Extensions for a typical CA (`man x509v3_config`).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;subjectKeyIdentifier&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;hash&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;authorityKeyIdentifier&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;keyid:always,issuer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;basicConstraints&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;critical, CA:true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;keyUsage&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;critical, digitalSignature, cRLSign, keyCertSign&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[ v3_intermediate_ca ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Extensions for a typical intermediate CA (`man x509v3_config`).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;subjectKeyIdentifier&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;hash&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;authorityKeyIdentifier&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;keyid:always,issuer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;basicConstraints&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;critical, CA:true, pathlen:0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;keyUsage&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;critical, digitalSignature, cRLSign, keyCertSign&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And also don&amp;rsquo;t forget to create those directories:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /root/ca /root/ca/certs /root/ca/crl /root/ca/newcerts /root/ca/private
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;touch /root/ca/index.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#ae81ff&#34;&gt;1420&lt;/span&gt; &amp;gt; serial
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;generate-root-certificates&#34;&gt;Generate Root Certificates&lt;/h2&gt;
&lt;p&gt;Keep this &lt;em&gt;VERY SAFE&lt;/em&gt;, preferably offline. Compromising the &lt;code&gt;root_ca_key&lt;/code&gt; means any of your servers (and users with mutual TLS) can be impersonated.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Generate a private key (needs a passphrase, don&amp;#39;t forget the passphrase)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl genrsa -aes256 -out /root/ca/root_ca_key &lt;span style=&#34;color:#ae81ff&#34;&gt;4096&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Sign a 69-year (nice) certificate, to be used by clients mostly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl req -config /root/ca/root.cnf -key /root/ca/root_ca_key -days &lt;span style=&#34;color:#ae81ff&#34;&gt;25202&lt;/span&gt; -new -x509 -sha256 -extensions v3_ca -out /root/ca/root_ca.crt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Congrats, we have a private key and 69-year certificate for it! Now we need a short(er) lived intermediate certificate. For this example, I&amp;rsquo;m going to use 10 years, although in an enterprise environment you&amp;rsquo;ll probably want to go a lot shorter (2-5 years, or as often as you feel comfortable bringing out the root private key to offline-sign new certs and update your Yubikeys).&lt;/p&gt;
&lt;p&gt;If you want to examine the key, you can use &lt;code&gt;openssl x509 -noout -text -in /root/ca/root_ca.crt&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;generate-intermediate-certificate&#34;&gt;Generate Intermediate Certificate&lt;/h2&gt;
&lt;p&gt;Similar to above, but we sign the public key with the root private key. We need to use a 2048 bit key for this to fit in the Yubikey&amp;rsquo;s PIV storage (which does not support 4096 bit keys with the PIV app, but does with PGP)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Generate a private key (needs a passphrase)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl genrsa -aes256 -out /root/ca/intermediate_ca_key &lt;span style=&#34;color:#ae81ff&#34;&gt;2048&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Generate a certificate-signing-request (CSR) for the intermediate CA key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl req -config /root/ca/root.cnf -new -sha256 -key /root/ca/intermediate_ca_key -out /root/ca/intermediate_ca.csr.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Sign the CSR with the root key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openssl ca -config /root/ca/root.cnf -keyfile /root/ca/root_ca_key -cert /root/ca/root_ca.crt -extensions v3_intermediate_ca -days &lt;span style=&#34;color:#ae81ff&#34;&gt;3650&lt;/span&gt; -notext -md sha256 -in /root/ca/intermediate_ca.csr.pem -out /root/ca/intermediate_ca.crt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want to examine the key, you can use &lt;code&gt;openssl x509 -noout -text -in /root/ca/intermediate_ca.crt&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;add-intermediate-key-to-yubikey&#34;&gt;Add Intermediate Key to Yubikey&lt;/h2&gt;
&lt;p&gt;In this phase, we take the intermediate CA key and import it to the Yubikey so we can use it. We also need to start the Yubikey service.&lt;/p&gt;
&lt;p&gt;So, the commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Instll Yubikey manager tools&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install yubikey-manager
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Start Yubikey PCS service and enable it on boot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable pcscd --now
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Add the intermediate CA keys in slot 9C&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# You will need the passphrase for the intermediate private key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# There are other slots available, including all of the &amp;#39;retired&amp;#39; slots if you want&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# to use your Yubikey for other things and not overwrite slot 9C&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ykman piv certificates import 9c /root/ca/intermediate_ca.crt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ykman piv keys import 9c /root/ca/intermediate_ca_key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are curious about the results, run &lt;code&gt;ykman piv info&lt;/code&gt;&lt;/p&gt;
&lt;h1 id=&#34;install-smallstep&#34;&gt;Install Smallstep&lt;/h1&gt;
&lt;h2 id=&#34;setup-debian&#34;&gt;Setup Debian&lt;/h2&gt;
&lt;p&gt;Install Debian Bullseye (I know Bookworm just released), no GUI, with SSH although we can disable that later. Then login, make sure you are root - either login as root, or &lt;code&gt;sudo su&lt;/code&gt; to get to a root prompt. Then &lt;code&gt;cd /root&lt;/code&gt; so we can begin.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using &lt;a href=&#34;https://en.wikipedia.org/wiki/Tempest_(codename)&#34;&gt;&amp;ldquo;tempest&amp;rdquo;&lt;/a&gt; as the name of my CA, located at &lt;code&gt;tempest.palnet.net&lt;/code&gt;. DNS resolves to the IP address of my system locally, not externally, I don&amp;rsquo;t own that domain name. Make sure you update the names in any configuration / examples I list with your own names.&lt;/p&gt;
&lt;p&gt;As usual, once you&amp;rsquo;re done installing run &lt;code&gt;apt update&lt;/code&gt; and &lt;code&gt;apt full-upgrade -y&lt;/code&gt; to make sure everything is up to date before continuing.&lt;/p&gt;
&lt;h2 id=&#34;install-smallstep-cli&#34;&gt;Install Smallstep CLI&lt;/h2&gt;
&lt;p&gt;Unfortunately their deb package doesn&amp;rsquo;t include Yubikey support, so we have to compile that from source, but we can install the CLI from deb packages. If you don&amp;rsquo;t want to use a Yubikey for your private keys, you can also instal the CA from deb packages and skip the whole compiling step below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Download step-cli from github (latest release is 0.24.2)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# We need to build step-ca from source to use Yubikey, but if you aren&amp;#39;t using Yubikey you can go ahead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# and install the ca from deb packages as well.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#wget https://dl.smallstep.com/gh-release/certificates/gh-release-header/v0.24.2/step-ca_0.24.2_amd64.deb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://dl.smallstep.com/gh-release/cli/gh-release-header/v0.24.4/step-cli_0.24.4_amd64.deb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install using apt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install ./*.deb -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm ./*.deb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;build-step-ca-from-source&#34;&gt;Build Step-CA from Source&lt;/h2&gt;
&lt;p&gt;To build Step-CA, we need to install a recent version of the Go compiler, a few other tools and libraries we need to build Step-CA, to actually git clone and build step-ca, and install it. Here&amp;rsquo;s the process:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Add Backports to sources.list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &amp;gt;&amp;gt; /etc/apt/sources.list &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt; EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#Backports repository
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;deb http://deb.debian.org/debian/ bullseye-backports main
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;deb-src http://deb.debian.org/debian/ bullseye-backports main
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# And apt-update&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install golang (this is the same version in Bookworm, fyi, 1.20 is in Sid still)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# And Git, so we can clone stuff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# And also some other packages we need to compile Smallstep&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install golang-1.19-go git libpcsclite-dev gcc make pkg-config curl -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Add Go 1.19 to PATH for the next operations&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PATH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/usr/lib/go-1.19/bin:&lt;/span&gt;$PATH&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Clone the git repo, move to it, and checkout the latest release (as of this writing, 0.24.2, but check Github)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/smallstep/certificates.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd certificates
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git checkout v0.24.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Build process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Once you execute these, go get a coffee and come back, or maybe drive to get a snack, it&amp;#39;ll be awhile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make bootstrap
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# I know this sounds odd but I promise &amp;#39;install&amp;#39; also does &amp;#39;build&amp;#39;, since it depends on the binary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# GOFLAGS are clear so it does a CGO build, which is required for Yubikey support&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make install GOFLAGS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# This tells the kernel that step-ca can bind to service ports&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;setcap CAP_NET_BIND_SERVICE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;+eip /usr/bin/step-ca
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now check version: &lt;code&gt;step version&lt;/code&gt; and &lt;code&gt;step-ca version&lt;/code&gt; to make sure they both run. &lt;code&gt;step-ca&lt;/code&gt; should show a release time/date of now the time you actually built it, which should be now() but in UTC and not your local timezone.&lt;/p&gt;
&lt;h2 id=&#34;setup-step-ca&#34;&gt;Setup Step-CA&lt;/h2&gt;
&lt;p&gt;Step-CA usually wants to do its own PKI, so we are going to let it generate a new set of private keys and sign them, then delete them. So, that&amp;rsquo;s fun. There aren&amp;rsquo;t any options to &lt;em&gt;not&lt;/em&gt; generate keys.&lt;/p&gt;
&lt;p&gt;Anyway, commands for this phase:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Create a new user for step-ca process, and a home in etc for it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /etc/step
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export STEPPATH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/etc/step
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;useradd step 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;passwd -l step
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Run Step Init to create its folder structure and config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Enter the password for your admin user (&amp;#39;provisioner&amp;#39;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;step ca init --name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TEMPEST&amp;#34;&lt;/span&gt; --dns&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tempest.palnet.net&amp;#34;&lt;/span&gt; --address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;:443&amp;#34;&lt;/span&gt; --provisioner&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;apalrd&amp;#34;&lt;/span&gt; --deployment-type standalone
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Copy the certificates (but not the private keys) from the root location to /etc/step and own them to step&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp /root/ca/root_ca.crt /root/ca/intermediate_ca.crt /etc/step/certs/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R step:step /etc/step/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next up, we need to edit &lt;code&gt;/etc/step/config/ca.json&lt;/code&gt; to configure our Yubikey instead of internal PKI for this Step instance. Specifically, replace the &lt;code&gt;key&lt;/code&gt; directive which points to a private key with a bit about it being a yubikey and selecting the parameters for the key management system (KMS). The diff looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 	&amp;#34;root&amp;#34;: &amp;#34;/etc/step/certs/root_ca.crt&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 	&amp;#34;federatedRoots&amp;#34;: null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 	&amp;#34;crt&amp;#34;: &amp;#34;/etc/step/certs/intermediate_ca.crt&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-	&amp;#34;key&amp;#34;: &amp;#34;/etc/step/secrets/intermediate_ca_key&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+   &amp;#34;key&amp;#34;: &amp;#34;yubikey:slot-id=9c&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+   &amp;#34;kms&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+            &amp;#34;type&amp;#34;: &amp;#34;yubikey&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+            &amp;#34;pin&amp;#34;: &amp;#34;123456&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+   },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 	&amp;#34;address&amp;#34;: &amp;#34;:443&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 	&amp;#34;insecureAddress&amp;#34;: &amp;#34;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now we can test it! &lt;code&gt;sudo -u step step-ca /etc/step/config/ca.json&lt;/code&gt;, shouldn&amp;rsquo;t give any errors and should sit and wait for requests to come in.&lt;/p&gt;
&lt;h2 id=&#34;add-systemd-service&#34;&gt;Add SystemD Service&lt;/h2&gt;
&lt;p&gt;Since we presumably want this to run all the time, this should be a service, and systemd is the thing that does services.&lt;/p&gt;
&lt;p&gt;So, write out this service file, or copy and paste this all into the terminal to do it for you:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The service script&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &amp;gt; /etc/systemd/system/step-ca.service  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt; EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Description=Smallstep Certificate Authority
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Service]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;User=step
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Group=step
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Environment=&amp;#34;STEPPATH=/etc/step&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;ExecStart=/usr/bin/step-ca /etc/step/config/ca.json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Install]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;WantedBy=multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Reload daemons and start now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now step-ca
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;enable-acme-challenges&#34;&gt;Enable ACME Challenges&lt;/h2&gt;
&lt;p&gt;Now that our &lt;code&gt;step-ca&lt;/code&gt; is up and running, we can enable the ACME provisioner for it. We are, finally, almost ready to issue certificates to our infrastructure! For this, we also need the &lt;code&gt;fingerprint&lt;/code&gt;, which the ca prints when it starts up (get it from &lt;code&gt;systemctl status step-ca&lt;/code&gt; and look for &lt;code&gt;X.509 Root Fingerprint&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;And the commands for this step:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Make sure STEPATH is still set, since we need it for this phase &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export STEPPATH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/etc/step
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Add the acme provisioner using our admin account&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;step ca provisioner add acme --type ACME --admin-name apalrd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Restart the service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl restart step-ca
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;using-your-ca&#34;&gt;Using your CA&lt;/h1&gt;
&lt;h2 id=&#34;trust-your-root&#34;&gt;Trust your Root&lt;/h2&gt;
&lt;p&gt;Here are some instructions on trusting your root certificate in Debian. Remember that the certificate is hosted by our ACME server, so we can just download it (although it&amp;rsquo;s certificate won&amp;rsquo;t yet be trusted, so we need to ignore certificate errors for now).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# As root, or prepend with sudo of course&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget --no-check-certificate https://tempest.palnet.net/roots.pem -O /usr/local/share/ca-certificates/tempest.crt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;update-ca-certificates
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You&amp;rsquo;ll need to do this for every single computer which you use to access your sites, or you&amp;rsquo;ll get a certificate error. Fun, right? But once you add the root certificate, then you can continue to add homelab services without needing to individually trust each one on each user&amp;rsquo;s system.&lt;/p&gt;
&lt;h2 id=&#34;using-your-ca-in-caddy&#34;&gt;Using your CA in Caddy&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s an example &lt;code&gt;Caddyfile&lt;/code&gt; which uses my local CA to issue a signed certificate. Also note that I first added the root certificate to the trust store on the local system, so I don&amp;rsquo;t need to separately tell Caddy to trust the root certificate.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Global options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Our local ACME server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;acme_ca https://tempest.palnet.net/acme/acme/directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#A single server which will get a TLS certificate automatically&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ca-testsvr.palnet.net {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#All of the options here are left as defaults&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#But just say hello world for now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;respond &amp;#34;Hello, World!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;references&#34;&gt;References&lt;/h1&gt;
&lt;p&gt;Here are some guides I used when writing this script, they might also be useful to you.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/&#34;&gt;Smallstep ACME Server on Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://smallstep.com/docs/step-ca/acme-basics/#configure-step-ca-for-acme&#34;&gt;Smallstep ACME Provisoiner Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://smallstep.com/docs/step-ca/configuration/#yubikey-piv&#34;&gt;Smallstep Yubikey PIV Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.openssl.org/docs/&#34;&gt;OpenSSL Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Organize your Homelab Services with Dashy!</title>
      <link>https://www.apalrd.net/posts/2023/ultimate_dashy/</link>
      <pubDate>Thu, 01 Jun 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/ultimate_dashy/</guid>
      <description>Do you have so many self-hosted services running in your homelab that it&amp;rsquo;s hard to keep track of them all? Do you hate typing the IP/port for each one? You could use DNS, but a nice dashboard would make it easier too! Today I&amp;rsquo;m setting that up with Dashy, a beautiful and easy to edit homelab dashboard tool. It&amp;rsquo;s not the lightest weight tool in the world, but the look is worth it for me.</description>
      <content>&lt;p&gt;Do you have so many self-hosted services running in your homelab that it&amp;rsquo;s hard to keep track of them all? Do you hate typing the IP/port for each one? You could use DNS, but a nice dashboard would make it easier too! Today I&amp;rsquo;m setting that up with Dashy, a beautiful and easy to edit homelab dashboard tool. It&amp;rsquo;s not the lightest weight tool in the world, but the look is worth it for me.&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/-sPNewi4GTc&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_dashy/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;install-script&#34;&gt;Install Script&lt;/h1&gt;
&lt;p&gt;Start with a Debian 11 (Bullseye) LXC container, and run this all as root. Feel free to go section by section if you want, or copy and paste the whole thing and yolo it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#NodeJS 16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget -O - https://deb.nodesource.com/setup_16.x | bash -
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#apt update&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#apt install stuff (nodejs version should track Nodesource now)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install -y nodejs git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#NPM install stuff (need a newer version of yarn than in apt)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install --global yarn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Move to dashy dir, clone the git repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /opt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/Lissy93/dashy.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd dashy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Do the yarn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn build
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create systemd service for Dashy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &amp;gt; /etc/systemd/system/dashy.service &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt; EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Description=Dashy homelab dashboard
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;After=network-online.target
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Service]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Environment=&amp;#34;PORT=80&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Environment=&amp;#34;HOST=::&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;ExecStart=/usr/bin/yarn --cwd=/opt/dashy start
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Restart=always
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Install]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;WantedBy=multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create systemd service to rebuild dashy on config change&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &amp;gt; /etc/systemd/system/dashy-rebuild.service &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt; EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Description=Rebuild Dashy on Config Changes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Service]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Type=oneshot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;ExecStart=/usr/bin/yarn --cwd=/opt/dashy build
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create systemd path to call service on config file change&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &amp;gt; /etc/systemd/system/dashy-rebuild.path &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt; EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Description=Monitor Dashy Config for Changes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Path]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;PathChanged=/opt/dashy/public/conf.yml
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[Install]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;WantedBy=multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make systemd aware that we just changed stuff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#And start our services!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now dashy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable --now dashy-rebuild.path
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>The ULTIMATE Guide to Fiber Optic Home Networking</title>
      <link>https://www.apalrd.net/posts/2023/network_fiber/</link>
      <pubDate>Thu, 25 May 2023 01:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/network_fiber/</guid>
      <description>Do you have a need to extend your home network around your property? Maybe you want reliable internet in the shed you turned into a work-from-home office, or your garage or workshop? Today I&amp;rsquo;m going to explain what you need to run fiber optic newtorking around your home and property on a budget, for high bandwidth and low latency networking. Fiber doesn&amp;rsquo;t have any issues with lightning or electrical potential changes between buildings, and can handle much higher bandwidth with higher reliability than wifi mesh or point to point systems.</description>
      <content>&lt;p&gt;Do you have a need to extend your home network around your property? Maybe you want reliable internet in the shed you turned into a work-from-home office, or your garage or workshop? Today I&amp;rsquo;m going to explain what you need to run fiber optic newtorking around your home and property on a budget, for high bandwidth and low latency networking. Fiber doesn&amp;rsquo;t have any issues with lightning or electrical potential changes between buildings, and can handle much higher bandwidth with higher reliability than wifi mesh or point to point systems.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not as expensive as you think to run fiber in your network!&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_fiber/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_fiber/#fiber&#34;&gt;Hardware - Fiber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_fiber/#media-converters&#34;&gt;Hardware - Media Converters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_fiber/#network-cards&#34;&gt;Hardware - Network Cards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_fiber/#network-switches&#34;&gt;Hardware - Network Switches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_fiber/#transceivers&#34;&gt;Hardware - Transceivers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_fiber/#my-1g-bidi-setup&#34;&gt;Example Setups - My 1G BiDi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_fiber/#my-10g-gaming-shed-setup&#34;&gt;Example Setups - My 10G Gaming Shed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/d20roxFfU0A&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/network_fiber/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;hardware-recommendations&#34;&gt;Hardware Recommendations&lt;/h1&gt;
&lt;p&gt;This section has more detailed links to the products I reference in the video. Enjoy!&lt;/p&gt;
&lt;p&gt;Some links to products may be affiliate links, which may earn a commission for me.&lt;/p&gt;
&lt;h2 id=&#34;fiber&#34;&gt;Fiber&lt;/h2&gt;
&lt;p&gt;For Fiber, there are a lot more options for singlemode than multimode. In general, ordering custom length patch cables is the easiest way to go. In general I have bought fiber from &lt;a href=&#34;fs.com&#34;&gt;fs.com&lt;/a&gt; for my own projects, so that&amp;rsquo;s what I&amp;rsquo;m linking here. For all of these options, you can click &amp;lsquo;customize&amp;rsquo; and have the right length made to order.&lt;/p&gt;
&lt;p&gt;Networking fiber uses LC connectors with UPC polish, which is color coded blue (vs green for APC polish, used in PON fiber-to-the-home systems).&lt;/p&gt;
&lt;p&gt;In general you should use riser rated cables indoors, there are very narrow use cases where you would need plenum rating (low smoke) in a normal house. In my locale it&amp;rsquo;s not required for low voltage cables at all in the residential code. If you are going underground in conduit the whole way, you can use indoor rated fiber (it&amp;rsquo;s considered a wet location, but not subject to damage), and if you are going outdoors you need to use a UV stable jacket (such as TPU) instead of PVC. If you need plenum rating, when customizing, change the jacket type from &amp;lsquo;PVC&amp;rsquo; to &amp;lsquo;Plenum (OFNP)&amp;rsquo;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t use armored cable, but I have done all of these runs after building the house and am more concerned with fishing the wiring easily through tough spaces. If you&amp;rsquo;re installing at construction time, it might be a good idea to use armored cable to protect from damage during construction. Remember, it&amp;rsquo;s effectively imposible to repair the fiber.&lt;/p&gt;
&lt;h3 id=&#34;om3-multimode-duplex&#34;&gt;OM3 Multimode (Duplex)&lt;/h3&gt;
&lt;p&gt;Remember, you want aqua cables (if they are colored indicating type), not orange. If the ends are colored, they should be blue, not green.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/12018.html&#34;&gt;OM3 Patch Cable Duplex LC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/20720.html&#34;&gt;OM3 Patch Cable Armored duplex LC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;os2-singlemode-duplex&#34;&gt;OS2 Singlemode (Duplex)&lt;/h3&gt;
&lt;p&gt;OS2 should be colored yellow if colored to match type, and the ends should be blue if colored to match type.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/50147.html&#34;&gt;OS2 Patch Cable Duplex LC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/20720.html&#34;&gt;OS2 Patch Cable Armored Duplex LC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/70220.html&#34;&gt;OS2 Industrial Armored TPU Cable&lt;/a&gt; - Make sure to select 2 fibers, LC UPC Duplex&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;os3-singlemode-simplex--bidi&#34;&gt;OS3 Singlemode (Simplex / BiDi)&lt;/h3&gt;
&lt;p&gt;These are only for BiDi use, use duplex if you aren&amp;rsquo;t going to do BiDi.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/12285.html&#34;&gt;OS2 Patch Cable Simplex LC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/70220.html&#34;&gt;OS2 Industrial Armored TPU Cable&lt;/a&gt; - Make sure to select single fiber, LC UPC Simplex&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;media-converters&#34;&gt;Media Converters&lt;/h2&gt;
&lt;p&gt;These devices strictly convert from a transceiver to copper, nothing more, nothing less. They are cheap and you should use them if you already have wired Ethernet hardware at this end of the link you want to connect to. Any of these options can go at either end of the link, as long as they are running at the same speed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/42R7gCs&#34;&gt;1G SFP to RJ45 - TP-Link MC220L&lt;/a&gt; - I use this one, it runs at 1G SFP.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/101476.html&#34;&gt;10G SFP+ to RJ45 Mult-Gig&lt;/a&gt; - I have not used this one myself, it requires 10G on the SFP+ side, and will negotiate 1/2.5/5/10G on the RJ45 side.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;network-cards&#34;&gt;Network Cards&lt;/h2&gt;
&lt;p&gt;These go in your computer and accept an SFP/SFP+ module. You may need to do some configuration with ethtool / windows / &amp;hellip; to set the link speed if you are not using the rated speed. Recommended for &amp;lsquo;servers&amp;rsquo; especially, but also good for high bandwidth desktops and workstations. Also, be aware of the form factor - a lof of these cards come in OCP NIC and normal PCIe slot sizes, and you probably can&amp;rsquo;t use an OCP NIC in your regular desktop.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://ebay.us/TQo3LD&#34;&gt;Intel X520-DA1/DA2 (10G capable)&lt;/a&gt; - only difference is DA1 = 1 port, DA2 = 2 port. Do NOT get T1/T2/.. versions, those are RJ45.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ebay.us/raue9O&#34;&gt;Mellanox Connect-X 3 (10G capable)&lt;/a&gt; - Make sure it&amp;rsquo;s Ethernet and 10G SFP+, they made CX3 cards with 10G QSFP and Infiniband variants.
If you want to go for higher speeds in the future, the Connext-X 4 family can do 25G with SFP28, which is the next speed tier up above SFP+, and is also backwards compatible. If you are building a router, some people claim the newer Intel X710-DA is better, although I can&amp;rsquo;t say one way or another.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;network-switches-and-routers&#34;&gt;Network Switches and Routers&lt;/h2&gt;
&lt;p&gt;A &lt;em&gt;ton&lt;/em&gt; of network switches have SFP or SFP+, here are just a few of my favorites. I use Mikrotik equipment, so that&amp;rsquo;s what I&amp;rsquo;ve listed here. Feel free to shop around as well, there are a lot of good regional distributors for this (i.e. Baltic Netoworks in the US, Getic in the EU) depending on your location.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3q635Es&#34;&gt;Mikrotik RB260GS (1G capable)&lt;/a&gt; - 5 Copper, 1 SFP port&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/43fYCgY&#34;&gt;Mikrotik RB260GSP (1G capable)&lt;/a&gt; - Same as above, but with &lt;em&gt;passive&lt;/em&gt; PoE out (if you don&amp;rsquo;t know about passive PoE, be warned).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/43lulgG&#34;&gt;Mikrotik hEX S Ethernet Router (1G capable)&lt;/a&gt; - Same ports as RB260, but a full router&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/43oqKhL&#34;&gt;Mikrotik hAP AC WiFi Router (1G capable)&lt;/a&gt; - Same as above, but with WiFi as well. You can also use it as a WiFi access point + switch, using the router you already have.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.balticnetworks.com/products/mikrotik-crs328-cloud-router-switch-24-gigabit-ethernet-ports-4-sfp?_pos=1&amp;_sid=e8b252994&amp;_ss=r&#34;&gt;Mikrotik CRS328-24P-4S+RM (10G SFP+ capable)&lt;/a&gt; - The big 24 PoE + 4 SFP+ port switch that I use in my house&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;transceivers&#34;&gt;Transceivers&lt;/h2&gt;
&lt;h3 id=&#34;om3-multimode-duplex-1&#34;&gt;OM3 Multimode (Duplex)&lt;/h3&gt;
&lt;p&gt;Choose the same transceiver for both ends.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/11774.html&#34;&gt;Basic 1G SFP from FS.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3OCwO2e&#34;&gt;Basic 1G SFP from Amazon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/11552.html&#34;&gt;10G SFP+ from FS.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3otuQGx&#34;&gt;10G SFP+ from Amazon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;os2-singlemode-duplex-1&#34;&gt;OS2 Singlemode (Duplex)&lt;/h3&gt;
&lt;p&gt;Choose the same transceiver for both ends.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/11775.html&#34;&gt;Basic 1G SFP from FS.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/43nsyrf&#34;&gt;Basic 1G SFP from Amazon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/11555.html&#34;&gt;10G SFP+ from FS.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/11556.html&#34;&gt;10G SFP+ 2km from FS.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3or4eGa&#34;&gt;10G SFP+ from Amazon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;os3-singlemode-simplex--bidi-1&#34;&gt;OS3 Singlemode (Simplex / BiDi)&lt;/h3&gt;
&lt;p&gt;Choose a MATCHED PAIR here, with opposite transmit/receive wavelengths on each end&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/11795.html&#34;&gt;Basic 1G SFP SIDE A&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/11802.html&#34;&gt;Basic 1G SFP SIDE B&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/36351.html&#34;&gt;10G SFP+ SIDE A&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/36353.html&#34;&gt;10G SFP+ SIDE B&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;example-setup-lists&#34;&gt;Example Setup Lists&lt;/h1&gt;
&lt;p&gt;These are some example setups I&amp;rsquo;ve setup for you to use to think about what you need for your project.&lt;/p&gt;
&lt;h2 id=&#34;1g-cheap-bidi-setup&#34;&gt;1G Cheap BiDi Setup&lt;/h2&gt;
&lt;p&gt;This is a simple gigabit BiDi setup that can be used to run Ethernet long distances, to outbuildings, etc. with a simple media converter to connect to your existing network and a switch at the far end.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/12285.html&#34;&gt;Fiber (Indoors / In Conduit)&lt;/a&gt; - I recommend the 3mm jacket for increased robustness&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/70220.html&#34;&gt;Fiber (Outdoors / Direct Burial)&lt;/a&gt; - Fiber Count = Simplex, Connectors = LC UPC Simplex&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/11795.html&#34;&gt;Basic 1G SFP SIDE A&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/11802.html&#34;&gt;Basic 1G SFP SIDE B&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/42R7gCs&#34;&gt;Media Converter for one side&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3q635Es&#34;&gt;Mikrotik Switch for other side&lt;/a&gt;
Total Cost is around $100 for indoor fiber or $200 for outdoor fiber, depending on the length.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;my-10g-gaming-shed-setup&#34;&gt;My 10G Gaming Shed Setup&lt;/h2&gt;
&lt;p&gt;This is the setup I actually used in the video.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/50147.html&#34;&gt;Fiber (Indoors / In Conduit)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fs.com/products/11556.html&#34;&gt;Transceivers (2x)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ebay.us/TQo3LD&#34;&gt;Intel X520-DA1/DA2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.balticnetworks.com/products/mikrotik-crs328-cloud-router-switch-24-gigabit-ethernet-ports-4-sfp?_pos=1&amp;_sid=e8b252994&amp;_ss=r&#34;&gt;Mikrotik CRS328-24P-4S+RM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since I already had the switch, I actually spent $98 on the rest of the parts, but the switch is an additional $489 at list price (obviously it can do a whole lot more than just this one run though).&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>The Homelab Swiss Army Knife: ZimaBoard</title>
      <link>https://www.apalrd.net/posts/2023/network_zima/</link>
      <pubDate>Thu, 18 May 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/network_zima/</guid>
      <description>I&amp;rsquo;ve used a lot of different small form factor machines over the years, from the Raspberry Pi to used ebay thin clients. All of them are good at some things. But when Icewhale sent over their x86-based Zimaboard for me to take a look at, I&amp;rsquo;ve been impressed with the flexibility it has for me to test new software and hardware in a relatively cheap way. It&amp;rsquo;s not spectacular at any one thing, but it&amp;rsquo;s versatile enough that it&amp;rsquo;s a great foundation for so many of my projects.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve used a lot of different small form factor machines over the years, from the Raspberry Pi to used ebay thin clients. All of them are good at some things. But when Icewhale sent over their x86-based Zimaboard for me to take a look at, I&amp;rsquo;ve been impressed with the flexibility it has for me to test new software and hardware in a relatively cheap way. It&amp;rsquo;s not spectacular at any one thing, but it&amp;rsquo;s versatile enough that it&amp;rsquo;s a great foundation for so many of my projects.&lt;/p&gt;
&lt;p&gt;So what&amp;rsquo;s good about the Zimaboard:
-Reasonable price for an x86-based single board computer
-Being x86 based is a huge advantage for running the usual homelab software
-Enough eMMC for a full operating system, enough for many use cases without additional storage
-Dual NICs are a huge benefit to a lot of projects
-Low power 12V input
-CasaOS is open-source and very easy to get started with if you want the basics for your homelab without a lot of fuss&lt;/p&gt;
&lt;p&gt;A few negatives:
-PCIe slot is in a bit of a weird position, slot covers don&amp;rsquo;t fit well and hit the case, I ended up taking them all off
-Not enough USB ports if you want to actually use it as a desktop (or install and OS via a GUI)
-The ZimaBoard itself is beautiful, but when you add cards and SSDs, it can look very hacked together.&lt;/p&gt;
&lt;p&gt;Contents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_zima/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_zima/#lscpu&#34;&gt;lscpu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_zima/#lspci&#34;&gt;lspci&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_zima/#vainfo&#34;&gt;vainfo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/R5QtXMwzJas&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/network_zima/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;lscpu&#34;&gt;lscpu&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Architecture&lt;/span&gt;:                    &lt;span style=&#34;color:#ae81ff&#34;&gt;x86_64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU op-mode(s)&lt;/span&gt;:                  &lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;-&lt;span style=&#34;color:#ae81ff&#34;&gt;bit, 64-bit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Address sizes&lt;/span&gt;:                   &lt;span style=&#34;color:#ae81ff&#34;&gt;39&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;bits physical, 48 bits virtual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Byte Order&lt;/span&gt;:                      &lt;span style=&#34;color:#ae81ff&#34;&gt;Little Endian&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU(s)&lt;/span&gt;:                          &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;On-line CPU(s) list&lt;/span&gt;:             &lt;span style=&#34;color:#ae81ff&#34;&gt;0-3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vendor ID&lt;/span&gt;:                       &lt;span style=&#34;color:#ae81ff&#34;&gt;GenuineIntel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Model name&lt;/span&gt;:                      &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel(R) Celeron(R) CPU N3450 @ 1.10GHz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU family&lt;/span&gt;:                      &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Model&lt;/span&gt;:                           &lt;span style=&#34;color:#ae81ff&#34;&gt;92&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Thread(s) per core&lt;/span&gt;:              &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Core(s) per socket&lt;/span&gt;:              &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Socket(s)&lt;/span&gt;:                       &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Stepping&lt;/span&gt;:                        &lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU max MHz&lt;/span&gt;:                     &lt;span style=&#34;color:#ae81ff&#34;&gt;2200.0000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU min MHz&lt;/span&gt;:                     &lt;span style=&#34;color:#ae81ff&#34;&gt;800.0000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;BogoMIPS&lt;/span&gt;:                        &lt;span style=&#34;color:#ae81ff&#34;&gt;2188.80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Flags&lt;/span&gt;:                           &lt;span style=&#34;color:#ae81ff&#34;&gt;fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology tsc_reliable nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg cx16 xtpr pdcm sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave rdrand lahf_lm 3dnowprefetch cpuid_fault cat_l2 ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust smep erms mpx rdt_a rdseed smap clflushopt intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts md_clear arch_capabilities&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Virtualization&lt;/span&gt;:                  &lt;span style=&#34;color:#ae81ff&#34;&gt;VT-x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;L1d cache&lt;/span&gt;:                       &lt;span style=&#34;color:#ae81ff&#34;&gt;96&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;KiB (4 instances)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;L1i cache&lt;/span&gt;:                       &lt;span style=&#34;color:#ae81ff&#34;&gt;128&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;KiB (4 instances)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;L2 cache&lt;/span&gt;:                        &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;MiB (2 instances)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;NUMA node(s)&lt;/span&gt;:                    &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;NUMA node0 CPU(s)&lt;/span&gt;:               &lt;span style=&#34;color:#ae81ff&#34;&gt;0-3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Itlb multihit&lt;/span&gt;:     &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability L1tf&lt;/span&gt;:              &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Mds&lt;/span&gt;:               &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Meltdown&lt;/span&gt;:          &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Mmio stale data&lt;/span&gt;:   &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Retbleed&lt;/span&gt;:          &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Spec store bypass&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Spectre v1&lt;/span&gt;:        &lt;span style=&#34;color:#ae81ff&#34;&gt;Mitigation; usercopy/swapgs barriers and __user pointer sanitization&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Spectre v2&lt;/span&gt;:        &lt;span style=&#34;color:#ae81ff&#34;&gt;Mitigation; Retpolines, IBPB conditional, IBRS_FW, STIBP disabled, RSB filling, PBRSB-eIBRS Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Srbds&lt;/span&gt;:             &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Tsx async abort&lt;/span&gt;:   &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;lspci&#34;&gt;lspci&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:00.0 Host bridge&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series Host Bridge (rev 0b)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:02.0 VGA compatible controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation HD Graphics 500 (rev 0b) (prog-if 00 [VGA controller])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:0e.0 Audio device&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series Audio Cluster (rev 0b)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:0f.0 Communication controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series Trusted Execution Engine (rev 0b)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:12.0 SATA controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series SATA AHCI Controller (rev 0b) (prog-if 01 [AHCI 1.0])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:13.0 PCI bridge&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port A&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#1 (rev fb) (prog-if 00 [Normal decode])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:14.0 PCI bridge&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port B&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#1 (rev fb) (prog-if 00 [Normal decode])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:14.1 PCI bridge&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port B&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#2 (rev fb) (prog-if 00 [Normal decode])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:15.0 USB controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series USB xHCI (rev 0b) (prog-if 30 [XHCI])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:1c.0 SD Host controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series eMMC Controller (rev 0b) (prog-if 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:1f.0 ISA bridge&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series Low Pin Count Interface (rev 0b)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:1f.1 SMBus&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Celeron N3350/Pentium N4200/Atom E3900 Series SMBus Controller (rev 0b)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;02:00.0 Ethernet controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 15)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;03:00.0 Ethernet controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 15)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;vainfo&#34;&gt;vainfo&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;vainfo: VA-API version&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1.14&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;(libva 2.12.0)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;vainfo: Driver version&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel iHD driver for Intel(R) Gen Graphics - 22.3.1 ()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;vainfo&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Supported profile and entrypoints&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileMPEG2Simple            :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileMPEG2Main              :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264Main               :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264Main               :	VAEntrypointEncSliceLP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264High               :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264High               :	VAEntrypointEncSliceLP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileJPEGBaseline           :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileJPEGBaseline           :	VAEntrypointEncPicture&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264ConstrainedBaseline:	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264ConstrainedBaseline:	VAEntrypointEncSliceLP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileVP8Version0_3          :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain               :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain10             :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileVP9Profile0            :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Setting Up my PROXMOX Backup Server!</title>
      <link>https://www.apalrd.net/posts/2023/pbs_intro/</link>
      <pubDate>Thu, 11 May 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/pbs_intro/</guid>
      <description>I&amp;rsquo;ve gone from &amp;ldquo;no backups&amp;rdquo; to &amp;ldquo;raid is a backup&amp;rdquo; to &amp;ldquo;two zfs pools in one box&amp;rdquo;, and decided it&amp;rsquo;s finally time for a proper backup solution. So, I settled on Proxmox Backup Server! And today, I rebuild my HP Microserver Gen8 with 4x10T refurbished SAS drives, a new SAS controller card, and more! With this backup solution, I&amp;rsquo;m feeling a lot better about my data migration to Ceph.
Contents Video SAS Drive Formatting ZFS Pool Setup Next Steps Video SAS Drive Formatting Since these drives were refurbished they were formerly formatted for a hardware RAID controller and were giving me lots of protection errors in dmesg - specifically blk_update_request: protection error (and failing to read, but not write).</description>
      <content>&lt;p&gt;I&amp;rsquo;ve gone from &amp;ldquo;no backups&amp;rdquo; to &amp;ldquo;raid is a backup&amp;rdquo; to &amp;ldquo;two zfs pools in one box&amp;rdquo;, and decided it&amp;rsquo;s finally time for a proper backup solution. So, I settled on Proxmox Backup Server! And today, I rebuild my HP Microserver Gen8 with 4x10T refurbished SAS drives, a new SAS controller card, and more! With this backup solution, I&amp;rsquo;m feeling a lot better about my data migration to Ceph.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/pbs_intro/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/pbs_intro/#sas-drive-formatting&#34;&gt;SAS Drive Formatting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/pbs_intro/#zfs-pool-setup&#34;&gt;ZFS Pool Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/pbs_intro/#next-steps&#34;&gt;Next Steps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/jqQueAjdrYA&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/pbs_intro/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;sas-drive-formatting&#34;&gt;SAS Drive Formatting&lt;/h2&gt;
&lt;p&gt;Since these drives were refurbished they were formerly formatted for a hardware RAID controller and were giving me lots of protection errors in dmesg - specifically &lt;code&gt;blk_update_request: protection error&lt;/code&gt; (and failing to read, but not write). Reading around I found the answer - format without hardware protection. The drives were likely previously used with a hardware RAID controller and had additional data integrity features enabled, something that ZFS doesn&amp;rsquo;t need. The command I used to do this is &lt;code&gt;sg_format --format /dev/sdX&lt;/code&gt; and took about a full day per drive to complete (I ran them all in parallel, no I didn&amp;rsquo;t wait a week). This is different than a filesystem format, since it&amp;rsquo;s a SCSI command to request that the drive format itself with the sector size and layout requested (in this case, the manufacturer&amp;rsquo;s defaults).&lt;/p&gt;
&lt;p&gt;I also ran SMART tests and they passed.&lt;/p&gt;
&lt;h2 id=&#34;zfs-pool-setup&#34;&gt;ZFS Pool Setup&lt;/h2&gt;
&lt;p&gt;I wanted to use a ZFS Special Device, which stores filesystem metadata on a separate drive. This can let me use a smaller faster drive to speed up directory listings and large metadata operations, which is important in PBS since it can potentially store up to 65k files per directory. The chunk-based deduplication system splits data up into files named by their hash, so it relies on the filesystem to store a ton of files.&lt;/p&gt;
&lt;p&gt;I created the zfs pool via the GUI, using RAIDZ1 with the 4x10T drives (30T usable). Then I added the special device from the shell: &lt;code&gt;zpool add &amp;lt;poolname&amp;gt; -o ashift=12 special mirror /dev/sde /dev/sdf -f&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;Going forward, I have a few plans for this system that I haven&amp;rsquo;t implemented yet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Auto-start the server at backup time, and auto shut-down when backups and other tasks are done&lt;/li&gt;
&lt;li&gt;LACP bond (2x1gig) when I have enough switch ports to do that&lt;/li&gt;
&lt;li&gt;Add backup of CephFS directly on the PBS server (mount Ceph on PBS, run proxmox-backup-client to the CephFS mount, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;TAPE BACKUP! I bought an LTO5 SAS drive to dip my toes in tape backup, to see if I like it before moving to an autoloader&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Remove Proxmox Server Access over SERIAL! Cheaper Alternative to IPMI or KVMs</title>
      <link>https://www.apalrd.net/posts/2023/newstor_com/</link>
      <pubDate>Thu, 27 Apr 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/newstor_com/</guid>
      <description>I have a rack-mounted KVM now, and it&amp;rsquo;s great, but I&amp;rsquo;m working on building out a new Proxmox cluster which might not have a graphics output at all on some of the nodes. So, I need a new remote access solution for them.
The new nodes I&amp;rsquo;m planning on building will all be based on used consumer hardware, so I&amp;rsquo;m limited by what would be available on normal mATX boards. This doesn&amp;rsquo;t include IPMI, and if I go with AMD-based CPUs, doesn&amp;rsquo;t include an iGPU either.</description>
      <content>&lt;p&gt;I have a rack-mounted KVM now, and it&amp;rsquo;s great, but I&amp;rsquo;m working on building out a new Proxmox cluster which might not have a graphics output at all on some of the nodes. So, I need a new remote access solution for them.&lt;/p&gt;
&lt;p&gt;The new nodes I&amp;rsquo;m planning on building will all be based on used consumer hardware, so I&amp;rsquo;m limited by what would be available on normal mATX boards. This doesn&amp;rsquo;t include IPMI, and if I go with AMD-based CPUs, doesn&amp;rsquo;t include an iGPU either. So I either need to get cheap GPUs to add to the second PCIe slot (which I then can&amp;rsquo;t use for things like HBAs), or at least put a GPU in for troubleshooting. However, adding a GPU often moves PCIe devices, leading to issues where the network card on enp4 is now enp5 when the GPU is attahed, for example. So trouleshooting for real would be a nightmare with this approach.&lt;/p&gt;
&lt;p&gt;But! There is an alternative. Despite being ancient, many boards still have a COM header connected to the chipset, which provides a basic serial port header (&amp;lsquo;COM1&amp;rsquo; in Windows) and is completely usable. So, my goal is to connect this COM header to a female RJ45 port on the back of the computer, so I can plug in a &amp;lsquo;Cisco-style&amp;rsquo; terminal cable. These sorts of cables (RJ45 serial to USB) are readily available cheaply on the internet, and I can open a terminal emulator on my laptop to diagnose the worst issues that lock up the system.&lt;/p&gt;
&lt;p&gt;Since some systems are rumored to not POST without a graphics card, I&amp;rsquo;m testing this approach today.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/newstor_com/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/newstor_com/#building-the-cable&#34;&gt;Building the Cable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/newstor_com/#proxmox-setup&#34;&gt;Proxmox Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/newstor_com/#parts&#34;&gt;Parts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/ycue2GGh_dk&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/newstor_com/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;building-the-cable&#34;&gt;Building the Cable&lt;/h1&gt;
&lt;p&gt;The Cisco/Juniper style RJ45 pinout is fairly simple if we exclude all of the flow control lines, so we just need 3 wires. I bought a pack of 2x5 IDC headers and a panel mount female RJ45 extension cable (which can be mounted in the case), cut the male end off, and crimped the resulting wires directly in the IDC header. Then I used a cheap USB to RJ45 serial cable and all worked great.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the pinout drawing for reference:
&lt;img alt=&#34;Pinout&#34; src=&#34;https://www.apalrd.net/posts/2023/newstor_com/pinout.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;proxmox-setup&#34;&gt;Proxmox Setup&lt;/h1&gt;
&lt;p&gt;Setup is really two steps - enabling kernel console via serial, and enabling a tty on that serial port. One of these requires editing the kernel &lt;code&gt;cmdline&lt;/code&gt; (Which can vary a bit - see &lt;a href=&#34;https://pve.proxmox.com/wiki/Host_Bootloader#sysboot_edit_kernel_cmdline&#34;&gt;Proxmox&amp;rsquo;s docs for more info&lt;/a&gt;), and the other requires using systemd.&lt;/p&gt;
&lt;p&gt;First, we need to add a new &lt;code&gt;console&lt;/code&gt; argument to the kernel cmdline. Default for this is &lt;code&gt;tty0&lt;/code&gt;, and we can add multiple arguments, so we should make sure both are specified. On my system I am using systemd-boot, so I edit the file &lt;code&gt;/etc/kernel/cmdline&lt;/code&gt; and add:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;console&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tty0 console&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ttyS0,115200n8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(ttyS0 should be &amp;lsquo;COM1&amp;rsquo; in Windows, and should be the COM port on the motherboard. You can also use USB Serial here if you need to, or any other serial ports you have available)&lt;/p&gt;
&lt;p&gt;Now, we just need to enable getty on our serial port so we have a proper login terminal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable serial-getty@ttyS0.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And reboot, watching boot messages on the console happily&lt;/p&gt;
&lt;p&gt;Of course, since Proxmox is Debian (with Ubuntu kernels), this should work on any of your other systems also Debian-based, as long as you are aware of the right place for the cmdline config (GRUB or Systemdboot).&lt;/p&gt;
&lt;h1 id=&#34;parts&#34;&gt;Parts&lt;/h1&gt;
&lt;p&gt;Some links to products may be affiliate links, which may earn a commission for me.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/40HxzJG&#34;&gt;Female 2x5 IDC Connector (50 pack)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3NmoXF8&#34;&gt;RJ45 Panel Mount Female Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/425p4cg&#34;&gt;RJ45 Console Cable to USB-A&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3AvGjrE&#34;&gt;RJ45 Console Cable to USB-C&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Network KVM for ALL of my Servers!</title>
      <link>https://www.apalrd.net/posts/2023/hdmi_kvm/</link>
      <pubDate>Thu, 13 Apr 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/hdmi_kvm/</guid>
      <description>Since I use a lot of repurposed computers as servers, I don&amp;rsquo;t have many with IPMI / remote access built in. Usually I can configure them remotely through SSH or their web UI, but sometimes things go wrong and it&amp;rsquo;s nice to have remote console access. Enter, PiKVM, a project to build a networked KVM switch with a Raspberry Pi. Unfortunately, I have a more than one server, and building a PiKVM for every one gets expensive, so I&amp;rsquo;m combining it with an 8 port rack mount KVM switch so I can remotely view and control all of the servers in my rack.</description>
      <content>&lt;p&gt;Since I use a lot of repurposed computers as servers, I don&amp;rsquo;t have many with IPMI / remote access built in. Usually I can configure them remotely through SSH or their web UI, but sometimes things go wrong and it&amp;rsquo;s nice to have remote console access. Enter, PiKVM, a project to build a networked KVM switch with a Raspberry Pi. Unfortunately, I have a more than one server, and building a PiKVM for every one gets expensive, so I&amp;rsquo;m combining it with an 8 port rack mount KVM switch so I can remotely view and control all of the servers in my rack.&lt;/p&gt;
&lt;p&gt;The KVM I&amp;rsquo;m using supports network control (but it&amp;rsquo;s not a network KVM, it can just switch inputs over the network) and I&amp;rsquo;ve configured that in this video.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/hdmi_kvm/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/hdmi_kvm/#networking-configuration&#34;&gt;Networking Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/hdmi_kvm/#pikvm-configuration&#34;&gt;PiKVM Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/jmwSfUyKC1Q&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/hdmi_kvm/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;networking-configuration&#34;&gt;Networking Configuration&lt;/h1&gt;
&lt;p&gt;The network configuration goes in &lt;code&gt;/etc/systemd/network/eth0.network&lt;/code&gt;. Make sure to run &lt;code&gt;rw&lt;/code&gt; to make the filesystem writeable before editing it, and &lt;code&gt;ro&lt;/code&gt; when you are done.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Match]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;eth0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Network]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;DHCP&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;DNSSEC&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Use DHCP for primary address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Add a static address in a /31 for the TESmart KVM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Address&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;192.168.1.11/31&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[DHCP]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Use same IP by forcing to use MAC address for clientID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ClientIdentifier&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;mac&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# https://github.com/pikvm/pikvm/issues/583&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;RouteMetric&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;pikvm-configuration&#34;&gt;PiKVM Configuration&lt;/h1&gt;
&lt;p&gt;The PiKVM configuration override goes in &lt;code&gt;/etc/kvmd/override.yaml&lt;/code&gt;. Make sure to run &lt;code&gt;rw&lt;/code&gt; to make the filesystem writeable before editing it, and &lt;code&gt;ro&lt;/code&gt; when you are done. I&amp;rsquo;m using the default IP of the Tesmart and a /31 subnet to avoid changing it, but if you do change the IP you&amp;rsquo;d change it here as well.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kvmd&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;gpio&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;drivers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;tes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tesmart&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.1.10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;scheme&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server0_led&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server0_switch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;switch&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server1_led&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server1_switch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;switch&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server2_led&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server2_switch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;switch&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server3_led&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server3_switch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;switch&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server4_led&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server4_switch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;switch&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server5_led&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server5_switch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;switch&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server6_led&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server6_switch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;switch&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server7_led&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;input&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;server7_switch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;pin&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;switch&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;view&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;table&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TESMART Switch&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#Terra NAS&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;server0_led, server0_switch|Switch]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#Megalab&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;server1_led, server1_switch|Switch]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#PVE1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;server2_led, server2_switch|Switch]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#PVE2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;server3_led, server3_switch|Switch]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#PVE3&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;server4_led, server4_switch|Switch]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#Minilab&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;server5_led, server5_switch|Switch]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#OPNsense&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;server6_led, server6_switch|Switch]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#Iridium&amp;#34;&lt;/span&gt;,  &lt;span style=&#34;color:#ae81ff&#34;&gt;server7_led, server7_switch|Switch]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Fully Routed Networks in Proxmox! Point-to-Point and Weird Cluster Configs Made Easy</title>
      <link>https://www.apalrd.net/posts/2023/cluster_routes/</link>
      <pubDate>Thu, 16 Mar 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/cluster_routes/</guid>
      <description>Are you playing with Proxmox clustering, but want faster networking without paying for multi-gig switches? For small clusters, sometimes it can make sense to use fast point to point links between nodes. This could be in a small 2 or 3 node cluster, where you can use dual port 10 gig cards and direct attach cables without a switch. Maybe you&amp;rsquo;ve got a wacky 5 node cluster with quad port gigabit cards on each node, and don&amp;rsquo;t want to buy a 20 port switch and do link aggregation.</description>
      <content>&lt;p&gt;Are you playing with Proxmox clustering, but want faster networking without paying for multi-gig switches? For small clusters, sometimes it can make sense to use fast point to point links between nodes. This could be in a small 2 or 3 node cluster, where you can use dual port 10 gig cards and direct attach cables without a switch. Maybe you&amp;rsquo;ve got a wacky 5 node cluster with quad port gigabit cards on each node, and don&amp;rsquo;t want to buy a 20 port switch and do link aggregation. Or maybe you want to be the crazy guy who uses intel NUCs with thunderbolt between them. Whatever your use case, this video will help you setup your fully routed cluster network properly.&lt;/p&gt;
&lt;p&gt;This is accomplished by creating point to point links between each node in any topology you can think of, and allowing OSPFv3 to exchange route information across all of the links. Once we have configured OSPF on all of the relevant interfaces, the cluster route map will automatically be generated and updated if any links go down and the shortest path will be chosen based on link speeds and priorities.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/cluster_routes/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/cluster_routes/#routed-cluster-subnet&#34;&gt;Routed Cluster Subnet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/cluster_routes/#routing-configuration&#34;&gt;Routing Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/cluster_routes/#full-example-config&#34;&gt;Full Example Config&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/dAjw_4EpQdk&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/cluster_routes/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;routed-cluster-subnet&#34;&gt;Routed Cluster Subnet&lt;/h1&gt;
&lt;p&gt;Our existing network has a subnet mask, something like 192.168.1.0/24 or 2000:db8::/64. To identify traffic on the cluster network, we are going to create a completely new subnet, in this example fd69:beef:cafe::/64. Only nodes in the cluster know about this second subnet, and traffic using this second subnet will go over our high speed backbone.&lt;/p&gt;
&lt;p&gt;Out of this subnet, we will assign an address to each node. In my case, I decided to use 551, 552, and 553 for the nodes.&lt;/p&gt;
&lt;p&gt;To setup the individual links, we just need to bring the interfaces up so a link-local address will be assigned automatically.&lt;/p&gt;
&lt;h1 id=&#34;routing-configuration&#34;&gt;Routing Configuration&lt;/h1&gt;
&lt;p&gt;We are going to use a package called free range routing for this, which implements the OSPFv3 protocol. So, naturally, we need to install it. &lt;code&gt;apt install frr -y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next we need to enable the OSPFv3 daemon in &lt;code&gt;/etc/frr/daemons&lt;/code&gt;. We could start it now, but we should probably configure it first.&lt;/p&gt;
&lt;p&gt;To configure FRR, edit &lt;code&gt;/etc/frr/frr.conf&lt;/code&gt;. I&amp;rsquo;m going to show this on the first node, but you&amp;rsquo;ll need to do this on all of your nodes with the specific interfaces on that node.&lt;/p&gt;
&lt;p&gt;Since Linux will route packets within the kernel (assuming routing is enabled), we can send packets destined to our cluster subnet on any interface and Linux will accept them. So, we don&amp;rsquo;t need to assign the address on the point to point links themselves, as long as they go across the right link. To make sure we can accept packets for our cluster network when any link is down, we are going to add our node address to the loopback interface. So, starting off the config file, we will add an address to the loopback interface. We will also add it to the zero-area and set it to passive since there&amp;rsquo;s no reason for OSPF to be active on this interface.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;interface lo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 address fd69:beef:cafe::551/128&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 area 0.0.0.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 passive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next up, we can add the existing gigabit interface as a backup. If there is no fast path to the other node, we can fall back on the &amp;lsquo;public&amp;rsquo; network. So, set up vmbr0 as a broadcast network like this. When setting cost you can choose any integer you want, the standard is to divide some reference bandwidth by the link speed, but the actual routing path used will be the path that results in the lowest cost across all links. In my example I set the backup cost to 100 and point to point cost to 10.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup links via primary gigabit link (vmbr0)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Cost for 1G assumptions (100 gig reference / 1 gig = 100 cost)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;interface vmbr0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 area 0.0.0.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 network broadcast&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 cost 100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now setup all of your point to point links. They can have a different cost if your interfaces have different bandwidths. Use the interface names here (use &lt;code&gt;ip a&lt;/code&gt; to find them).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;interface ens19&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 area 0.0.0.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 network point-to-point&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 cost 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, let&amp;rsquo;s setup the router. Set the router ID to something unique for each node, it can be whatever you want.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#OSPF router settings (unique router ID required for each router)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;router ospf6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ospf6 router-id 0.5.5.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;redistribute connected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;auto-cost reference-bandwidth 100000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, we can restart frr so it will come up with the new config - &lt;code&gt;systemctl restart frr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Within a few seconds of starting frr, routes should start coming in. Try viewing them with &lt;code&gt;ip -6 route&lt;/code&gt;, you should see something like &lt;code&gt;fd69 something via fe80 dev ens19 proto ospf&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&#34;full-example-config&#34;&gt;Full Example Config&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# default to using syslog. /etc/rsyslog.d/45-frr.conf places the log in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# /var/log/frr/frr.log&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Note:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# FRR&amp;#39;s configuration shell, vtysh, dynamically edits the live, in-memory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# configuration while FRR is running. When instructed, vtysh will persist the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# live configuration to this file, overwriting its contents. If you want to&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# avoid this, you can edit this file manually before starting FRR, or instruct&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# vtysh to write configuration to a different file.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;log syslog informational&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Enable IPv6 forwarding since we are using IPv6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 forwarding&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add our router&amp;#39;s private address on lo (loopback)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#This address is a single address (/128) out of the subnet (/64)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#of our &amp;#39;cluster&amp;#39; network, of which routes to individial /128s are&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#distributed using OSPF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;interface lo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 address fd69:beef:cafe::551/128&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 area 0.0.0.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 passive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup links via primary gigabit link (vmbr0)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Cost for 1G assumptions (100 gig reference / 1 gig = 100 cost)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;interface vmbr0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 area 0.0.0.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 network broadcast&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 cost 100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Two p2p links ens19 and ens20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Since we are using IPv6 we do not need to assign&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#addresses on these links, relying on link-local addresses&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Cost for 10G assumptions (100 gig reference / 10 gig = 10 cost)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Feel free to edit your cost as appropriate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#You can tweak these cost values to change the traffic flow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;interface ens19&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 area 0.0.0.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 network point-to-point&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 cost 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;interface ens20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 area 0.0.0.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 network point-to-point&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ipv6 ospf6 cost 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#OSPF router settings (unique router ID required for each router)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;router ospf6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;ospf6 router-id 0.5.5.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;redistribute connected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;auto-cost reference-bandwidth 100000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>One WiFi, Multiple Networks! Segment your WiFi Network with Private Pre-Shared-Keys</title>
      <link>https://www.apalrd.net/posts/2023/network_ppsk/</link>
      <pubDate>Thu, 09 Mar 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/network_ppsk/</guid>
      <description>Do you love segmenting your network into as many subnets and VLANs as possible? Do you have too many Wifi networks for all of your special flower IoT devices that can barely speak IP, let alone fend for themselves on the wild internet? You could use WPA EAP Enterprise Authentication, but good luck getting your smart toaster to log in. The solution I&amp;rsquo;m playing with is called Private Pre-Shared Keys, where each client can potentially have their own passphrase and VLAN assignment for the same SSID, and the client just has to support normal passphrase authentication.</description>
      <content>&lt;p&gt;Do you love segmenting your network into as many subnets and VLANs as possible? Do you have too many Wifi networks for all of your special flower IoT devices that can barely speak IP, let alone fend for themselves on the wild internet? You could use WPA EAP Enterprise Authentication, but good luck getting your smart toaster to log in. The solution I&amp;rsquo;m playing with is called Private Pre-Shared Keys, where each client can potentially have their own passphrase and VLAN assignment for the same SSID, and the client just has to support normal passphrase authentication.&lt;/p&gt;
&lt;p&gt;For this video, I&amp;rsquo;m using a Mikrotik wAP AC with RouterOS 7.8. I&amp;rsquo;d like to try OpenWRT in the future, but as of the making of this video it&amp;rsquo;s not quite ready.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ppsk/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ppsk/#full-mikrotik-config-export&#34;&gt;Full Mikrotik Config Export&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ppsk/#full-freeradius-configuration&#34;&gt;Full FreeRADIUS Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/gfNeCCurovs&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/network_ppsk/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;full-mikrotik-config-export&#34;&gt;Full Mikrotik Config Export&lt;/h1&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;/interface bridge
add ingress-filtering=no name=bridge vlan-filtering=yes
/interface wireless
set [ find default-name=wlan1 ] disabled=no mode=ap-bridge ssid=\
    SpaceLasers wps-mode=disabled
set [ find default-name=wlan2 ] disabled=no mode=ap-bridge ssid=\
    BillWiTheScienceFi wps-mode=disabled
/interface wireless security-profiles
set [ find default=yes ] authentication-types=wpa2-psk mode=dynamic-keys \
    radius-called-format=ssid radius-mac-authentication=yes \
    supplicant-identity=MikroTik tls-mode=dont-verify-certificate
/ip hotspot profile
set [ find default=yes ] html-directory=hotspot
/interface bridge port
add bridge=bridge interface=ether1
add bridge=bridge interface=wlan1
add bridge=bridge interface=wlan2
/interface bridge vlan
add bridge=bridge tagged=ether1,wlan2,wlan1 vlan-ids=9
/ipv6 address
add address=2001:db8:beef:cafe:ba69:f4ff:fe78:5a22 eui-64=yes interface=bridge
/radius
add address=2001:db8:beef:cafe::420 service=wireless
/system identity
set name=WAP
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;full-freeradius-configuration&#34;&gt;Full FreeRADIUS Configuration&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;authorize&lt;/code&gt; File:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;#MAC is a specific value, SSID has specific value
FC:D4:36:B3:00:33 Called-Station-ID == &amp;#34;BillWiTheScienceFi&amp;#34;, Auth-Type := Reject

#MAC has specific value, also pass a unique PSK and VLAN ID
FC:D4:36:B3:00:33 Called-Station-ID == &amp;#34;SpaceLasers&amp;#34;, Auth-Type := Accept
        Mikrotik-Wireless-Psk = &amp;#34;ClientKey&amp;#34;,
        Mikrotik-Wireless-VLANID = 9,

#MAC matches by OUI FC:D4:36 (Motorola, my test phone)
DEFAULT User-Name =~ &amp;#34;^FD:D4:36&amp;#34;, Auth-Type := Accept
        Mikrotik-Wireless-Psk = &amp;#34;Motorola&amp;#34;

#MAC is locally defined (starts with one of x2, 06, xA, xE))
DEFAULT User-Name =~ &amp;#34;^[\dA-F][26AE]&amp;#34;, Auth-Type := Accept
        Mikrotik-Wireless-Psk = &amp;#34;RandomKey&amp;#34;

#MAC is a specific value, reject user
FC:D4:36:B3:00:33 Auth-Type := Reject

#Any other users (you don&amp;#39;t have to accept them)
DEFAULT Auth-Type := Accept
        Mikrotik-Wireless-Forward = 1,
        Mikrotik-Wireless-Psk = &amp;#34;GenericKey&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Also, the &lt;code&gt;clients.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;client lan {
        ipaddr = 2601:40e:8101:6820::/64
        secret = CorrectHorseBatteryStaple
}
&lt;/code&gt;&lt;/pre&gt;</content>
    </item>
    
    <item>
      <title>Manage your Media Collection with Jellyfin! Install on Proxmox with Hardware Transcode</title>
      <link>https://www.apalrd.net/posts/2023/ultimate_jellyfin/</link>
      <pubDate>Thu, 23 Feb 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/ultimate_jellyfin/</guid>
      <description>In the last video I introduced Linux Containers, today we&amp;rsquo;re going to supercharge that by seeing if we can get some graphics hardware into our container, and give our large blu-ray collection a new home. We&amp;rsquo;re going to cover a few more advanced Proxmox container features, such as privilaged containers, hardware pass-through, and Jellyfin setup and transcoding for Intel and AMD GPUs.
There are always hardware quirks with hardware transcoding, but I&amp;rsquo;ve worked through it with two examples - a modern Intel Jasper Lake Celeron (which requires the guc/huc firmware), and an AMD Radeon WS3100.</description>
      <content>&lt;p&gt;In the last video I introduced Linux Containers, today we&amp;rsquo;re going to supercharge that by seeing if we can get some graphics hardware into our container, and give our large blu-ray collection a new home. We&amp;rsquo;re going to cover a few more advanced Proxmox container features, such as privilaged containers, hardware pass-through, and Jellyfin setup and transcoding for Intel and AMD GPUs.&lt;/p&gt;
&lt;p&gt;There are always hardware quirks with hardware transcoding, but I&amp;rsquo;ve worked through it with two examples - a modern Intel Jasper Lake Celeron (which requires the guc/huc firmware), and an AMD Radeon WS3100.&lt;/p&gt;
&lt;p&gt;This video is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2023/ultimate/&#34;&gt;Ultimate Home Server Megaproject&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/tWumbDlbzLY&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_jellyfin/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Welcome to the Editing Den! My Editing Workflow</title>
      <link>https://www.apalrd.net/posts/2023/studio_editing/</link>
      <pubDate>Thu, 16 Feb 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/studio_editing/</guid>
      <description>Today, I&amp;rsquo;m going on a tour of my editing den, and the process I go through to take footage of stuff and turn it into a final video for you all. So come along on this behind the scenes adventure!
Video Ingest The first step in my editing workflow is ingest. I have footage from a variety of devices and SD cards, and I need to get it onto a reliable storage as quickly as possible.</description>
      <content>&lt;p&gt;Today, I&amp;rsquo;m going on a tour of my editing den, and the process I go through to take footage of stuff and turn it into a final video for you all. So come along on this behind the scenes adventure!&lt;/p&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/Uu3kWtEXFps&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/studio_editing/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;ingest&#34;&gt;Ingest&lt;/h2&gt;
&lt;p&gt;The first step in my editing workflow is ingest. I have footage from a variety of devices and SD cards, and I need to get it onto a reliable storage as quickly as possible.&lt;/p&gt;
&lt;p&gt;With the equipment I have, I really have four types of files.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Footage from my Nikon camera is in h.264 format on SD cards&lt;/li&gt;
&lt;li&gt;Audio from the DJI Mic is in uncompressed wav internal to the device&lt;/li&gt;
&lt;li&gt;Footage from my iPhone is on the iPhone and needs to be copied over the network&lt;/li&gt;
&lt;li&gt;Screen capture of tutorials is captured in h.264 using OBS, on my local SSD&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the camera and mic, ingesting the footage means plugging the card into my desktop and copying the files. Since the MOV and WAV files are both compatible with Resolve directly, I copy these files straight into the working folder on my NAS for this video.&lt;/p&gt;
&lt;p&gt;For the iPhone, it&amp;rsquo;s recorded in h.265, which isn&amp;rsquo;t compatible with the free version of Davinci Resolve. I haven&amp;rsquo;t bought a license yet since I want to try out the Linux version first before locking a license down to a single computer. So, using the native Files app, I copy the files into a big &amp;lsquo;iphone&amp;rsquo; folder, where I can transcode them. I use Handbrake to transcode them down to h.264, and the resulting files go into the video&amp;rsquo;s working folder.&lt;/p&gt;
&lt;p&gt;At this point, all of my footage is relatively safe on my NAS, stored on a ZFS mirror. I still keep the original footage on the card for now, until the nightly backup runs and I&amp;rsquo;m sure the footage is definitely safe. If I were to have a drive failure or NAS failure before the nightly backup runs, I&amp;rsquo;d still have the originals on the SD card.&lt;/p&gt;
&lt;h2 id=&#34;workstatio-and-peripherals&#34;&gt;Workstatio and Peripherals&lt;/h2&gt;
&lt;p&gt;As for the workstaion itself, my editing beast is a first-gen AMD Ryzen Threadripper 1950x, and it&amp;rsquo;s great at rendering and transcoding as well as virtualization. I like to use an ultrawide as my main monitor, so I have a 29&amp;quot; 21:9 monitor paired with a 24&amp;quot; 16:9 side monitor. It&amp;rsquo;s  plenty of real estate for a video timeline or immersive game.&lt;/p&gt;
&lt;p&gt;While I&amp;rsquo;ll usually write scripts on my laptop, which can sit on the corner of the desk, I have a very clicky typing keyboard made by Unicomp, paired with an ergonomic vertical mouse by Logitech.&lt;/p&gt;
&lt;p&gt;The whole environment is tucked neatly into a closet, with LED lighting that I&amp;rsquo;ve installed for both atmosphere and recording. These are controlled by a QuinLED board via Home Assistant, and can be controlled from the Stream Deck.&lt;/p&gt;
&lt;h2 id=&#34;screen-capture&#34;&gt;Screen Capture&lt;/h2&gt;
&lt;p&gt;Since most of my videos are software tutorials, they tend to include a lot of screen capture segments. For these, I film at my desk, and the workflow is a bit different from the other video segments.&lt;/p&gt;
&lt;p&gt;Screen capture is done in OBS, the open broadcaster software.&lt;/p&gt;
&lt;p&gt;During sessions, I rely heavily on my Stream Deck to control OBS. I usually use my side monitor with display scaling set to 150% to better accomodate viewers at lower resolutions or on smaller screens. Overlaying my face is done live in OBS, and I can turn it on and off with my Stream Deck. I use Edge as my web browser in all of my tutorials, and I reset it to defaults before each video.&lt;/p&gt;
&lt;p&gt;After a recording session, program output gets copied to the working folder on the NAS as usual.&lt;/p&gt;
&lt;h2 id=&#34;editing-workflow&#34;&gt;Editing Workflow&lt;/h2&gt;
&lt;p&gt;At this point, all of my footage is in the working folder on the NAS. I import it into Davinci Resolve directly, so I&amp;rsquo;m editing directly over the network and not copying anything back and forth.&lt;/p&gt;
&lt;p&gt;Since I have 5 gigabit Ethernet between my workstation and my switch, and 10 gig from there to the NAS, and I edit at 1080p with 1080p footage, I haven&amp;rsquo;t found a need to transcode to a mezzanine codec such as ProRes or generate proxies. In general the ZFS ARC hit rate on my NAS is extremely high during editing sessions so the speed of the spinning drives isn&amp;rsquo;t a bottleneck. I&amp;rsquo;ll probably re-evaluate all of these choices if I upgrade to equipment that can do 4K, but for the types of content I produce that isn&amp;rsquo;t necessary right now.&lt;/p&gt;
&lt;p&gt;While I usually don&amp;rsquo;t generate proxies, timelapse segments in particular do stutter in the preview window. Resolve makes it pretty easy to right-click on a clip and generate optimized media as needed, which is basically a proxy. This takes quite a bit of space, with the timelapse clips for this project taking over 12 gigs at half resolution! But it does make it way nicer to scrub through clips with speed changes. So maybe I&amp;rsquo;ll reconsider my decision not to render proxies after all.&lt;/p&gt;
&lt;p&gt;I use a single project in Resolve for all of my videos, with bins for different categories and videos. I haven&amp;rsquo;t really seen any suggestion on one project vs multiple and I find it easier to be able to grab clips and bits from other videos. Experts will probably disagree on this choice, and I&amp;rsquo;d love it if you did to boost engagement.&lt;/p&gt;
&lt;p&gt;When I have all of the footage imported, I start by combining multiple files of the same shot into multicam clips. Most of my clips are actually multicam clips, since I add the audio track from the mics as another camera angle, but sometimes I also have as many as 3 real cameras. Resolve makes it easy to sync by audio automatically, and like magic I have a multicam clip and can independently select the video and audio angle shot by shot.&lt;/p&gt;
&lt;p&gt;Once all of the multicams are syncd, I categorize clips into A-roll, B-roll, and screencap and may rename clips in the editor based on what makes sense. This is all purely in Resolve, the original filenames are still kept on disk.&lt;/p&gt;
&lt;p&gt;Finally, I can start dropping stuff on the timeline. Usually I work from start to finish in a single editing session, although sometimes I take a break if I feel like I need to shoot a follow-up or more content. I have a few videos that have been sitting half-finished for months now, so you&amp;rsquo;ll see those eventually.&lt;/p&gt;
&lt;h2 id=&#34;rendering&#34;&gt;Rendering&lt;/h2&gt;
&lt;p&gt;After editing is done, it&amp;rsquo;s time to render out the project. I use the YouTube preset and tweaked it a little. Youtube is going to end up transcoding from this down to all of the resolutions they support, so I&amp;rsquo;d like to use the highest reasonable bitrate to reduce the quality loss through that process. I save the file as an mp4 and click the button. Then, as the CPU goes to town and has fun, I wait for it to finish so I can upload it to Youtube. I name the final files with a major number and minor letter and keep all finished renders, even if they aren&amp;rsquo;t the final upload. For major changes, I&amp;rsquo;ll create a duplicate timeline for V2 and beyond.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>I spent a WEEK without IPv4 to understand IPv6 transition mechanisms</title>
      <link>https://www.apalrd.net/posts/2023/network_ipv6/</link>
      <pubDate>Thu, 09 Feb 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/network_ipv6/</guid>
      <description>The time has come to talk about something uncomfortable to a lot of you. You&amp;rsquo;ve been using legacy methods for far too long. It&amp;rsquo;s time to move to IPv6.
But, of course, there&amp;rsquo;s a lot more to IPv6 than &amp;lsquo;just&amp;rsquo; switching everything over. A lot of systems in the world still haven&amp;rsquo;t adopted it after nearly 25 years, and although software support is virtually a requirement these days, that doesn&amp;rsquo;t mean it&amp;rsquo;s widely enabled.</description>
      <content>&lt;p&gt;The time has come to talk about something uncomfortable to a lot of you. You&amp;rsquo;ve been using legacy methods for far too long. It&amp;rsquo;s time to move to IPv6.&lt;/p&gt;
&lt;p&gt;But, of course, there&amp;rsquo;s a lot more to IPv6 than &amp;lsquo;just&amp;rsquo; switching everything over. A lot of systems in the world still haven&amp;rsquo;t adopted it after nearly 25 years, and although software support is virtually a requirement these days, that doesn&amp;rsquo;t mean it&amp;rsquo;s widely enabled. There are also still a lot of misconceptions from network administrators who are scared of or don&amp;rsquo;t properly understand IPv6, and I want to address all of that.&lt;/p&gt;
&lt;p&gt;But, for me to describe to you the best setup for your networks going forward, I need to understand for myself how all of the IPv6 transition mechanisms and behaviors work. To understand where transition mechanisms fail, I&amp;rsquo;m spending a fully week with only IPv6 and reporting on what works and doesn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;At the start of this, I&amp;rsquo;d like to absolutely stress that the NAT you know and hate was not imagined when the Internet Protocol was created, and in many ways has introduced a huge amount of headache in routing. You should stop thinking of NAT as a security mechanism and think of it as the emergency address exhaustion prevention that it is. Likewise, CG-NAT is a dire emergency address exhaustion prevention mechnism that nobody really wants to deploy unless they absolutely must. Don&amp;rsquo;t blame your provider when they deploy CG-NAT, embrace IPv6 and global routing instead.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ipv6/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ipv6/#crash-course-on-ipv6&#34;&gt;Crash Course on IPv6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ipv6/#advantages-for-the-homelab&#34;&gt;Advantages for the Homelab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ipv6/#transition-mechanisms&#34;&gt;Transition Mechanisms&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ipv6/#dual-stack&#34;&gt;Dual Stack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ipv6/#stateless-ipicmp-translation&#34;&gt;Stateless IP/ICMP Translation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ipv6/#nat64&#34;&gt;NAT64&lt;/a&gt; - the method I&amp;rsquo;ve setup for this test&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ipv6/#464xlat&#34;&gt;464XLAT&lt;/a&gt; - the method I ended up using on macOS/iOS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/network_ipv6/#lessons-learned&#34;&gt;Lessons Learned&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;TBD&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/network_ipv6/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;crash-course-on-ipv6&#34;&gt;Crash Course on IPv6&lt;/h1&gt;
&lt;p&gt;The biggest hurdle to implementing IPv6 on your own isn&amp;rsquo;t usually ISP support, router support, or client support. It&amp;rsquo;s the mental thought process behind un-learning the legacy methods of network design. With IPv6, we aren&amp;rsquo;t just copying the mistakes of IPv4 and adding a wider address space, we&amp;rsquo;re going back to how the internet protocol was intended to behave before we started running out of addresses, getting rid of network address translation, and generally adding a stronger focus on proper subnet design and routing.&lt;/p&gt;
&lt;p&gt;So, here are a few quick notes that can are crucial in understanding IPv6:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Addresses are 128 bits long and written as 8 four-letter hex blocks separated by colons (i.e. &lt;code&gt;fd69:beef:cafe:feed:face:6969:0420:0001&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Leading zeros can be omitted (i.e. &lt;code&gt;0420&lt;/code&gt; can become &lt;code&gt;420&lt;/code&gt;, but not &lt;code&gt;42&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Groups of zeros can be omitted with two colons, but only once in an address (i.e. &lt;code&gt;2000:1::1&lt;/code&gt;, but not &lt;code&gt;2000::1::1&lt;/code&gt; as that is ambiguous)&lt;/li&gt;
&lt;li&gt;Network prefixes are (virtually) always 64 bits long, with a 64-bit client suffix, using CIDR notation (i.e. &lt;code&gt;2000::/3&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;All addresses should be treated as if they are globally unique, even if they are only within our organization&lt;/li&gt;
&lt;li&gt;You are encouraged to have as many addresses as you want on a single interface, for different purposes or scopes&lt;/li&gt;
&lt;li&gt;Similarly, we can have multiple routers advertising prefixes on the same layer 2 domain, and this is also encouraged&lt;/li&gt;
&lt;li&gt;We no longer need to centrally assign addresses via DHCP, since nodes can now assign themselves addresses in the vast 64-bit local client space&lt;/li&gt;
&lt;li&gt;Since everything is globally routable and unique, we have no need to do network address translation or port forwarding&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;advantages-for-the-homelab&#34;&gt;Advantages for the Homelab&lt;/h1&gt;
&lt;p&gt;A question I get over and over when I bring up IPv6 is &amp;lsquo;what advantages does this bring to my home lab network&amp;rsquo;. So, here are some reasons you should start using IPv6 within your own network:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you are behind carrier-grade NAT on IPv4, your IPv6 connectivity will still be globally routable and can receive incoming connections such as VPNs or game servers. I&amp;rsquo;ve found that I can host servers on a mobile hotspot using IPv6&lt;/li&gt;
&lt;li&gt;Peer-to-peer communications such as gaming usually have to deal with NAT traversal, but with IPv6 this is no longer an issue, especially for multiple gamers using the same connection&lt;/li&gt;
&lt;li&gt;IPSec VPN is widely used but often performs poorly as it struggles to traverse NAT, so like gaming this is not an issue with IPv6&lt;/li&gt;
&lt;li&gt;Since we always have a link-local address, we don&amp;rsquo;t need to assign addresses at all on point-to-point links or isolated networks&lt;/li&gt;
&lt;li&gt;If you want to host services, you don&amp;rsquo;t need to use different ports or a reverse proxy to separate traffic out of the single port on the singlular WAN address&lt;/li&gt;
&lt;li&gt;This same advantage applies to single servers, where you can assign multiple addresses for different services, potentially using the same port&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;transition-mechanisms&#34;&gt;Transition Mechanisms&lt;/h1&gt;
&lt;p&gt;The primary methods of transition are Dual-Stack, SIIT, NAT64, and 464XLAT, each of which increases in complexity and has different advantages.&lt;/p&gt;
&lt;h2 id=&#34;dual-stack&#34;&gt;Dual Stack&lt;/h2&gt;
&lt;p&gt;In most cases, you will end up deploying dual-stack networks. With this setup, both IPv4 and IPv6 are completely deployed across the entire network. Resources are accessible via one or the other IP version, all network segments must be assigned both an IPv4 and IPv6 subnet, and all routers must have routing tables for both IPv4 and IPv6. Clients may choose to access any resource via either IP version, likely receiving both A and AAAA records for destinations. As you can see, this is manageable for home networks of only one router but generally is difficult to scale. However, it&amp;rsquo;s the easiest way to deploy IPv6 in your home network or small organization.&lt;/p&gt;
&lt;h2 id=&#34;stateless-ipicmp-translation&#34;&gt;Stateless IP/ICMP Translation&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d like to avoid duplicating routing tables and all of your routing configuration, you can transition fully to IPv6, and statelessly translate between IPv4 and IPv6 at the edge of your network. This method is known as &amp;lsquo;Stateless IP/ICMP Translation&amp;rsquo; and is most suited for applications where each device which needs to access the public IPv4 internet has a public IPv4 address, such as datacenters. This way, the IPv4 public addresses can be statelessly translated 1:1 to IPv6 destinations and relayed to IPv6-only servers, allowing the datacenter to operate fully IPv6 internally while still providing access to public IPv4 clients. However, this method does not perform traditional source NAT / masquarade as would normally be used in IPv4 networks.&lt;/p&gt;
&lt;h2 id=&#34;nat64&#34;&gt;NAT64&lt;/h2&gt;
&lt;p&gt;Another mechanism is NAT64. This operates similarly to &amp;rsquo;legacy&amp;rsquo; IPv4 NAT, in that we have a pool of addresses which we are masquarading behind a single public address. However, in our case, the address pool is IPv6 and the public address is IPv4. So, the NAT64 server takes requests from native IPv6 clients with the destination IPv4 address encoded into the destination IPv6 address (possibly using the well-known prefix &lt;code&gt;64:ff9b::/96&lt;/code&gt; and adding the 32-bit IPv4 on the end). It then performs both protocol, address, and port translation as it would in IPv4 NAT, and outgoing connections depart the NAT64 server appearing as a normal network behind a single public IPv4. The downside to this is that clients need to know that they should be connecting to IPv4 destinations. Like traditional NAT, this is a stateful transition and imposes the NAT64 gateway as a potential choke point on the network (as the NAT service always has been).&lt;/p&gt;
&lt;p&gt;The most common mechanism used alongside NAT64 is DNS64. In this transition mechansim, the DNS sever is aware that it&amp;rsquo;s serving an IPv6-only network and the prefix in use for NAT64 translation. If a DNS server encounters a query which has no AAAA record but does have a valid A record, it will synthesize an AAAA record by combining the A record with the NAT64 prefix. Now, any client software which utilizes DNS will automatically connect to the NAT64 gateway for access to the IPV4 internet via IPv6.&lt;/p&gt;
&lt;h2 id=&#34;464xlat&#34;&gt;464XLAT&lt;/h2&gt;
&lt;p&gt;In addition to DNS64, the final mechanism which can be deployed in a NAT64 network is known as &amp;lsquo;464XLAT&amp;rsquo;. Conceptually it&amp;rsquo;s nearly identical to a combination of NAT64 at the network level and SIIT at the individual device level (4-&amp;gt;6 1:1 followed by 6-&amp;gt;4 NAT), although different terminology is often used due to the different organizations which developed this. The NAT64 server at the edge of the network usually performs client NAT or CG-NAT, and is known as the &amp;lsquo;PLAT&amp;rsquo; (Provider side transLATor). Each client then runs its own &amp;lsquo;CLAT&amp;rsquo; (Client side transLATor), which self-assigns an IPv4 address in its networking stack as well as an IPv6 address to communicate with the PLAT. Client applications which send packets using IPv4 see the CLAT&amp;rsquo;s IPv4 as the default IPv4 route, and the CLAT then performs stateless 4-&amp;gt;6 translation. This removes or reduces the need for DNS64, imposes similar network requirements for a NAT64 gateway, and allows compatible clients to perform IPv4-&amp;gt;IPv6 translation if they need direct IPv4 communication. This is usually the method used within ISP networks, as their NAT64/PLAT entity would already be required as a CG-NAT gateway and they can implement the CLAT service on their modem/gateway to provide the appearance of end-to-end IPv4 to clients with no downsides.&lt;/p&gt;
&lt;p&gt;On our own networks, using 464XLAT is mostly limited by client software support. iOS and macOS both have native CLAT functions which will automatically activate, but older versions of macOS and essentially every other OS currently in use do not automatically function. That said, it&amp;rsquo;s possible to deploy both 464XLAT and DNS64 on the same network easily, so clients without native 464XLAT support will fall back on DNS64 and only have issues with IPv4 literals in certain peer-to-peer software.&lt;/p&gt;
&lt;h1 id=&#34;lessons-learned&#34;&gt;Lessons Learned&lt;/h1&gt;
&lt;p&gt;A summary of the lessons I learned in my week without IPv4:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IPv6 is absolutely ready for prime-time and has been for awhile&lt;/li&gt;
&lt;li&gt;About half of the internet sites I rely on support IPv6 natively, so there needs to be more pressure on site admins and CDNs to support IPv6 natively&lt;/li&gt;
&lt;li&gt;There seems to be a lack of drive (judging by forum posts) to enable IPv6 on internet services by admins, either because they don&amp;rsquo;t care to, or it&amp;rsquo;s more work to manage a public IPv4 and public IPv6 presence&lt;/li&gt;
&lt;li&gt;Networks should be designed IPv6-first instead of IPv4-first, and this design approach largely solves most of the major issues&lt;/li&gt;
&lt;li&gt;NAT64 should replace traditional NAT in network architectures and is essentially a drop-in replacement pending better software support by routers&lt;/li&gt;
&lt;li&gt;DNS64 alone is a mostly usable transition mechanism and is probably &amp;rsquo;enough&amp;rsquo; for public Wifi or other well-managed networks where you know what services are important to you or don&amp;rsquo;t mind peer-to-peer IPv4 addresses failing&lt;/li&gt;
&lt;li&gt;464XLAT is a solution with no user-visible downsides and is the way ISP networks should be deployed going forward, combined with CG-NAT&lt;/li&gt;
&lt;li&gt;Apple has excellent IPv6 support on their devices, fully supporting automatic configuration of 464XLAT on devices with NAT64, and overall an excellent attitude to forcing IPv6 support from developers&lt;/li&gt;
&lt;li&gt;Other operating systems are bit of hit or miss&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Linux VM Templates in Proxmox on EASY MODE using Prebuilt Cloud Init Images!</title>
      <link>https://www.apalrd.net/posts/2023/pve_cloud/</link>
      <pubDate>Thu, 02 Feb 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/pve_cloud/</guid>
      <description>Have you ever wanted a nice, easy way to create new VMs to play with using your favorite base distro, without doing a lot of work to configure basic settings like your account, networking, hostname, etc?
Cloud-Init can do all of that and more, but it&amp;rsquo;s designed more for big cloud providers and not the easiest thing to setup. But, what if we could take a generic cloud image, and use it with Proxmox&amp;rsquo;s built-in Cloud-Init automation, to provision easy bare VMs without having to build our own templates?</description>
      <content>&lt;p&gt;Have you ever wanted a nice, easy way to create new VMs to play with using your favorite base distro, without doing a lot of work to configure basic settings like your account, networking, hostname, etc?&lt;/p&gt;
&lt;p&gt;Cloud-Init can do all of that and more, but it&amp;rsquo;s designed more for big cloud providers and not the easiest thing to setup. But, what if we could take a generic cloud image, and use it with Proxmox&amp;rsquo;s built-in Cloud-Init automation, to provision easy bare VMs without having to build our own templates? That&amp;rsquo;s what I&amp;rsquo;ve done, and I&amp;rsquo;ve written a script to automate downloading these templates on new Proxmox systems from the major distros which provide them (Debian, Ubuntu, Fedora).&lt;/p&gt;
&lt;p&gt;Of course, once cloud-init is installed and configured, there&amp;rsquo;s no reason we can&amp;rsquo;t clone a template, install software on it, and then clone the clone to have a newly-configured VM with more software installed. From here, you can build out your library of useful application templates for whatever you do regularly.&lt;/p&gt;
&lt;h2 id=&#34;the-video&#34;&gt;The Video&lt;/h2&gt;
&lt;p&gt;As always, here&amp;rsquo;s the video with the full instructions.
&lt;a href=&#34;https://youtu.be/E7rv08ttv8k&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/pve_cloud/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-script&#34;&gt;The Script&lt;/h2&gt;
&lt;p&gt;This script will download a bunch of premade cloud images from the most common Linux distributions and add them as new 900-numbered VM templates, import your SSH keys, and configure the VM how I like it as a template. Of course, feel free to change any of the settings in the script before you run it, and you&amp;rsquo;ll need to add your public key in a plain text file and set your username.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#args:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# vm_id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# vm_name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# file name in the current directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; create_template&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Print all of the configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Creating template &lt;/span&gt;$2&lt;span style=&#34;color:#e6db74&#34;&gt; (&lt;/span&gt;$1&lt;span style=&#34;color:#e6db74&#34;&gt;)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Create new VM &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Feel free to change any of these to your liking&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm create $1 --name $2 --ostype l26 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Set networking to default bridge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm set $1 --net0 virtio,bridge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vmbr0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Set display to serial&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm set $1 --serial0 socket --vga serial0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Set memory, cpu, type defaults&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#If you are in a cluster, you might need to change cpu type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm set $1 --memory &lt;span style=&#34;color:#ae81ff&#34;&gt;1024&lt;/span&gt; --cores &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; --cpu host
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Set boot device to new file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm set $1 --scsi0 &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;storage&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;:0,import-from&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;pwd&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/&lt;/span&gt;$3&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;,discard&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;on
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Set scsi hardware as default boot disk using virtio scsi single&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm set $1 --boot order&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;scsi0 --scsihw virtio-scsi-single
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Enable Qemu guest agent in case the guest has it available&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm set $1 --agent enabled&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;1,fstrim_cloned_disks&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Add cloud-init device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm set $1 --ide2 &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;storage&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;:cloudinit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Set CI ip config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#IP6 = auto means SLAAC (a reliable default with no bad effects on non-IPv6 networks)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#IP = DHCP means what it says, so leave that out entirely on non-IPv4 networks to avoid DHCP delays&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm set $1 --ipconfig0 &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ip6=auto,ip=dhcp&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Import the ssh keyfile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm set $1 --sshkeys &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;ssh_keyfile&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#If you want to do password-based auth instaed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Then use this option and comment out the line above&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#qm set $1 --cipassword password&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Add the user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm set $1 --ciuser &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;username&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Resize the disk to 8G, a reasonable minimum. You can expand it more later.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#If the disk is already bigger than 8G, this will fail, and that is okay.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm disk resize $1 scsi0 8G
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Make it a template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qm template $1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Remove file when done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rm $3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Path to your ssh authorized_keys file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Alternatively, use /etc/pve/priv/authorized_keys if you are already authorized&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#on the Proxmox system&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export ssh_keyfile&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/root/.ssh/id_rsa.pub
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Username to create on VM template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export username&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;apalrd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Name of your storage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export storage&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;local-zfs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The images that I&amp;#39;ve found premade&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Feel free to add your own&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Debian&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Buster (10) (really old at this point)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#wget &amp;#34;https://cloud.debian.org/images/cloud/buster/latest/debian-10-genericcloud-amd64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#create_template 900 &amp;#34;temp-debian-10&amp;#34; &amp;#34;debian-10-genericcloud-amd64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Bullseye (11) (oldoldstable)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#wget &amp;#34;https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#create_template 901 &amp;#34;temp-debian-11&amp;#34; &amp;#34;debian-11-genericcloud-amd64.qcow2&amp;#34; &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Bookworm (12) (oldstable)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;902&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-debian-12&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;debian-12-genericcloud-amd64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Trixie (13) (stable)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;903&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-debian-13&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;debian-13-genericcloud-amd64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sid (unstable)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://cloud.debian.org/images/cloud/sid/daily/latest/debian-sid-genericcloud-amd64-daily.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;909&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-debian-sid&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;debian-sid-genericcloud-amd64-daily.qcow2&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Ubuntu&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#20.04 (Focal Fossa) LTS (really old at this point)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#wget &amp;#34;https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64.img&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#create_template 910 &amp;#34;temp-ubuntu-20-04&amp;#34; &amp;#34;ubuntu-20.04-server-cloudimg-amd64.img&amp;#34; &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#22.04 (Jammy Jellyfish) LTS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;911&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-ubuntu-22-04&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ubuntu-22.04-server-cloudimg-amd64.img&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#24.04 (Noble Numbat) LTS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;912&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-ubuntu-24-04&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ubuntu-24.04-server-cloudimg-amd64.img&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Fedora 41&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://mirror.accum.se/mirror/fedora/linux/releases/41/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;921&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-fedora-37&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Fedora 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://mirror.accum.se/mirror/fedora/linux/releases/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;922&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-fedora-38&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Rocky Linux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Rocky 8 latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://dl.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud.latest.x86_64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;930&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-rocky-8&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Rocky-8-GenericCloud.latest.x86_64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Rocky 9 latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;931&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-rocky-9&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Rocky-9-GenericCloud.latest.x86_64.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Alpine Linux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Alpine 3.22.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://dl-cdn.alpinelinux.org/alpine/v3.22/releases/cloud/generic_alpine-3.22.0-x86_64-bios-cloudinit-r0.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;940&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-alpine-3.22&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;generic_alpine-3.22.0-x86_64-bios-cloudinit-r0.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## FreeBSD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#FreeBSD 14.2 RELEASE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Despite the images being named CLOUDINIT, they do not actually use cloud-init&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#the default account is freebsd password freebsd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://download.freebsd.org/releases/VM-IMAGES/14.2-RELEASE/amd64/Latest/FreeBSD-14.2-RELEASE-amd64-BASIC-CLOUDINIT.ufs.qcow2.xz&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;xz -d -v &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FreeBSD-14.2-RELEASE-amd64-BASIC-CLOUDINIT.ufs.qcow2.xz&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create_template &lt;span style=&#34;color:#ae81ff&#34;&gt;960&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-freebsd-14.2&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FreeBSD-14.2-RELEASE-amd64-BASIC-CLOUDINIT.ufs.qcow2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Making Proxmox into a pretty good NAS</title>
      <link>https://www.apalrd.net/posts/2023/ultimate_nas/</link>
      <pubDate>Thu, 26 Jan 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/ultimate_nas/</guid>
      <description>Continuing the series where apalrd teaches proxmox skills through meaningful applications, today we are setting up a proper fileserver on our Proxmox system using Linux Containers. I&amp;rsquo;ve chosen to use a lightweight Linux Container (LXC) for this, so we can share the host&amp;rsquo;s ZFS filesystem. To manage shares and users using a web UI, I&amp;rsquo;m installing Cockpit, as well as some additional modules from 45Drives to deal with Samba. This should provide a pretty easy to use storage interface, keep all of our storage contained in the host Proxmox system without adding another layer of filesystem or a virtual machine, and run well on lower end hardware such as the Terramaster unit I&amp;rsquo;m using.</description>
      <content>&lt;p&gt;Continuing the series where apalrd teaches proxmox skills through meaningful applications, today we are setting up a proper fileserver on our Proxmox system using Linux Containers. I&amp;rsquo;ve chosen to use a lightweight Linux Container (LXC) for this, so we can share the host&amp;rsquo;s ZFS filesystem. To manage shares and users using a web UI, I&amp;rsquo;m installing Cockpit, as well as some additional modules from 45Drives to deal with Samba. This should provide a pretty easy to use storage interface, keep all of our storage contained in the host Proxmox system without adding another layer of filesystem or a virtual machine, and run well on lower end hardware such as the Terramaster unit I&amp;rsquo;m using.&lt;/p&gt;
&lt;p&gt;This video is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2023/ultimate/&#34;&gt;Ultimate Home Server Megaproject&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_nas/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_nas/#cockpit-setup&#34;&gt;Cockpit Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_nas/#cockpit-modules&#34;&gt;Cockpit Modules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/Hu3t8pcq8O0&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_nas/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;cockpit-setup&#34;&gt;Cockpit Setup&lt;/h1&gt;
&lt;p&gt;I started with Debian 11 (Bullseye), although 12 (Bookworm) has now released and you should use that instead.&lt;/p&gt;
&lt;p&gt;In the video I described how to add the bullseye-backports repository to &lt;code&gt;/etc/apt/sources.list&lt;/code&gt;, however, as of the release of Bookworm this is no longer necesary to do. We also no longer need to specify the repository during installation, as it&amp;rsquo;s part of the normal Bookworm repos.&lt;/p&gt;
&lt;p&gt;So here&amp;rsquo;s the command to install Cockpit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install --no-install-recommends cockpit -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After Cockpit is installed, we can allow root access (temporarily, while we setup more users). To do that, edit &lt;code&gt;/etc/cockpit/disallowed-users&lt;/code&gt; and comment out the entry &lt;code&gt;root&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;At this point, you can connect to cockpit at https://&lt;IP&gt;:9090 and login with your root credentials, and it should work.&lt;/p&gt;
&lt;h1 id=&#34;cockpit-modules&#34;&gt;Cockpit Modules&lt;/h1&gt;
&lt;p&gt;Next, install the three modules from 45Drives:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/45Drives/cockpit-file-sharing&#34;&gt;45Drives Cockpit File Sharing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/45Drives/cockpit-navigator&#34;&gt;45Drives Cockpit Navigator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/45Drives/cockpit-identities&#34;&gt;45Drives Cockpit Identities&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As of this last update, here are the commands to download and install the most recent versions. Make sure you update these with the latest versions before you download!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Download Cockpit File Sharing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://github.com/45Drives/cockpit-file-sharing/releases/download/v4.2.8/cockpit-file-sharing_4.2.8-1focal_all.deb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Download Cockpit Navitator&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://github.com/45Drives/cockpit-navigator/releases/download/v0.5.10/cockpit-navigator_0.5.10-1focal_all.deb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Download Cockpit Identities&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://github.com/45Drives/cockpit-identities/releases/download/v0.1.12/cockpit-identities_0.1.12-1focal_all.deb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install them&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install ./*.deb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#It will complain about being unable to delete the deb files, so we will do that now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm ./*.deb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>FIXING my USB3 2.5Gbe network adapters on Linux / Proxmox!</title>
      <link>https://www.apalrd.net/posts/2023/network_realtek8156/</link>
      <pubDate>Thu, 19 Jan 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/network_realtek8156/</guid>
      <description>Do you have a USB3 2.5Gbe network adapter that doesn&amp;rsquo;t work well in Linux? Well, the kernel has included the upgraded Realtek drivers for awhile now, but for some reason it needs additional udev rules to load correctly. It&amp;rsquo;s a pretty simple fix and results in dramatically improved bandwidth (full duplex ~1.5Gbps and half duplex ~1.9Gbps), and functions properly with the correct driver.
tl;dr if you&amp;rsquo;re on a Debian-based system (including Proxmox) create the udev file below and reboot, and it should work fine.</description>
      <content>&lt;p&gt;Do you have a USB3 2.5Gbe network adapter that doesn&amp;rsquo;t work well in Linux? Well, the kernel has included the upgraded Realtek drivers for awhile now, but for some reason it needs additional udev rules to load correctly. It&amp;rsquo;s a pretty simple fix and results in dramatically improved bandwidth (full duplex ~1.5Gbps and half duplex ~1.9Gbps), and functions properly with the correct driver.&lt;/p&gt;
&lt;p&gt;tl;dr if you&amp;rsquo;re on a Debian-based system (including Proxmox) create the udev file below and reboot, and it should work fine. Validate it by running &lt;code&gt;dmesg | grep enx&lt;/code&gt; to see if it bound the right driver for your &lt;code&gt;enxXXXXXXXXXXXX&lt;/code&gt; interface.&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/sAfPm2CxfI4&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/network_realtek8156/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;udev-file&#34;&gt;Udev File&lt;/h1&gt;
&lt;p&gt;This file needs to go at &lt;code&gt;/etc/udev/rules.d/50-usb-realtek-net.rules&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And the file contents (from the Realtek driver download):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# This is used to change the default configuration of Realtek USB ethernet adapters&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ACTION!&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;add&amp;#34;, GOTO=&amp;#34;usb_realtek_net_end&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;SUBSYSTEM!&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;usb&amp;#34;, GOTO=&amp;#34;usb_realtek_net_end&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ENV{DEVTYPE}!&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;usb_device&amp;#34;, GOTO=&amp;#34;usb_realtek_net_end&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Modify this to change the default value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ENV{REALTEK_MODE1}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ENV{REALTEK_MODE2}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Realtek&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;0bda&amp;#34;, ATTR{idProduct}==&amp;#34;815[2,3,5,6]&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;0bda&amp;#34;, ATTR{idProduct}==&amp;#34;8053&amp;#34;, ATTR{bcdDevice}==&amp;#34;e???&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE2}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE2}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Samsung&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;04e8&amp;#34;, ATTR{idProduct}==&amp;#34;a101&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Lenovo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;304f&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;3052&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;3054&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;3057&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;3062&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;3069&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;3082&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;3098&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;7205&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;720a&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;720b&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;720c&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;7214&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;721e&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;8153&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;a359&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;17ef&amp;#34;, ATTR{idProduct}==&amp;#34;a387&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# TP-LINK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;2357&amp;#34;, ATTR{idProduct}==&amp;#34;0601&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Nvidia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;0955&amp;#34;, ATTR{idProduct}==&amp;#34;09ff&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# LINKSYS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ATTR{idVendor}&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;=&amp;#34;13b1&amp;#34;, ATTR{idProduct}==&amp;#34;0041&amp;#34;, ATTR{bConfigurationValue}!=&amp;#34;$env{REALTEK_MODE1}&amp;#34;, ATTR{bConfigurationValue}=&amp;#34;$env{REALTEK_MODE1}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;LABEL&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;usb_realtek_net_end&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Take Control of your Smarthome with Home Assistant! Installation Tutorial on Proxmox</title>
      <link>https://www.apalrd.net/posts/2023/ultimate_ha/</link>
      <pubDate>Thu, 12 Jan 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/ultimate_ha/</guid>
      <description>If you&amp;rsquo;re building your first home server (or following my Ultimate Home Server series!), the first app I recommend playing with is Home Assistant. Taking control of your home automation with free and open-source software is an excellent way to get out of the cloud-based walled gardens, and self-hosting an app like this is a great way to learn about self-hosting in general without the pressure of hosting something like your firewall.</description>
      <content>&lt;p&gt;If you&amp;rsquo;re building your first home server (or following my Ultimate Home Server series!), the first app I recommend playing with is Home Assistant. Taking control of your home automation with free and open-source software is an excellent way to get out of the cloud-based walled gardens, and self-hosting an app like this is a great way to learn about self-hosting in general without the pressure of hosting something like your firewall.&lt;/p&gt;
&lt;p&gt;In this video, I go over the process for creating a new virtual machine in Proxmox for Home Assistant, what settings you should choose, and why. I also include the steps to pass through USB hardware such as Zigbee and Z-Wave dongles to your virtual machine. Enjoy!&lt;/p&gt;
&lt;p&gt;This video is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2023/ultimate/&#34;&gt;Ultimate Home Server Megaproject&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;Click on the thumbnail to see the video
&lt;a href=&#34;https://youtu.be/beo7pnKLEC4&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_ha/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Terramaster NAS as low-cost Proxmox node? Teardown and SW Install!</title>
      <link>https://www.apalrd.net/posts/2023/ultimate_terra/</link>
      <pubDate>Thu, 05 Jan 2023 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/ultimate_terra/</guid>
      <description>I get asked a lot about what hardware I recommend for homelabs and home servers. It&amp;rsquo;s a very difficult question since it depends on what exactly you want to get out of your setup. But, whatever you choose, I&amp;rsquo;m starting a new series where I&amp;rsquo;ll setup all of the commonly requested home server software in a single box. Since I want to try this on both used and new hardware, here&amp;rsquo;s a low cost NAS you can buy brand-new and run your own software on it!</description>
      <content>&lt;p&gt;I get asked a lot about what hardware I recommend for homelabs and home servers. It&amp;rsquo;s a very difficult question since it depends on what exactly you want to get out of your setup. But, whatever you choose, I&amp;rsquo;m starting a new series where I&amp;rsquo;ll setup all of the commonly requested home server software in a single box. Since I want to try this on both used and new hardware, here&amp;rsquo;s a low cost NAS you can buy brand-new and run your own software on it!&lt;/p&gt;
&lt;p&gt;A few basics of this guy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Terramaster F2-223 - F2 means 2-slot cube form factor, -2 is dual core, 23 is the &amp;rsquo;new&amp;rsquo; series (at least when this video was produced)&lt;/li&gt;
&lt;li&gt;Intel Celeron N4505 dual core&lt;/li&gt;
&lt;li&gt;Dual DDR4 sodimm slots, comes with 1x 4G stick and one easily accessible empty slot. I added an 8G stick to bring it up to 12G so I can do virtualization&lt;/li&gt;
&lt;li&gt;Dual Intel I225-v3 2.5G NICs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A few upsides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They are pretty cheap for the HW you get new&lt;/li&gt;
&lt;li&gt;Mix of SATA and NVMe storage options, for bulk storage and high speed storage&lt;/li&gt;
&lt;li&gt;x86 processor so it can run Linux based OSes well&lt;/li&gt;
&lt;li&gt;Intel I225 2.5Gbe NIC is considered &amp;lsquo;good&amp;rsquo; compared to Realtek chipsets, and widely compatible across OSes such as Linux and BSD&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A few downsides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The included software seems to want to install itself on your drive as the boot disk, but I was unable to get it to do so in a short amount of time so I gave up and installed Proxmox (which I was planning on doing anyway)&lt;/li&gt;
&lt;li&gt;The internal USB seems to perpetually change some BIOS/UEFI settings back to default, removing it fixed all of the issues I had getting it to boot Proxmox properly&lt;/li&gt;
&lt;li&gt;The second RAM stick is harder to get to, although I don&amp;rsquo;t think you realistically need more than 12G of RAM to go with this much CPU power. Maybe it would matter more for the quad-core version&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This video is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2023/ultimate/&#34;&gt;Ultimate Home Server Megaproject&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_terra/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_terra/#links&#34;&gt;Links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_terra/#lscpu&#34;&gt;Hardware - lscpu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_terra/#lspci&#34;&gt;Hardware - lspci&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_terra/#vainfo&#34;&gt;Hardawre - vainfo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;Click on the thumbnail to watch the video:
&lt;a href=&#34;https://youtu.be/4_5uvWjOaR8&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_terra/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;links&#34;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Terramaster F2-223: &lt;a href=&#34;https://www.terra-master.com/global/products/homesoho-nas/f2-223.html&#34;&gt;Product Page&lt;/a&gt; or &lt;a href=&#34;https://amzn.to/3CgJwg4&#34;&gt;On Amazon&lt;/a&gt; - Note: You should also consider the quad-core versions if you want to do some virtualization, so you&amp;rsquo;d want a model with the -423 suffix (F2-423, F4-423, U4-423).&lt;/li&gt;
&lt;li&gt;The RAM I bought: &lt;a href=&#34;https://amzn.to/3VMx91T&#34;&gt;On Amazon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Only one stick of RAM if you don&amp;rsquo;t want to buy a pair: &lt;a href=&#34;https://amzn.to/3ZabG60&#34;&gt;On Amazon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Try to find an HP Microserver like mine: &lt;a href=&#34;https://ebay.us/10HV63&#34;&gt;On eBay&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some links to products may be affiliate links, which may earn a commission for me.&lt;/p&gt;
&lt;h2 id=&#34;hardware-information&#34;&gt;Hardware Information&lt;/h2&gt;
&lt;h3 id=&#34;lscpu&#34;&gt;lscpu&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Architecture&lt;/span&gt;:                    &lt;span style=&#34;color:#ae81ff&#34;&gt;x86_64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU op-mode(s)&lt;/span&gt;:                  &lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;-&lt;span style=&#34;color:#ae81ff&#34;&gt;bit, 64-bit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Byte Order&lt;/span&gt;:                      &lt;span style=&#34;color:#ae81ff&#34;&gt;Little Endian&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Address sizes&lt;/span&gt;:                   &lt;span style=&#34;color:#ae81ff&#34;&gt;39&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;bits physical, 48 bits virtual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU(s)&lt;/span&gt;:                          &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;On-line CPU(s) list&lt;/span&gt;:             &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Thread(s) per core&lt;/span&gt;:              &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Core(s) per socket&lt;/span&gt;:              &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Socket(s)&lt;/span&gt;:                       &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;NUMA node(s)&lt;/span&gt;:                    &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vendor ID&lt;/span&gt;:                       &lt;span style=&#34;color:#ae81ff&#34;&gt;GenuineIntel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU family&lt;/span&gt;:                      &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Model&lt;/span&gt;:                           &lt;span style=&#34;color:#ae81ff&#34;&gt;156&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Model name&lt;/span&gt;:                      &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel(R) Celeron(R) N4505 @ 2.00GHz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Stepping&lt;/span&gt;:                        &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU MHz&lt;/span&gt;:                         &lt;span style=&#34;color:#ae81ff&#34;&gt;2899.952&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU max MHz&lt;/span&gt;:                     &lt;span style=&#34;color:#ae81ff&#34;&gt;2900.0000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;CPU min MHz&lt;/span&gt;:                     &lt;span style=&#34;color:#ae81ff&#34;&gt;800.0000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;BogoMIPS&lt;/span&gt;:                        &lt;span style=&#34;color:#ae81ff&#34;&gt;3993.60&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Virtualization&lt;/span&gt;:                  &lt;span style=&#34;color:#ae81ff&#34;&gt;VT-x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;L1d cache&lt;/span&gt;:                       &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;KiB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;L1i cache&lt;/span&gt;:                       &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;KiB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;L2 cache&lt;/span&gt;:                        &lt;span style=&#34;color:#ae81ff&#34;&gt;1.5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;MiB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;L3 cache&lt;/span&gt;:                        &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;MiB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;NUMA node0 CPU(s)&lt;/span&gt;:               &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Itlb multihit&lt;/span&gt;:     &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability L1tf&lt;/span&gt;:              &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Mds&lt;/span&gt;:               &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Meltdown&lt;/span&gt;:          &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Mmio stale data:   Vulnerable&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Clear CPU buffers attempted, no microcode; SMT disabled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Retbleed&lt;/span&gt;:          &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Spec store bypass&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Mitigation; Speculative Store Bypass disabled via prctl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Spectre v1&lt;/span&gt;:        &lt;span style=&#34;color:#ae81ff&#34;&gt;Mitigation; usercopy/swapgs barriers and __user pointer sanitization&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Spectre v2&lt;/span&gt;:        &lt;span style=&#34;color:#ae81ff&#34;&gt;Mitigation; Enhanced IBRS, IBPB conditional, RSB filling, PBRSB-eIBRS Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Srbds:             Vulnerable&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;No&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;microcode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Vulnerability Tsx async abort&lt;/span&gt;:   &lt;span style=&#34;color:#ae81ff&#34;&gt;Not affected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;Flags&lt;/span&gt;:                           &lt;span style=&#34;color:#ae81ff&#34;&gt;fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#ae81ff&#34;&gt;i mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc art arch_perfmon peb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#ae81ff&#34;&gt;s bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#ae81ff&#34;&gt;dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg cx16 xtpr pdcm sse4_1 sse4_2 x2apic movbe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#ae81ff&#34;&gt;popcnt tsc_deadline_timer aes xsave rdrand lahf_lm 3dnowprefetch cpuid_fault epb cat_l&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;cdp_l2 ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#ae81ff&#34;&gt;d fsgsbase tsc_adjust smep erms rdt_a rdseed smap clflushopt clwb intel_pt sha_ni xsave&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#ae81ff&#34;&gt;opt xsavec xgetbv1 xsaves split_lock_detect dtherm ida arat pln pts hwp hwp_notify hwp_&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#ae81ff&#34;&gt;act_window hwp_epp hwp_pkg_req umip waitpkg gfni rdpid movdiri movdir64b md_clear flush&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#ae81ff&#34;&gt;_l1d arch_capabilities&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;lspci&#34;&gt;lspci&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:00.0 Host bridge&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4e14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:02.0 VGA compatible controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4e55 (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:04.0 Signal processing controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4e03&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:08.0 System peripheral&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4e11&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:14.0 USB controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4ded (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:14.2 RAM memory&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4def (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:14.5 SD Host controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4df8 (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:16.0 Communication controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4de0 (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:17.0 SATA controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4dd3 (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:1c.0 PCI bridge&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4db8 (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:1c.1 PCI bridge&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4db9 (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:1c.5 PCI bridge&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4dbd (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:1f.0 ISA bridge&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4d87 (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:1f.3 Audio device&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4dc8 (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:1f.4 SMBus&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4da3 (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;00:1f.5 Serial bus controller [0c80]&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Device 4da4 (rev 01)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;01:00.0 Ethernet controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Ethernet Controller I225-V (rev 03)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;02:00.0 Ethernet controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel Corporation Ethernet Controller I225-V (rev 03)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;03:00.0 Non-Volatile memory controller&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Samsung Electronics Co Ltd NVMe SSD Controller SM961/PM961/SM963&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;vainfo&#34;&gt;vainfo&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;libva info&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;VA-API version 1.10.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;libva info&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Trying to open /usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;libva info&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Found init function __vaDriverInit_1_10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;libva info&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;va_openDriver() returns 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;vainfo: VA-API version&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1.10&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;(libva 2.10.0)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;vainfo: Driver version&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Intel iHD driver for Intel(R) Gen Graphics - 21.1.1 ()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;vainfo&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Supported profile and entrypoints&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileNone                   :	VAEntrypointVideoProc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileNone                   :	VAEntrypointStats&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileMPEG2Simple            :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileMPEG2Main              :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264Main               :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264Main               :	VAEntrypointEncSliceLP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264High               :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264High               :	VAEntrypointEncSliceLP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileJPEGBaseline           :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileJPEGBaseline           :	VAEntrypointEncPicture&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264ConstrainedBaseline:	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileH264ConstrainedBaseline:	VAEntrypointEncSliceLP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileVP8Version0_3          :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain               :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain               :	VAEntrypointEncSliceLP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain10             :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain10             :	VAEntrypointEncSliceLP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileVP9Profile0            :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileVP9Profile1            :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileVP9Profile2            :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileVP9Profile3            :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain422_10         :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain444            :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain444            :	VAEntrypointEncSliceLP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain444_10         :	VAEntrypointVLD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;VAProfileHEVCMain444_10         :	VAEntrypointEncSliceLP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Ultimate Home Server Megaproject</title>
      <link>https://www.apalrd.net/projects/2023/ultimate/</link>
      <pubDate>Thu, 05 Jan 2023 08:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2023/ultimate/</guid>
      <description>In this project, I explore an all-in-one home server using low cost hardware, bringing together as many common home applications as possible in a single box.
Terramaster NAS as low-cost Proxmox node? Teardown and SW Install! In the first video, I introduce the hardware for this project - a cheap Terramaster NAS! It combines two HDD bays and two NVMe slots in a very tiny and low power brick, with dual 2.</description>
      <content>&lt;p&gt;In this project, I explore an all-in-one home server using low cost hardware, bringing together as many common home applications as possible in a single box.&lt;/p&gt;
&lt;h2 id=&#34;terramaster-nas-as-low-cost-proxmox-node-teardown-and-sw-install&#34;&gt;Terramaster NAS as low-cost Proxmox node? Teardown and SW Install!&lt;/h2&gt;
&lt;p&gt;In the first video, I introduce the hardware for this project - a cheap Terramaster NAS! It combines two HDD bays and two NVMe slots in a very tiny and low power brick, with dual 2.5G ethernet too! I get it running with Proxmox, so future projects have a platform to build on.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_terra/&#34;&gt;&lt;img alt=&#34;Terramaster NAS as low-cost Proxmox node? Teardown and SW Install!&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_terra/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;take-control-of-your-smarthome-with-home-assistant-installation-tutorial-on-proxmox&#34;&gt;Take Control of your Smarthome with Home Assistant! Installation Tutorial on Proxmox&lt;/h2&gt;
&lt;p&gt;In this video, I go over the process for creating a new virtual machien in Proxmox for Home Assistant, what settings you should choose, and why. I also include the steps to pass through USB hardware such as Zigbee and Z-Wave dongles to your virtual machine. Enjoy!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_ha/&#34;&gt;&lt;img alt=&#34;Take Control of your Smarthome with Home Assistant! Installation Tutorial on Proxmox&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_ha/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;making-proxmox-into-a-pretty-good-nas&#34;&gt;Making Proxmox into a pretty good NAS&lt;/h2&gt;
&lt;p&gt;Continuing the series where apalrd teaches proxmox skills through meaningful applications, today we are setting up a proper fileserver on our Proxmox system using Linux Containers. I&amp;rsquo;ve chosen to use a lightweight Linux Container (LXC) for this, so we can share the host&amp;rsquo;s ZFS filesystem. To manage shares and users using a web UI, I&amp;rsquo;m installing Cockpit, as well as some additional modules from 45Drives to deal with Samba. Hope you enjoy it!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_nas/&#34;&gt;&lt;img alt=&#34;Making Proxmox into a pretty good NAS&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_nas/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;manage-your-media-collection-with-jellyfin-install-on-proxmox-with-hardware-transcode&#34;&gt;Manage your Media Collection with Jellyfin! Install on Proxmox with Hardware Transcode&lt;/h2&gt;
&lt;p&gt;In the last video I introduced Linux Containers, today we&amp;rsquo;re going to supercharge that by seeing if we can get some graphics hardware into our container, and give our large blu-ray collection a new home. We&amp;rsquo;re going to cover a few more advanced Proxmox container features, such as privilaged containers, hardware pass-through, and Jellyfin setup and transcoding for Intel and AMD GPUs.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_jellyfin/&#34;&gt;&lt;img alt=&#34;Manage your Media Collection with Jellyfin! Install on Proxmox with Hardware Transcode&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_jellyfin/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;migrating-my-personal-server-from-truenas-to-proxmox&#34;&gt;Migrating my PERSONAL SERVER from TrueNAS to Proxmox&lt;/h2&gt;
&lt;p&gt;Today I&amp;rsquo;m taking my 10 servers and hopefully working that list down to just 7! JUST SEVEN!
So, driven by my desire to consolidate my critical services into one box so I can lab away with the rest of the boxes, I am taking the time to shut down some of the most critical servers in the house and re-home them, then disassemble the parts for the next project.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_migrate/&#34;&gt;&lt;img alt=&#34;Migrating my PERSONAL SERVER from TrueNAS to Proxmox&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_migrate/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;unleash-your-home-cameras-with-frigate-self-hosted-ai-video-recorder-install-on-proxmox-lxc&#34;&gt;Unleash your Home Cameras with FRIGATE Self-Hosted AI Video Recorder! Install on Proxmox LXC&lt;/h2&gt;
&lt;p&gt;Do you have security cameras at your house? Would you like to locally host all of your recording and analytics, to make sure nobody else has access to your video feeds and recordings? Would you also like to integrate with Home Assistant, the greatest open automation platform in the world? Then Frigate NVR is for you! In this video, I&amp;rsquo;m going to go in depth to setup Frigate in an LXC container, for maximum efficiency. Using Podman Quadlet, I&amp;rsquo;m going to manage the Frigate container in a sane way with normal systemd and journalctl tools. And I&amp;rsquo;m going all-in on hardware passthrough, with my Coral TPU for advanced AI detections and person/cat/car counting, along with a basic Intel Quick Sync GPU to decode the video streams in hardware and reduce CPU load. So join me on this adventure!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/&#34;&gt;&lt;img alt=&#34;Unleash your Home Cameras with FRIGATE Self-Hosted AI Video Recorder! Install on Proxmox LXC&#34; src=&#34;https://www.apalrd.net/posts/2023/ultimate_frigate/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>All about POOLS | Proxmox &#43; Ceph Hyperconverged Cluster fäncy Configurations for RBD</title>
      <link>https://www.apalrd.net/posts/2022/cluster_ceph_pools/</link>
      <pubDate>Thu, 29 Dec 2022 08:14:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/cluster_ceph_pools/</guid>
      <description>In this video, I expand on the last video of my hyper-converged Proxmox + Ceph cluster to create more custom pool layouts than Proxmox&amp;rsquo;s GUI allows. This includes setting the storage class (HDD / SSD / NVME), failure domain, and even erasure coding of pools. All of this is then setup as a storage location in Proxmox for RBD (RADOS Block Device), so we can store VM disks on it.</description>
      <content>&lt;p&gt;In this video, I expand on the last video of my hyper-converged Proxmox + Ceph cluster to create more custom pool layouts than Proxmox&amp;rsquo;s GUI allows. This includes setting the storage class (HDD / SSD / NVME), failure domain, and even erasure coding of pools. All of this is then setup as a storage location in Proxmox for RBD (RADOS Block Device), so we can store VM disks on it.&lt;/p&gt;
&lt;p&gt;After all of this, I now have the flexibility to assign VM disks to HDDs or SSDs, and use erasure coding to get 66% storage efficiency instead of 33% (doubling my usable capacity for the same disks!). With more nodes and disks, I could improve both the storage efficiency and failure resilience of my cluster, but with only the small number of disks I have, I opted to go for a basic 2+1 erasure code.&lt;/p&gt;
&lt;p&gt;This is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/cluster/&#34;&gt;Hyper-Converged Cluster Megaproject&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/nyhIqewyDBk&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/cluster_ceph_pools/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>HDMI Distribution over your Home Network? Low-Cost HDMI Matrix using IP-Based Hardware</title>
      <link>https://www.apalrd.net/posts/2022/hdmi_ip/</link>
      <pubDate>Thu, 08 Dec 2022 00:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/hdmi_ip/</guid>
      <description>So, you want to send HDMI video around your house? Maybe you want to use your office computer on your living room TV without a proprietary streaming solution like AirPlay or Chromecast? Share a cable or satellite box between your living room and bedroom? Or you&amp;rsquo;re crazy like me and you want to put all of your computers into the basement, and connect to any of them from any desk in the house?</description>
      <content>&lt;p&gt;So, you want to send HDMI video around your house? Maybe you want to use your office computer on your living room TV without a proprietary streaming solution like AirPlay or Chromecast? Share a cable or satellite box between your living room and bedroom? Or you&amp;rsquo;re crazy like me and you want to put all of your computers into the basement, and connect to any of them from any desk in the house?&lt;/p&gt;
&lt;p&gt;Traditional video distribution methods which support many-to-many configurations usually require expensive matrix switches, either for HDMI or HDBaseT. With lower cost IP-based equipment, we can use the network infrastructure we already have in our home networks to send HDMI video across the network, at the cost of video compression. If you can tolerate 1080P/60 video for your application, this is far cheaper than other alternatives in a many-to-many configuration.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve tried running a thicc HDMI cable through the wall at my house. This will work, but over a limited distance (and the workable distance gets shorter with the higher bitrates of each HDMI spec). You can&amp;rsquo;t repair an HDMI cable realistically, so if you break it you&amp;rsquo;re going back in the wall or attic. I have a few places in my house with floating TVs (I absolutely hate cable cluttter) and running HDMI from the TV down to a media cabinet is as far as I&amp;rsquo;d go with a physical cable.&lt;/p&gt;
&lt;p&gt;There are solutions like active optical cables and HDBaseT which are suitable for higher bitrate uncompressed applications like home theaters, but I&amp;rsquo;m primarily concerned with workstation tasks which aren&amp;rsquo;t as demanding of the video stream. However, these solutions might be right for you.&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/y-PxmQn8Xr8&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/hdmi_ip/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;q-and-a&#34;&gt;Q and A&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/5n-hQ29qWh4&#34;&gt;&lt;img alt=&#34;Q and A thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/hdmi_ip/thumbnail2.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Will it do 4K?
&lt;ul&gt;
&lt;li&gt;No, it does 1080p60&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Will it do 144hz?
&lt;ul&gt;
&lt;li&gt;No, it wont.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Does it support ultrawide?
&lt;ul&gt;
&lt;li&gt;The transmitter and receiver negotiate resolutions separately&lt;/li&gt;
&lt;li&gt;The transmitter supports 800x600 up to 1920x1090 without knowing the display&amp;rsquo;s supported resolutions&lt;/li&gt;
&lt;li&gt;The receiver will separately try to negotiate 1920x1080 with the display, or lower if the display doesn&amp;rsquo;t support it&lt;/li&gt;
&lt;li&gt;When the transmitter and receiver are &amp;rsquo;tuned&amp;rsquo; together it will add black bars to match the two aspect ratios and scale the resolutions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What type of encoding does it use? Can I open it in VLC?
&lt;ul&gt;
&lt;li&gt;I do not know what encoding it uses but strongly suspect h.265&lt;/li&gt;
&lt;li&gt;I opened the multicast group/port in VLC as both UDP and RTP and VLC was not able to decode it. So, the encapsulation is unknown.&lt;/li&gt;
&lt;li&gt;I captured a pcap of the two boxes in use and have a link to it &lt;a href=&#34;https://www.apalrd.net/posts/2022/hdmi_ip/capture.pcap&#34;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Support for HDCP
&lt;ul&gt;
&lt;li&gt;The TiVo negotiated HDCP 1.x successfully. I do not know if the device supports HDCP 2.x&lt;/li&gt;
&lt;li&gt;I can&amp;rsquo;t tell if any displays are negotiating HDCP, they won&amp;rsquo;t tell me in their menus&lt;/li&gt;
&lt;li&gt;I do not know if HDCP is being stripped or if HDCP is separately negotiated on each end.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What about NDI / other professional solutions?
&lt;ul&gt;
&lt;li&gt;They exist&lt;/li&gt;
&lt;li&gt;They are more expensive&lt;/li&gt;
&lt;li&gt;NDI does not allow directly connecting sources and sinks without a vision mixer in the middle&lt;/li&gt;
&lt;li&gt;Other solutions are priced with &amp;lsquo;contact us&amp;rsquo;, meaning they are effectively not available to home users&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Display Power Savings
&lt;ul&gt;
&lt;li&gt;I noticed that the receiver will always display the no connection logo once the transmitter stops receiving a signal, so the display will never power off.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How are the compression artifacts?
&lt;ul&gt;
&lt;li&gt;In general not bad.&lt;/li&gt;
&lt;li&gt;I watched some (CC licensed) movies side by side and had to scrub back and forth to spot differences&lt;/li&gt;
&lt;li&gt;In general it looks like the i-frame interval is relatively long, so sometimes scene changes in movies will cause some artifacting until the next i-frame. This would not happen on a computer or game where there aren&amp;rsquo;t major scene changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Does it work over WiFi extenders / Powerline extenders / MoCA coax?
&lt;ul&gt;
&lt;li&gt;I don&amp;rsquo;t have any of these to test&lt;/li&gt;
&lt;li&gt;In theory it will work on anything that supports multicast and creates a layer 2 bridge (&lt;em&gt;not&lt;/em&gt; layer 3 route)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What is the latency?
&lt;ul&gt;
&lt;li&gt;4 frames. See the video for more detailed info.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How does it handle multiple keyboards/mice?
&lt;ul&gt;
&lt;li&gt;It sends separate data from each of them. Clicking one mouse and dragging the other won&amp;rsquo;t click + drag, it will take all of the mouse data from the moving mouse (release the click).&lt;/li&gt;
&lt;li&gt;Keyboards will send both keys but not mix scancodes, for example holding shift on one keyboard and pressing a letter on the other won&amp;rsquo;t result in a capital letter.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Why don&amp;rsquo;t they support PoE?
&lt;ul&gt;
&lt;li&gt;I don&amp;rsquo;t see a reason to use PoE when they will always connect to a higher powered device anyway, like a TV or computer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What is the power consumption / can you really connect them to USB power?
&lt;ul&gt;
&lt;li&gt;Measured ~1.5W on the receiver and ~2W on the transmitter, measuring the AC input with a kill-a-watt meter. Well within the 500ma limit of traditional USB power.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;reverse-engineering&#34;&gt;Reverse Engineering&lt;/h1&gt;
&lt;p&gt;My subscribers have been very interested in some light reverse-engineering of these, so if anyone wants to try, here&amp;rsquo;s the information I have to share:&lt;/p&gt;
&lt;h2 id=&#34;packet-captures&#34;&gt;Packet Captures&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Display is established (ID #1), mouse movement and keyboard input on an Ubuntu jellyfish desktop - &lt;a href=&#34;https://www.apalrd.net/posts/2022/hdmi_ip/capture.pcap&#34;&gt;download here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Establishing a connection (ID #1), nothing connected, transmitter powered on and given time to settle, then receiver powered on and given time to settle - &lt;a href=&#34;https://www.apalrd.net/posts/2022/hdmi_ip/capture2.pcap&#34;&gt;download here&lt;/a&gt;
More will come.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;parts-i-used&#34;&gt;Parts I Used&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.tesmart.com/collections/hdmi-kvm-extender/products/tesmart-120m-hdmi-extender-kvm-over-tcp-ip-ethernet-via-single-cat5e-6-cable-1080p-with-ir-up-to-120m?variant=37641919398084&amp;sca_ref=2636570.HXDyVJctBl&amp;sca_source=Vid_HDMI_IP&#34;&gt;TESmart HKE12MMA20 KVM over IP (Newer Model, shown here)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3iPQ9yI&#34;&gt;TESmart hKE12MMA10 KVM over IP (Older Model) available on Amazon&lt;/a&gt;
Some links to products may be affiliate links, which may earn a commission for me.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Import a Virtual Machine Template (OVA, VMDK, RAW, ...) into Proxmox!</title>
      <link>https://www.apalrd.net/posts/2022/pve_import/</link>
      <pubDate>Thu, 01 Dec 2022 10:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/pve_import/</guid>
      <description>Short tutorial this week, how to import a VM image you may get to use in Proxmox. I took a vacation for Thanksgiving, so back to the regularly scheduled madness soon. Enjoy!
The Basics: You need to use qm importvm (See the man page here if you want to reference it). The basic command is:
qm importvm &amp;lt;vmid&amp;gt; &amp;lt;source&amp;gt; &amp;lt;storage&amp;gt; &amp;lt;options&amp;gt; Where &amp;lt;vmid&amp;gt; is the number of a VM which alraedy exists, &amp;lt;source&amp;gt; is the path to a file which qemu can convert (qcow2, vmdk,raw img), and &amp;lt;storage&amp;gt; is the name of a storage location in Proxmox.</description>
      <content>&lt;p&gt;Short tutorial this week, how to import a VM image you may get to use in Proxmox. I took a vacation for Thanksgiving, so back to the regularly scheduled madness soon. Enjoy!&lt;/p&gt;
&lt;p&gt;The Basics:
You need to use &lt;code&gt;qm importvm&lt;/code&gt; &lt;a href=&#34;https://pve.proxmox.com/pve-docs/qm.1.html&#34;&gt;(See the man page here if you want to reference it)&lt;/a&gt;. The basic command is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qm importvm &amp;lt;vmid&amp;gt; &amp;lt;source&amp;gt; &amp;lt;storage&amp;gt; &amp;lt;options&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where &lt;code&gt;&amp;lt;vmid&amp;gt;&lt;/code&gt; is the number of a VM which alraedy exists, &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; is the path to a file which qemu can convert (qcow2, vmdk,raw img), and &lt;code&gt;&amp;lt;storage&amp;gt;&lt;/code&gt; is the name of a storage location in Proxmox. For &lt;code&gt;options&lt;/code&gt;, they are only relevant if you are using file based storage, then you can pass &lt;code&gt;--format&lt;/code&gt; with one of &lt;code&gt;qcow2&lt;/code&gt;, &lt;code&gt;vmdk&lt;/code&gt;, or &lt;code&gt;raw&lt;/code&gt; to specify the file format to use. If you are using block based storage such as ZFS, LVM, &amp;hellip; then this is ignored and unnecessary.&lt;/p&gt;
&lt;p&gt;The Video:
&lt;a href=&#34;https://youtu.be/k6-miz1Tb80&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/pve_import/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Proxmox NETWORKING: VLANs, Bridges, and Bonds!</title>
      <link>https://www.apalrd.net/posts/2022/pve_networking/</link>
      <pubDate>Thu, 17 Nov 2022 08:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/pve_networking/</guid>
      <description>I&amp;rsquo;m sure many of you follow me because you use Proxmox. It&amp;rsquo;s been a staple of my content for some time now. So, while working on the next episode of the Ceph series, I thought it would be good to do a separate segment on networking. So, here you have it. The basics of VLANs, Bridges, and Bonds in Proxmox VE. I&amp;rsquo;m only covering the native Linux versions, not Open VSwitch and VXLAN.</description>
      <content>&lt;p&gt;I&amp;rsquo;m sure many of you follow me because you use Proxmox. It&amp;rsquo;s been a staple of my content for some time now. So, while working on the next episode of the Ceph series, I thought it would be good to do a separate segment on networking. So, here you have it. The basics of VLANs, Bridges, and Bonds in Proxmox VE. I&amp;rsquo;m only covering the native Linux versions, not Open VSwitch and VXLAN. I&amp;rsquo;m sure I&amp;rsquo;ll get around to a video on that topic someday.&lt;/p&gt;
&lt;p&gt;So, what are the most important things to know when choosing a network topology for Proxmox (or any virtualization environment)? TRAFFIC! Where is traffic going, and how much of it is going everywhere?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How much traffic is going to Proxmox itself? This includes the web UI and API (which should be minimal), but also SPICE sessions if you&amp;rsquo;re using SPICE for VDI.&lt;/li&gt;
&lt;li&gt;How much traffic is going from Proxmox to your storage solutions? If you&amp;rsquo;re using NFS / SMB / iSCSI, it could be a lot. Are you keepign your storage network separated, either physically or virtually (VLANs)? Proxmox will need an IP address on any network you use to communicate with storage&lt;/li&gt;
&lt;li&gt;How much traffic is going to your VMs? Do they need to be on specific VLANs?&lt;/li&gt;
&lt;li&gt;Do any VMs do routing or need access to a VLAN trunk port? If so, should they get open access or restricted to certain VLANs? Do you want to expose each VLAN as a separate virtual network interface or trunk them over a single interface?&lt;/li&gt;
&lt;li&gt;Do you require high availability at the network level, i.e. bonded failover? Do you want to use a slower 1G network when your 10G network fails, or just lose connectivity altogether?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you can answer these questions, you can proceed to decide how to arrange the physical interfaces you have (or are buying/adding) for the best performace for your use case.&lt;/p&gt;
&lt;p&gt;In my test setup, I&amp;rsquo;m going to demonstrate bonding between identical (two Gigabit) and different (multi-gig + gigabit), and the concepts apply to 10G and faster networking as well.&lt;/p&gt;
&lt;p&gt;And a good reference from Proxmox: &lt;a href=&#34;https://pve.proxmox.com/pve-docs/pve-admin-guide.html#sysadmin_network_configuration&#34;&gt;Proxmox Networking Admin Guide&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/zx5LFqyMPMU&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/pve_networking/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Thin Client Addicts Anonymous - HP T530 Teardown/Review</title>
      <link>https://www.apalrd.net/posts/2022/hp_t530/</link>
      <pubDate>Thu, 10 Nov 2022 00:32:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/hp_t530/</guid>
      <description>I have a thin client addiction. You all have seen my 3x Dell Wyse 5060 Hyperconverged Cluster project. And you know that I bought a Dell Wyse 3040. But, I actually bought 3x 3040s, and someone sent me a Wyse 7010, and an HP T620 (yet to be reviewed). And now I bought another. An HP T530.
I&amp;rsquo;d consider this to be an excellent choice for anyone wanting to run Home Assistant, since it has enough power for, an upgradeable M.</description>
      <content>&lt;p&gt;I have a thin client addiction. You all have seen my &lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_ceph/&#34;&gt;3x Dell Wyse 5060 Hyperconverged Cluster&lt;/a&gt; project. And you know that I bought a &lt;a href=&#34;https://www.apalrd.net/posts/2022/wyse_3040/&#34;&gt;Dell Wyse 3040&lt;/a&gt;. But, I actually bought 3x 3040s, and someone sent me a &lt;a href=&#34;https://www.apalrd.net/posts/2022/wyse_7010/&#34;&gt;Wyse 7010&lt;/a&gt;, and an HP T620 (yet to be reviewed). And now I bought another. An HP T530.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d consider this to be an excellent choice for anyone wanting to run Home Assistant, since it has &lt;em&gt;enough&lt;/em&gt; power for, an upgradeable M.2 storage slot, and can handle a Coral TPU for Frigate using the M.2 WiFi slot (but &lt;em&gt;not&lt;/em&gt; in the storage slot). It&amp;rsquo;s also a bit more modern than the Dell units, using DDR4 (only single channel though) and sporting a USB-C port and more USB 3.0 ports. That said, it&amp;rsquo;s a lower end processor and GPU than the 5060, if that&amp;rsquo;s a concern for you.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to see my saved eBay search for T530&amp;rsquo;s, &lt;a href=&#34;https://ebay.us/vjcuy4&#34;&gt;find it here (Affiliate link)&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;Click on the thumbnail to view the video on Youtube
&lt;a href=&#34;https://youtu.be/d4vHfr-Pvjg&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/hp_t530/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;m2-compatibility&#34;&gt;M.2 Compatibility&lt;/h1&gt;
&lt;p&gt;This unit has two M.2 slots - one E key (WiFi) and one M key (Storage). The M slot can fit up to 2280 size SSDs.&lt;/p&gt;
&lt;p&gt;I found that the Storage slot electrically works for SATA only, not PCIe. Be aware of this when buying SSDs for this thin client.&lt;/p&gt;
&lt;p&gt;I tested an Intel WiFi + Bluetooth card in the Wifi slot, and found that at least one PCIe lane and USB are working on that slot. I can&amp;rsquo;t confirm if the other PCIe bus, SDIO, etc. work on this slot.&lt;/p&gt;
&lt;h1 id=&#34;hardware-info&#34;&gt;Hardware Info&lt;/h1&gt;
&lt;p&gt;All of this was taken via an Xubuntu 20.04 Live ISO, so your kernel may be configured slightly differently&lt;/p&gt;
&lt;h2 id=&#34;lscpu&#34;&gt;lscpu&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Architecture:                    x86_64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
Address sizes:                   48 bits physical, 48 bits virtual
CPU(s):                          2
On-line CPU(s) list:             0,1
Thread(s) per core:              1
Core(s) per socket:              2
Socket(s):                       1
NUMA node(s):                    1
Vendor ID:                       AuthenticAMD
CPU family:                      21
Model:                           112
Model name:                      AMD Embedded G-Series GX-215JJ Radeon R2E
Stepping:                        0
Frequency boost:                 enabled
CPU MHz:                         1107.674
CPU max MHz:                     1500.0000
CPU min MHz:                     1100.0000
BogoMIPS:                        2994.56
Virtualization:                  AMD-V
L1d cache:                       64 KiB
L1i cache:                       128 KiB
L2 cache:                        2 MiB
NUMA node0 CPU(s):               0,1
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Not affected
Vulnerability Meltdown:          Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp
Vulnerability Spectre v1:        Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2:        Mitigation; Full AMD retpoline, STIBP disabled, RSB filling
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected
Flags:                           fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36
                                 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp 
                                 lm constant_tsc rep_good acc_power nopl nonstop_tsc cpuid extd_apicid 
                                 aperfmperf pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt 
                                 aes xsave avx f16c lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a 
                                 misalignsse 3dnowprefetch osvw ibs xop skinit wdt lwp fma4 tce nodeid_msr 
                                 tbm perfctr_core perfctr_nb bpext ptsc mwaitx cpb hw_pstate ssbd vmmcall 
                                 fsgsbase bmi1 avx2 smep bmi2 xsaveopt arat npt lbrv svm_lock nrip_save 
                                 tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold 
                                 avic v_vmsave_vmload vgif overflow_recov
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;CPU does support aes-ni and AMD-V, but not SMT (hyper-threading). So, 2 cores, 2 threads.&lt;/p&gt;
&lt;h2 id=&#34;lspci&#34;&gt;lspci&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;00:00.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 15h (Models 60h-6fh) Processor Root Complex
00:00.2 IOMMU: Advanced Micro Devices, Inc. [AMD] Family 15h (Models 60h-6fh) I/O Memory Management Unit
00:01.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Stoney [Radeon R2/R3/R4/R5 Graphics] (rev 83)
00:01.1 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] Device 15b3
00:02.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 15h (Models 60h-6fh) Host Bridge
00:02.2 PCI bridge: Advanced Micro Devices, Inc. [AMD] Family 15h (Models 60h-6fh) Processor Root Port
00:03.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 15h (Models 60h-6fh) Host Bridge
00:08.0 Encryption controller: Advanced Micro Devices, Inc. [AMD] Carrizo Platform Security Processor
00:09.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Carrizo Audio Dummy Host Bridge
00:09.2 Audio device: Advanced Micro Devices, Inc. [AMD] Family 15h (Models 60h-6fh) Audio Controller
00:10.0 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB XHCI Controller (rev 20)
00:11.0 SATA controller: Advanced Micro Devices, Inc. [AMD] FCH SATA Controller [AHCI mode] (rev 4b)
00:12.0 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB EHCI Controller (rev 49)
00:14.0 SMBus: Advanced Micro Devices, Inc. [AMD] FCH SMBus Controller (rev 4b)
00:14.3 ISA bridge: Advanced Micro Devices, Inc. [AMD] FCH LPC Bridge (rev 11)
00:18.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Stoney HT Configuration
00:18.1 Host bridge: Advanced Micro Devices, Inc. [AMD] Stoney Address Maps
00:18.2 Host bridge: Advanced Micro Devices, Inc. [AMD] Stoney DRAM Configuration
00:18.3 Host bridge: Advanced Micro Devices, Inc. [AMD] Stoney Miscellaneous Configuration
00:18.4 Host bridge: Advanced Micro Devices, Inc. [AMD] Stoney PM Configuration
00:18.5 Host bridge: Advanced Micro Devices, Inc. [AMD] Stoney NB Performance Monitor
01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 15)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Realtek NIC, as expected for a device of this price range&lt;/p&gt;
&lt;h2 id=&#34;vainfo&#34;&gt;vainfo&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;vainfo: VA-API version: 1.7 (libva 2.6.0)
vainfo: Driver version: Mesa Gallium driver 21.2.6 for AMD STONEY (DRM 3.41.0, 5.13.0-30-generic, LLVM 12.0.0)
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            :	VAEntrypointVLD
      VAProfileMPEG2Main              :	VAEntrypointVLD
      VAProfileVC1Simple              :	VAEntrypointVLD
      VAProfileVC1Main                :	VAEntrypointVLD
      VAProfileVC1Advanced            :	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointEncSlice
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointEncSlice
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointEncSlice
      VAProfileHEVCMain               :	VAEntrypointVLD
      VAProfileHEVCMain10             :	VAEntrypointVLD
      VAProfileJPEGBaseline           :	VAEntrypointVLD
      VAProfileNone                   :	VAEntrypointVideoProc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Some links to products may be affiliate links, which may earn a commission for me.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Waveshare UPS Battery Backup for your Raspberry Pi! With Data Logging to MQTT</title>
      <link>https://www.apalrd.net/posts/2022/rpi_ups/</link>
      <pubDate>Thu, 03 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/rpi_ups/</guid>
      <description>As some of you may know, I have a Raspberry Pi which handles all of the radios for Home Assistant. It runs ZwaveJS2MQTT (using the WebSockets connection to Home Assistant, not MQTT), Zigbee2MQTT (using MQTT), and RTL-433 (also using MQTT). So, it&amp;rsquo;s fairly critical infrastructure. Usually, with critical infrastructure, I try to get it PoE powered so I don&amp;rsquo;t have to worry about power bricks and can get battery backup via the CRS328 network switch in the basement (which is on a battery of its own).</description>
      <content>&lt;p&gt;As some of you may know, I have a Raspberry Pi which handles all of the radios for Home Assistant. It runs ZwaveJS2MQTT (using the WebSockets connection to Home Assistant, not MQTT), Zigbee2MQTT (using MQTT), and RTL-433 (also using MQTT). So, it&amp;rsquo;s fairly critical infrastructure. Usually, with critical infrastructure, I try to get it PoE powered so I don&amp;rsquo;t have to worry about power bricks and can get battery backup via the CRS328 network switch in the basement (which is on a battery of its own). But, unfortunately, the connection between my upstairs laundry room and basement network closet is via fiber, so no power being carried there. I need another solution, and not wanting a giant AC UPS I decided on a tiny Pi UPS from Waveshare.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a hat for the Pi with two 18650 lithium batteries, a charger circuit, power monitor and balancing ICs, and an 8.4v to 5v buck converter to power the Pi itself. It comes with an 8.4v wall brick to power the whole thing, and is designed to be plugged in to wall power normally and transition to battery power without any interruption. But, that&amp;rsquo;s still not good enough for me. I want the data collected to get into Home Assistant. So, I wrote a custom Python script to push the power monitor data to MQTT, and made a video about it.&lt;/p&gt;
&lt;p&gt;In a bit of a divergence from my other blog posts, I&amp;rsquo;m linking to my Github for the code and instructions. So, read the readme to install my code if you want to use it.&lt;/p&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;Click on the thumbnail to watch the video on Youtube
&lt;a href=&#34;https://youtu.be/KM3v9tt-CpU&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/rpi_ups/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;parts-list&#34;&gt;Parts List&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Waveshare Pi UPS (B) - Pogo Pins model is what I got - &lt;a href=&#34;https://amzn.to/3TYkuJe&#34;&gt;Amazon&lt;/a&gt; or &lt;a href=&#34;https://www.waveshare.com/product/ups-hat-b.htm&#34;&gt;Waveshare&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Waveshare Pi UPS - female header hat is another model that I didn&amp;rsquo;t get - &lt;a href=&#34;https://amzn.to/3FEo86J&#34;&gt;Amazon&lt;/a&gt; or &lt;a href=&#34;https://www.waveshare.com/ups-hat.htm&#34;&gt;Waveshare&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Wavehare Pi UPS for Pi Zero - another model that I didn&amp;rsquo;t get but the code should work with hopefully - &lt;a href=&#34;https://amzn.to/3fo33TC&#34;&gt;Amazon&lt;/a&gt; or &lt;a href=&#34;https://www.waveshare.com/ups-hat-c.htm&#34;&gt;Waveshare&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apalrd/waveshare_ups_mqtt/&#34;&gt;My Software on Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Backup Proxmox VE to the CLOUD! Backup Hook Scripts and S3</title>
      <link>https://www.apalrd.net/posts/2022/pve_backup/</link>
      <pubDate>Thu, 27 Oct 2022 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/pve_backup/</guid>
      <description>Proxmox has a pretty good backup scheduler, but it relies on the backup destination being mounted as a storage location. This implies that the backup destination needs to be a protocol that Proxmox supports - SMB (CIFS), NFS, &amp;hellip; or Proxmox Backup Server. If you want to push your backups to a cloud service, you probably need something a bit more complicated. Thankfully, Proxmox&amp;rsquo;s backup scheduler thought about this and has a hook feature we can use for this purpose, and we can use any protocol supported on the Debian base system, including things such as FUSE or s3cmd.</description>
      <content>&lt;p&gt;Proxmox has a pretty good backup scheduler, but it relies on the backup destination being mounted as a storage location. This implies that the backup destination needs to be a protocol that Proxmox supports - SMB (CIFS), NFS, &amp;hellip; or Proxmox Backup Server. If you want to push your backups to a cloud service, you probably need something a bit more complicated. Thankfully, Proxmox&amp;rsquo;s backup scheduler thought about this and has a hook feature we can use for this purpose, and we can use any protocol supported on the Debian base system, including things such as FUSE or s3cmd.&lt;/p&gt;
&lt;p&gt;In this project, I integrate S3 object storage with the Proxmox backup scheduler, copying resulting backups to a cloud storage service directly from the Proxmox system. The S3 protocol is ubiquitous among cloud object storage providers, so we aren&amp;rsquo;t tied to AWS - we can use any service such as Backblaze. In my case, I&amp;rsquo;m demonstrating this with Linode.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/pve_backup/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/pve_backup/#proxmox-vzdump-hook-scripting&#34;&gt;Proxmox VZDump hook scripting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/pve_backup/#s3-tools&#34;&gt;S3 Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/pve_backup/#backup-expiration-script&#34;&gt;Backup Expiration Script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/pve_backup/#final-backup-script&#34;&gt;Final Backup Script&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;Click on the thumbnail to view the video on Youtube
&lt;a href=&#34;https://youtu.be/aFDX2CDTJCE&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/pve_backup/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;proxmox-vzdump-hook-scripting&#34;&gt;Proxmox VZDump hook scripting&lt;/h1&gt;
&lt;p&gt;Proxmox&amp;rsquo;s documentation mentions briefly that the &lt;code&gt;--script&lt;/code&gt; argument can be passed to &lt;code&gt;vzdump&lt;/code&gt;, the Proxmox backup utility. We can also add the line &lt;code&gt;script &amp;lt;path_to_script&amp;gt;&lt;/code&gt; in the &lt;code&gt;/etc/pve/jobs.conf&lt;/code&gt; file, and it will retain this script argument even if you modify the backup job from the GUI. You can&amp;rsquo;t add a script command from the GUI, but you need to initially create the job there.&lt;/p&gt;
&lt;p&gt;Proxmox mentions a backup file (&lt;code&gt;vzdump-hook-script.pl&lt;/code&gt;), but I was unable to find a copy easily. For your convenience, I&amp;rsquo;ve uploaded it to my site &lt;a href=&#34;https://www.apalrd.net/posts/2022/pve_backup/vzdump-hook-script.pl&#34;&gt;here&lt;/a&gt; for you to view. The tl;dr is that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first argument to the script is the phase, which is one of:
&lt;ul&gt;
&lt;li&gt;job-start&lt;/li&gt;
&lt;li&gt;job-end&lt;/li&gt;
&lt;li&gt;job-abort&lt;/li&gt;
&lt;li&gt;backup-start&lt;/li&gt;
&lt;li&gt;backup-end&lt;/li&gt;
&lt;li&gt;backup-abort&lt;/li&gt;
&lt;li&gt;log-end&lt;/li&gt;
&lt;li&gt;pre-stop&lt;/li&gt;
&lt;li&gt;pre-restart&lt;/li&gt;
&lt;li&gt;post-restart&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The &amp;lsquo;job&amp;rsquo; type phases are called once for a job, while the rest are called for each backup in the job&lt;/li&gt;
&lt;li&gt;The backup mode (stop/suspend/snapshot) and vmid are passed as arguments to the non-job types&lt;/li&gt;
&lt;li&gt;Additional information is passed as environment variables for certain phases, including &lt;code&gt;TARGET&lt;/code&gt; (the full path on the local system to the backup file), &lt;code&gt;LOGFILE&lt;/code&gt; (the full path to the log file), and a few other useful attributes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our case, we are going to hook to the &lt;code&gt;job-end&lt;/code&gt;, &lt;code&gt;backup-end&lt;/code&gt;, and &lt;code&gt;log-end&lt;/code&gt; phases and do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For &lt;code&gt;backup-end&lt;/code&gt;, copy the file &lt;code&gt;TARGET&lt;/code&gt; to the S3 bucket and delete the original&lt;/li&gt;
&lt;li&gt;For &lt;code&gt;log-end&lt;/code&gt;, copy the file &lt;code&gt;LOGFILE&lt;/code&gt; to the S3 bucket and delete the original&lt;/li&gt;
&lt;li&gt;For &lt;code&gt;job-end&lt;/code&gt;, check if there are any backups which should be expired and remove them. This is done only once, even if there are multiple VMs to backup in a single job.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;s3-tools&#34;&gt;S3 Tools&lt;/h1&gt;
&lt;p&gt;There are a few different open source options for general purpose file management using the S3 protocol. The most common are &lt;code&gt;s3cmd&lt;/code&gt; and &lt;code&gt;s3fs-fuse&lt;/code&gt;. The first provides a command line utility to perform actions on an S3 bucket (ls, put, get, delete, &amp;hellip;) and the second implements a filesystem backed by an S3 bucket. Since the S3 protocol can only replace files (not modify parts of a file), &lt;code&gt;s3fs-fuse&lt;/code&gt; can be quite slow depending on how files are written/read. Given the use of hook scripts here, I&amp;rsquo;ve decided to use &lt;code&gt;s3cmd&lt;/code&gt;. It&amp;rsquo;s easily installed by running &lt;code&gt;apt install s3cmd&lt;/code&gt; on Proxmox.&lt;/p&gt;
&lt;p&gt;Once &lt;code&gt;s3cmd&lt;/code&gt; is installed, we need to configure it by running &lt;code&gt;s3cmd --configure&lt;/code&gt;. It will ask you a few questions, and the answers will depend on your cloud storage provider. They should have a guide on configuring S3 access with their service (i.e. Linode&amp;rsquo;s is &lt;a href=&#34;https://www.linode.com/docs/products/storage/object-storage/guides/s3cmd/&#34;&gt;here&lt;/a&gt;). I&amp;rsquo;ve walked through my own setup in the video.&lt;/p&gt;
&lt;p&gt;Once we run configure, it will generate a file called &lt;code&gt;~/.s3cfg&lt;/code&gt; which includes the access key and endpoint URL. Since we ran this as root, it will be &lt;code&gt;/root/.s3cfg&lt;/code&gt; on our Proxmox host. That&amp;rsquo;s fine, since backup jobs run as root.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in the details, feel free to read the &lt;a href=&#34;https://s3tools.org/usage&#34;&gt;s3cmd docs here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve verified that you have &lt;code&gt;s3cmd&lt;/code&gt; installed and can &lt;code&gt;s3cmd ls&lt;/code&gt; and &lt;code&gt;s3cmd put&lt;/code&gt; to the target bucket, we can add the s3 put&amp;rsquo;s to our backup script.&lt;/p&gt;
&lt;h1 id=&#34;backup-expiration-script&#34;&gt;Backup Expiration Script&lt;/h1&gt;
&lt;p&gt;I &lt;a href=&#34;https://gist.github.com/JProffitt71/9044744&#34;&gt;found a script&lt;/a&gt; to handle expiration of files in S3. I&amp;rsquo;ve copied it here for reference. I named it &lt;code&gt;s3cleanup.sh&lt;/code&gt; on my system.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Usage: ./s3cleanup.sh &amp;#34;bucketname&amp;#34; &amp;#34;7 days&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s3cmd ls s3://$1 | grep &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; DIR &amp;#34;&lt;/span&gt; -v | &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; read -r line;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    createDate&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;echo $line|awk &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;print $1&amp;#34; &amp;#34;$2&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    createDate&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;date -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$createDate&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;+%s&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    olderThan&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;date -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$2&lt;span style=&#34;color:#e6db74&#34;&gt; ago&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;+%s&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; $createDate -le $olderThan &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        fileName&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;echo $line|awk &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;print $4&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; $fileName !&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            printf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Deleting &amp;#34;%s&amp;#34;\n&amp;#39;&lt;/span&gt; $fileName
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            s3cmd del &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$fileName&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Don&amp;rsquo;t forget to &lt;code&gt;chmod +x&lt;/code&gt; it once you are done.&lt;/p&gt;
&lt;h1 id=&#34;final-backup-script&#34;&gt;Final Backup Script&lt;/h1&gt;
&lt;p&gt;Here is the final backup script which you can copy to your system. Again, don&amp;rsquo;t forget to &lt;code&gt;chmod +x&lt;/code&gt; it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/usr/bin/perl -w&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Hook script for vzdump to backup to an S3 bucket&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 2022 Andrew Palardy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Based on example hook script from Proxmox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;use&lt;/span&gt; strict;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Define the name of your bucket here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $bucket &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;apalrd-proxmox&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The S3 endpoint comes from the s3cmd --configure setup, it is not set here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Define the number of days to retain backups in the bucket&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Only accepts days, doesn&amp;#39;t check hours/minutes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $retain &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Uncomment this to see the hook script with arguments (not required)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#print &amp;#34;HOOK: &amp;#34; . join (&amp;#39; &amp;#39;, @ARGV) . &amp;#34;\n&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Get the phase from the first argument&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $phase &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; shift;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#For job-based phases&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Note that job-init was added in PVE 7.2 or 7.3 AFAIK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (    $phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;job-init&amp;#39;&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        $phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;job-start&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        $phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;job-end&amp;#39;&lt;/span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        $phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;job-abort&amp;#39;&lt;/span&gt;) { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Env variables available for job based arguments&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $dumpdir &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $ENV{DUMPDIR};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $storeid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $ENV{STOREID};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Uncomment this to print the environment variables for debugging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#print &amp;#34;HOOK-ENV: dumpdir=$dumpdir;storeid=$storeid\n&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Call s3cleanup at job end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ($phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;job-end&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                system (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/root/s3cleanup.sh $bucket \&amp;#34;$retain days\&amp;#34;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#For backup-based phases&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;elsif&lt;/span&gt; ($phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;backup-start&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         $phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;backup-end&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         $phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;backup-abort&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         $phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;log-end&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         $phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;pre-stop&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         $phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;pre-restart&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         $phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;post-restart&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Data available to backup-based phases&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $mode &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; shift; &lt;span style=&#34;color:#75715e&#34;&gt;# stop/suspend/snapshot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $vmid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; shift;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $vmtype &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $ENV{VMTYPE}; &lt;span style=&#34;color:#75715e&#34;&gt;# lxc/qemu&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $dumpdir &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $ENV{DUMPDIR};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $storeid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $ENV{STOREID};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $hostname &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $ENV{HOSTNAME};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $tarfile &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $ENV{TARGET};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $logfile &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $ENV{LOGFILE}; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Uncomment this to print environment variables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#print &amp;#34;HOOK-ENV: vmtype=$vmtype;dumpdir=$dumpdir;storeid=$storeid;hostname=$hostname;tarfile=$tarfile;logfile=$logfile\n&amp;#34;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# During backup-end, copy the target file to S3 and delete the original on the system&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ($phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;backup-end&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;#S3 put&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; system (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;s3cmd put $tarfile s3://$bucket/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;#rm original&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                system (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rm $tarfile&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;#Die of error returned&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;($result &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        die &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;upload backup failed&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# During log-end, copy the log file to S3 and delete the original on the system (same as target file)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ($phase &lt;span style=&#34;color:#f92672&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;log-end&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;my&lt;/span&gt; $result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; system (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;s3cmd put $logfile s3://$bucket/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                system (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rm $logfile&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;($result &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        die &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;upload logfile failed&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Otherwise, phase is unknown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        die &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;got unknown phase &amp;#39;$phase&amp;#39;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit (&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Sub-$100 Networked 433Mhz Receiver for Home Assistant</title>
      <link>https://www.apalrd.net/posts/2022/sdr_rtl433/</link>
      <pubDate>Thu, 20 Oct 2022 07:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/sdr_rtl433/</guid>
      <description>I previously wrote about my install of RTL-433 on a Raspberry Pi, running Raspberry Pi OS Buster. With the release of Bullseye, rtl-433 is now merged into the repository and doesn&amp;rsquo;t need to be compiled from source. So, I thought it would be a good time to revisit this project and make a video about it, this time using a cheap eBay thin client instead of a raspberry pi, and showcasing my setup a bit.</description>
      <content>&lt;p&gt;I &lt;a href=&#34;https://www.apalrd.net/posts/2021/rtl433/&#34;&gt;previously wrote about my install of RTL-433&lt;/a&gt; on a Raspberry Pi, running Raspberry Pi OS Buster. With the release of Bullseye, rtl-433 is now merged into the repository and doesn&amp;rsquo;t need to be compiled from source. So, I thought it would be a good time to revisit this project and make a video about it, this time using a cheap eBay thin client instead of a raspberry pi, and showcasing my setup a bit. As I&amp;rsquo;m using Home Assistant in my home automation system, anything that can publish to MQTT can be brought in, so buying fairly cheap off the shelf sensors which are rugged enough to survive for years outdoors is a great use case for me, even if there is virtually no security in the 433Mhz world. Overall, I was able to setup the receiver for under $100, which is pretty good as far as home automation products go.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/sdr_rtl433/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/sdr_rtl433/#software-installation&#34;&gt;Software Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/sdr_rtl433/#home-assistant-configuration&#34;&gt;Home Assistant Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/sdr_rtl433/#parts-and-software&#34;&gt;Parts and Software&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;Click on the thumbnail to view the video on Youtube
&lt;a href=&#34;https://youtu.be/_COwsvkxyFA&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/sdr_rtl433/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;software-installation&#34;&gt;Software Installation&lt;/h1&gt;
&lt;p&gt;First off, I chose Debian 11 (Bullseye) since it&amp;rsquo;s a pretty familiar OS to a lot of Linux users, it&amp;rsquo;s very easy to setup, and includes rtl-433 in the package repository now. So, after setting installing Debian on my thin client, I just need to install rtl-433, right?&lt;/p&gt;
&lt;p&gt;Well yes, we do need to install it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install rtl-433
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But once it&amp;rsquo;s installed, it doesn&amp;rsquo;t configure and launch itself as a service like we want. We can try out rtl433 by running it using sudo to get a feel for what options we might want for our service install. In my case, I use most of the default options and specify an MQTT server as the output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rtl_433 -C si -F &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mqtt://&amp;lt;server&amp;gt;:1883,user=&amp;lt;user&amp;gt;,pass=&amp;lt;pass&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now we need to make a systemd script so it can launch on boot and use the service logging functions of systemd.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo touch /etc/systemd/system/rtl433.service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo chmod &lt;span style=&#34;color:#ae81ff&#34;&gt;664&lt;/span&gt; etc/systemd/system/rtl433.service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo nano /etc/systemd/system/rtl433.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the file contents (obviously change your MQTT configuration):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Description&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;rtl_433 SDR Receiver Daemon&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;After&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;network-online.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ExecStart&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/usr/bin/rtl_433 -C si -F &amp;#34;mqtt://&amp;lt;broker&amp;gt;:1883,user=&amp;lt;user&amp;gt;,pass=&amp;lt;pass&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Restart&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WantedBy&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;multi-user.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you installed via package like me, it will be in &lt;code&gt;/usr/bin/rtl_433&lt;/code&gt;. If you compile it from source for any reason, it will be in &lt;code&gt;/usr/local/bin/rtl_433&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s basically it. Tell systemd to reload daemons since we changed it&amp;rsquo;s service files, then enable / start the service.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl start rtl433
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable rtl433
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;home-assistant-configuration&#34;&gt;Home Assistant Configuration&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;m using a relatively dated version of Home Assistant and I know there&amp;rsquo;s a lot of changes going on in the UI, but here&amp;rsquo;s what I have in my manual MQTT configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Outdoor temperature and humidity sensor (Acurite 609TXC)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Outdoor Temperature&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;outdoor_temperature&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rtl_433/zeus/devices/Acurite-609TXC/252/temperature_C&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;°C&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Outdoor Humidity&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;outdoor_humidity&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rtl_433/zeus/devices/Acurite-609TXC/252/humidity&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;parts-and-software&#34;&gt;Parts and Software&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/merbanan/rtl_433#running&#34;&gt;RTL-433 Software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dell Wyse 3040 Thin Client &lt;a href=&#34;https://ebay.us/IHLTaf&#34;&gt;From Ebay&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nooelec NESDR Mini 2+ &lt;a href=&#34;https://amzn.to/3go6CZZ&#34;&gt;From Amazon&lt;/a&gt; or &lt;a href=&#34;https://www.nooelec.com/store/nesdr-mini-2-plus.html&#34;&gt;From Nooelec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Acurite 609TXC replacement sensor &lt;a href=&#34;https://amzn.to/3eH5LmA&#34;&gt;From Amazon&lt;/a&gt; or &lt;a href=&#34;https://www.acurite.com/shop-all/weather-instruments/weather-sensors-and-parts/replacement-parts/indoor-outdoor-temperature-humidity-sensor.html&#34;&gt;From Accurite (choose option 2)&lt;/a&gt;
Some links to products may be affiliate links, which may earn a commission for me.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>CNC Router Web Control Appliance</title>
      <link>https://www.apalrd.net/posts/2022/cnc_js/</link>
      <pubDate>Thu, 13 Oct 2022 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/cnc_js/</guid>
      <description>In this part of the 3018 Desktop Router project, I setup a permanent home for CNCjs on a Dell Wyse 3040 thin client. I&amp;rsquo;m running CNCjs as the CNC control software and G-code sender (the CNC&amp;rsquo;s grbl controller is actually doing the motion control). I&amp;rsquo;m using mjpg-streamer to add a USB webcam to the CNCjs web UI, with nearly no load on the CPU to encode. And I&amp;rsquo;ve setup a script to launch ffmpeg to record the mjpeg stream when g-code is started and stopped (also using nearly no load on the CPU to transcode).</description>
      <content>&lt;p&gt;In this part of the 3018 Desktop Router project, I setup a permanent home for CNCjs on a Dell Wyse 3040 thin client. I&amp;rsquo;m running CNCjs as the CNC control software and G-code sender (the CNC&amp;rsquo;s grbl controller is actually doing the motion control). I&amp;rsquo;m using mjpg-streamer to add a USB webcam to the CNCjs web UI, with nearly no load on the CPU to encode. And I&amp;rsquo;ve setup a script to launch ffmpeg to record the mjpeg stream when g-code is started and stopped (also using nearly no load on the CPU to transcode). As a cherry on top, I&amp;rsquo;m running all of this with systemd services so everything autostarts properly on boot without the hacky cron suggestions of the CNCjs docs.&lt;/p&gt;
&lt;p&gt;Any Linux single board computer will of course work, including a raspberry pi, but the 3040s are really cheap and tiny, and come with a case and storage for less than the cost of a bare Pi.&lt;/p&gt;
&lt;p&gt;This video is the part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/cnc/&#34;&gt;CNC Router Megaproject&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#cncjs&#34;&gt;CNCjs&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#install&#34;&gt;Install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#cncjs-test-run&#34;&gt;CNCjs Test Run&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#cncjs-systemd-service&#34;&gt;CNCjs Systemd Service&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#webcam-streaming&#34;&gt;Webcam Streaming&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#v4l2-ctl&#34;&gt;v4l2-ctl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#mjpg-streamer&#34;&gt;mjpg-streamer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#webcam-test-run&#34;&gt;Webcam Test Run&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#webcam-systemd-service&#34;&gt;Webcam Systemd Service&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#recording&#34;&gt;Recording&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#ffmpeg&#34;&gt;ffmpeg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#network-mount-using-autofs&#34;&gt;Network Mount using Autofs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#startstop-scripts&#34;&gt;Start/Stop Scripts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#final-cncjs-configuration&#34;&gt;Final CNCjs Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/#parts-and-links&#34;&gt;Parts and Links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video&#34;&gt;Video&lt;/h1&gt;
&lt;p&gt;Click the thumbnail to view the video on Youtube
&lt;a href=&#34;https://youtu.be/AZdw8djAeMc&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/cnc_js/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;cncjs&#34;&gt;CNCjs&lt;/h1&gt;
&lt;p&gt;The actual web UI I&amp;rsquo;ve chosen is CNCjs, a node.js based web app for controlling CNC machines which use an open source control board based on grbl, Smoothieware, or TinyG. It&amp;rsquo;s actually just a fancy G-code sender, interpretation of the G-code and motion control is done by the router&amp;rsquo;s control board (which in many cases runs grbl).&lt;/p&gt;
&lt;h2 id=&#34;install&#34;&gt;Install&lt;/h2&gt;
&lt;p&gt;CNCjs is written in node.js and available through the node package manager. To install it though, we first must install node.js (package &lt;code&gt;nodejs&lt;/code&gt;) and the node package manager (&lt;code&gt;npm&lt;/code&gt;) - this will take a very long time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install nodejs npm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once complete, we can use npm to install cncjs using node:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo npm install -g cncjs --unsafe-perms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;cncjs-test-run&#34;&gt;CNCjs Test Run&lt;/h2&gt;
&lt;p&gt;To test cncjs, we should be able to just run it as the current user - try this command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cncjs --allow-remote-access -p &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we can edit &lt;code&gt;.cncrc&lt;/code&gt; to add allowRemoteAccess so we don&amp;rsquo;t need to pass it as an argument any more. See my final &lt;code&gt;.cncrc&lt;/code&gt; at the end of this post for the configuration I ended up with.&lt;/p&gt;
&lt;p&gt;To give us permissions to run on port 80 without root, we could delegate this capability to the cncjs binary (&lt;code&gt;/usr/local/bin/cncjs&lt;/code&gt;, which is actually a symlink into &lt;code&gt;/usr/local/lib/node_modules/&lt;/code&gt;). But, actually, we need to give this to the node.js binary, since that&amp;rsquo;s the process that ultimately will run and needs the permissions.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo setcap CAP_NET_BIND_SERVICE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;+eip /usr/bin/node
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also, to give permissions to use the serial port, we need to add our local user to the group &lt;code&gt;dialout&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo usermod -a -G dialout discovery
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;cncjs-systemd-service&#34;&gt;CNCjs Systemd Service&lt;/h2&gt;
&lt;p&gt;This will make CNCjs run as a system service. We can do the usual stuff with &lt;code&gt;systemctl&lt;/code&gt;, which is how services should be managed on distros which use systemd. So, let&amp;rsquo;s create the service file and edit it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo touch /etc/systemd/system/cncjs.service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo chmod &lt;span style=&#34;color:#ae81ff&#34;&gt;664&lt;/span&gt; /etc/systemd/system/cncjs.service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo nano /etc/systemd/system/cncjs.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now the service contents. Notably, running as our local user in the local user&amp;rsquo;s home directory.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Description&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;CNC Controller Web UI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;After&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;network-online.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ExecStart&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;cncjs -p 80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;User&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;discovery&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WorkingDirectory&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/home/discovery&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Restart&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WantedBy&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;multi-user.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can start and enable the service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl start cncjs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable cncjs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;webcam-streaming&#34;&gt;Webcam Streaming&lt;/h1&gt;
&lt;p&gt;We have a few pieces of software to install. Notably, &lt;code&gt;v4l2-ctl&lt;/code&gt; and &lt;code&gt;mjpg-streamer&lt;/code&gt; along with dependencies.&lt;/p&gt;
&lt;h2 id=&#34;v4l2-ctl&#34;&gt;v4l2-ctl&lt;/h2&gt;
&lt;p&gt;If you want to see the capabilities of your camera or identify which one is which, you can use &lt;code&gt;v4l2-ctl&lt;/code&gt; to do so. If you only have one camera and assume it supports MJPEG and is &lt;code&gt;/dev/video0&lt;/code&gt;, you can skip this if you&amp;rsquo;d like.&lt;/p&gt;
&lt;p&gt;Install it using apt:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install v4l-utils
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;List devices - &lt;code&gt;sudo v4l2ctl --list-devices&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you have more than one device (not /dev/video* nodes, actual devices) you can specify the device using &lt;code&gt;-d /dev/videoX&lt;/code&gt; in the following commands. If you have multiple cameras, then do this for each.&lt;/p&gt;
&lt;p&gt;Then list formats - &lt;code&gt;sudo v4l2-ctl --list-formats&lt;/code&gt; - it should show MJPEG as an option. If it doesn&amp;rsquo;t, all will still work fine, but the CPU will encode the images as JPEG and it will put more load on the processor.&lt;/p&gt;
&lt;p&gt;You can also do &lt;code&gt;sudo v4l2-ctl --all&lt;/code&gt; to see everything. This should include the maximum resolution for the camera. You&amp;rsquo;ll need to note that for later.&lt;/p&gt;
&lt;h2 id=&#34;mjpg-streamer&#34;&gt;mjpg-streamer&lt;/h2&gt;
&lt;p&gt;mjpg-streamer is a project which was originally designed to allow extremely low resource Linux systems to host camera streams, by relying entirly on the webcam hardware to JPEG-encode each image (resulting in a motion-JPEG stream). mjpg-streamer then only has to deal with shuffling bytes around to the HTTP clients. It&amp;rsquo;s been updated to support the Pi camera (if you want to use that), and can also encode to MJPEG if the camera doesn&amp;rsquo;t support it (at the cost of higher CPU usage). Since we need an HTTP MJPEG stream for the CNCjs camera widget, we can&amp;rsquo;t use h.264 here, so relying on the camera&amp;rsquo;s MJPEG codec is the lowest resource way to achieve this. The bitrate is fairly high (~35mbps for my setup) which will make the recordings bigger, but you can always transcode the recordings before keeping them.&lt;/p&gt;
&lt;p&gt;Anyway, let&amp;rsquo;s install it. In this case, it&amp;rsquo;s not available from &lt;code&gt;apt&lt;/code&gt;, so we are going to install dependencies through apt and then build it from source.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install cmake libjpeg8-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/jacksonliam/mjpg-streamer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd mjpg-streamer/mjpg-streamer-experimental
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo make install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;webcam-test-run&#34;&gt;Webcam Test Run&lt;/h2&gt;
&lt;p&gt;mjpg-streamer has different modules to deal with input and output, so in this case we are using &lt;code&gt;input_uvc&lt;/code&gt; which deals with v4l2 devices and &lt;code&gt;output_http&lt;/code&gt; which provides an http webserver for streams and snapshots. You can pass arguments to both modules, in this case I&amp;rsquo;m passing a device and resolution (make sure to choose something your device supports!).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mjpg_streamer -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;input_uvc.so -d /dev/video0 -r 1920x1080&amp;#34;&lt;/span&gt; -o &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;output_http.so -p 8080&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can leave out the device option if you only have one camera. We need to use sudo to gain permissions to access the /dev/video devices, since we aren&amp;rsquo;t adding ourselves to the video group. Systemd will run the service as root by default anyway.&lt;/p&gt;
&lt;h2 id=&#34;webcam-systemd-service&#34;&gt;Webcam Systemd Service&lt;/h2&gt;
&lt;p&gt;First, create the script - you can replace &lt;code&gt;webcamd&lt;/code&gt; with whatever you want, i.e. if you are using multiple cameras&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo touch /etc/systemd/system/webcamd.service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo chmod &lt;span style=&#34;color:#ae81ff&#34;&gt;664&lt;/span&gt; /etc/systemd/system/webcamd.service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo nano /etc/systemd/system/webcamd.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now the service contents. Make sure your devices supports the resolution you specify!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Description&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Webcam Stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;After&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;network-online.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ExecStart&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;mjpg_streamer -i &amp;#34;input_uvc.so -d /dev/video0 -r 1920x1080&amp;#34; -o &amp;#34;output_http.so -p 8080&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Restart&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WantedBy&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;multi-user.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can start and enable the service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl start webcamd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable webcamd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;recording&#34;&gt;Recording&lt;/h1&gt;
&lt;p&gt;Finally, nearing the end of this big software dump. The final step is to start and stop recordings from CNCjs, preferably automatically, in a location we can access easily, and also with the ability to manually start and stop recordings.&lt;/p&gt;
&lt;h2 id=&#34;ffmpeg&#34;&gt;ffmpeg&lt;/h2&gt;
&lt;p&gt;We will record the stream with ffmpeg. Depending on the GPU you are running on, you may be able to use &lt;code&gt;libva&lt;/code&gt; hardware acceleration. In my setup, I am using mjpg passthrough, so the resulting file is a .mjpeg and is not transcoding to a more space efficient codec. This reduces CPU usage dramatically if &lt;code&gt;libva&lt;/code&gt; doesn&amp;rsquo;t support both MJPEG decoding and h.264 encoding on your hardware. Not many programs can play back the .mjpeg file directly, but you can always transcode it to h.264 in ffmpeg or Handbrake for a more universal format (and you probably should to keep file sizes reasonable).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ffmpeg -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://localhost:8080/?action=stream&amp;#34;&lt;/span&gt; -codec copy /mnt/cnc/test1.mjpeg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;network-mount-using-autofs&#34;&gt;Network Mount using Autofs&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve chosen to network mount my recordings directory using autofs. You can use a directory on the system if you have enough space. My 3040 thin client has 8GB of emmc, so it can&amp;rsquo;t really fit any recordings. Here&amp;rsquo;s the basic process to setup autofs for this use case:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install autofs and the cifs (samba) client:  &lt;code&gt;sudo apt install autofs cifs-utils&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create a mount point: &lt;code&gt;sudo mkdir /mnt/cnc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Edit &lt;code&gt;/etc/auto.master&lt;/code&gt; using sudo and add the following line: &lt;code&gt;/- /etc/auto.smb.shares --timeout 15 browse&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add a new share in that new file, again as root:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/mnt/cnc -fstype=cifs,rw,username=&amp;lt;user&amp;gt;,password=&amp;lt;password&amp;gt;,noperm ://server/share/directory
&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&#34;5&#34;&gt;
&lt;li&gt;Then enable and start autofs&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable autofs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl restart autofs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;6&#34;&gt;
&lt;li&gt;You should be able to see the network share - &lt;code&gt;ls /mnt/cnc&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;startstop-scripts&#34;&gt;Start/Stop Scripts&lt;/h2&gt;
&lt;p&gt;Now that we have a place to store the recordings and a command to record, we need to be able to spawn this from cncjs on command. Here are the scripts to do that with &lt;code&gt;~/rec-start.sh&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Date/time stamp for new recording&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fname&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;date +%F_%H-%M-%S&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Call ffmpeg with filename cnc_&amp;lt;date&amp;gt;.mjpeg in the background&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ffmpeg -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://localhost:8080/?action=stream&amp;#34;&lt;/span&gt; -codec copy /mnt/cnc/cnc_$fname.mjpeg -nostats &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#End terminal session&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;disown
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And to stop, we kill ffmpeg with &lt;code&gt;~/rec-stop.sh&lt;/code&gt; and it will clean up itself nicely:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;killall ffmpeg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;final-cncjs-configuration&#34;&gt;Final CNCjs Configuration&lt;/h1&gt;
&lt;p&gt;Here is my final configuration file for CNCjs, in case you&amp;rsquo;d like to copy anything from it. All of this can be configured via the web UI if you like as well.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;state&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;checkForUpdates&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;controller&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;exception&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;ignoreErrors&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;secret&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$2a$10$FBerJXHRoBaO0YD4nVZUM.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;allowRemoteAccess&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;commands&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;727d8fa0-0790-44f0-a9bb-6fcb992fab2d&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;mtime&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1665444504169&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Start Record&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;commands&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/home/discovery/rec-start.sh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ec02236a-529d-4fba-a575-70fbce559222&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;mtime&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1665444509575&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Stop Record&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;commands&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/home/discovery/rec-stop.sh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;events&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;80a0b85d-bcab-414a-9c22-0d8a25a83368&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;mtime&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1665444515639&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;event&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gcode:start&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;trigger&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;system&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;commands&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/home/discovery/rec-start.sh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;811d3570-9200-4b9f-88db-38b518f870f6&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;mtime&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1665444519136&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;event&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gcode:stop&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;trigger&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;system&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;commands&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/home/discovery/rec-stop.sh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;parts-and-links&#34;&gt;Parts and Links&lt;/h1&gt;
&lt;p&gt;Some of these may be affiliate links, which may earn a commission for me.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;cnc.js.org&#34;&gt;CNCjs software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sainsmart Genmitsu 3018 PROver router:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.sainsmart.com/collections/cnc-machines/products/sainsmart-genmitsu-cnc-router-3018-prover-kit&#34;&gt;At Sainsmart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3yRzAHZ&#34;&gt;At Amazon (Affiliate Link)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3yM2nO0&#34;&gt;Webcam I am using&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3SajDUe&#34;&gt;CNC tape that I tried and liked&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ebay.us/JOD97E&#34;&gt;Dell Wyse 3040 Thin Client&lt;/a&gt;
Some links to products may be affiliate links, which may earn a commission for me.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>New Toy! HP MicroServer Gen8</title>
      <link>https://www.apalrd.net/posts/2022/microsrv_intro/</link>
      <pubDate>Thu, 06 Oct 2022 07:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/microsrv_intro/</guid>
      <description>Today, I open a new gift to the homelab - an HP MicroServer Gen8. This little chonky cube is full of hard drives and not a whole lot else, making it a perfect test system for ZFS, TrueNAS, Proxmox VE and Proxmox Backup Server, etc. and I&amp;rsquo;m already planning the videos I want to make with it. So come along as I open it up and see roughly what&amp;rsquo;s inside, the specs, and use HP iLO (their proprietary IPMI) for the first time.</description>
      <content>&lt;p&gt;Today, I open a new gift to the homelab - an HP MicroServer Gen8. This little chonky cube is full of hard drives and not a whole lot else, making it a perfect test system for ZFS, TrueNAS, Proxmox VE and Proxmox Backup Server, etc. and I&amp;rsquo;m already planning the videos I want to make with it. So come along as I open it up and see roughly what&amp;rsquo;s inside, the specs, and use HP iLO (their proprietary IPMI) for the first time.&lt;/p&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a video of my fun. Click on the thumbnail to watch it on Youtube.
&lt;a href=&#34;https://youtu.be/yq_zIidPxtw&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/microsrv_intro/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;exterior&#34;&gt;Exterior&lt;/h2&gt;
&lt;p&gt;Here are some pictures of the exterior of the case. There aren&amp;rsquo;t many ports, dual gigabit NICs, two USB2, two USB3, VGA, and iLO&amp;rsquo;s dedicated Ethernet. The one PCIe half height expansion slot has been filled with an LSI SAS card.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Exterior Front&#34; src=&#34;https://www.apalrd.net/posts/2022/microsrv_intro/front.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Exterior Rear&#34; src=&#34;https://www.apalrd.net/posts/2022/microsrv_intro/back.jpg&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;internals&#34;&gt;Internals&lt;/h2&gt;
&lt;p&gt;Inside, there&amp;rsquo;s a handy SD card slot and USB port to plug in your boot media (if you don&amp;rsquo;t want to boot off the data drives). There&amp;rsquo;s also an extra SATA port that&amp;rsquo;s labeled &amp;lsquo;ODD&amp;rsquo; (optical disk drive), although that isn&amp;rsquo;t installed on this model. This modified unit has the power cable for the DVD drive connected to a 2 port Molex to SATA power cable to power the extra 1TB 2.5&amp;quot; hard drives.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Interior&#34; src=&#34;https://www.apalrd.net/posts/2022/microsrv_intro/internal_ports.jpg&#34;&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>My Introduction to CNC - 3018 Desktop Router</title>
      <link>https://www.apalrd.net/posts/2022/cnc_intro/</link>
      <pubDate>Wed, 21 Sep 2022 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/cnc_intro/</guid>
      <description>My dad bought a Sainsmart Genmitsu 3018 PROver CNC router over a year ago, but never really set it up or learned how to use it. Since I enjoy the role of creating and maintaining tools and infrastructure, I decided to help him set it up and operate it to cut thin polycarbonate sheets. In this first episode, I hook the machine up to my laptop and try to cut out a representative model from 1.</description>
      <content>&lt;p&gt;My dad bought a Sainsmart Genmitsu 3018 PROver CNC router over a year ago, but never really set it up or learned how to use it. Since I enjoy the role of creating and maintaining tools and infrastructure, I decided to help him set it up and operate it to cut thin polycarbonate sheets. In this first episode, I hook the machine up to my laptop and try to cut out a representative model from 1.5mm polycarbonate sheet. It goes&amp;hellip; okay&amp;hellip; as you can see in the video.&lt;/p&gt;
&lt;p&gt;I have big plans for this router in the future, including making it literally bigger (3040 upgrade), and setting up one of my absolute favorite &lt;a href=&#34;https://www.apalrd.net/posts/2022/wyse_3040/&#34;&gt;Dell Wyse 3040&lt;/a&gt; thin clients to run it standalone without a control computer. All of that&amp;rsquo;s in the future though.&lt;/p&gt;
&lt;p&gt;This video is the first episode in the &lt;a href=&#34;https://www.apalrd.net/projects/2022/cnc/&#34;&gt;CNC Router Megaproject&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;Click the thumbnail to watch it on Youtube.
&lt;a href=&#34;https://youtu.be/akjSc2-bZpY&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/cnc_intro/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;parts-and-software&#34;&gt;Parts and Software&lt;/h2&gt;
&lt;p&gt;Here are links to some of the hardware and software that make this project possible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CNCjs - &lt;a href=&#34;https://cnc.js.org/&#34;&gt;https://cnc.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;FreeCAD - &lt;a href=&#34;https://www.freecadweb.org/&#34;&gt;https://www.freecadweb.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;grbl - &lt;a href=&#34;https://github.com/gnea/grbl&#34;&gt;https://github.com/gnea/grbl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sainsmart Genmitsu 3018 PROver:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.sainsmart.com/collections/cnc-machines/products/sainsmart-genmitsu-cnc-router-3018-prover-kit&#34;&gt;At Sainsmart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://amzn.to/3yRzAHZ&#34;&gt;At Amazon (Affiliate Link)&lt;/a&gt;
Some links to products may be affiliate links, which may earn a commission for me.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>CNC Router Megaproject</title>
      <link>https://www.apalrd.net/projects/2022/cnc/</link>
      <pubDate>Tue, 20 Sep 2022 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2022/cnc/</guid>
      <description>In this project, I explore the setup, operation, and &amp;rsquo;tricking out&amp;rsquo; of a desktop 3018 class CNC router.
My Introduction to CNC - 3018 Desktop Router In this video, I setup the machine and try to cut out a part using CNCjs. I quickly learn that it&amp;rsquo;s not the easiest thing in the world, makes a huge mess, and is loud. But I will continue on!
CNC Router Web Control Appliance In this part of the 3018 Desktop Router project, I setup a permanent home for CNCjs on a Dell Wyse 3040 thin client.</description>
      <content>&lt;p&gt;In this project, I explore the setup, operation, and &amp;rsquo;tricking out&amp;rsquo; of a desktop 3018 class CNC router.&lt;/p&gt;
&lt;h2 id=&#34;my-introduction-to-cnc---3018-desktop-router&#34;&gt;My Introduction to CNC - 3018 Desktop Router&lt;/h2&gt;
&lt;p&gt;In this video, I setup the machine and try to cut out a part using CNCjs. I quickly learn that it&amp;rsquo;s not the easiest thing in the world, makes a huge mess, and is loud. But I will continue on!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_intro/&#34;&gt;&lt;img alt=&#34;My Introduction to CNC - 3018 Desktop Router&#34; src=&#34;https://www.apalrd.net/posts/2022/cnc_intro/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;cnc-router-web-control-appliance&#34;&gt;CNC Router Web Control Appliance&lt;/h2&gt;
&lt;p&gt;In this part of the 3018 Desktop Router project, I setup a permanent home for CNCjs on a Dell Wyse 3040 thin client. I&amp;rsquo;m running CNCjs as the CNC control software and G-code sender (the CNC&amp;rsquo;s grbl controller is actually doing the motion control). I&amp;rsquo;m using mjpg-streamer to add a USB webcam to the CNCjs web UI, with nearly no load on the CPU to encode. And I&amp;rsquo;ve setup a script to launch ffmpeg to record the mjpeg stream when g-code is started and stopped (also using nearly no load on the CPU to transcode). As a cherry on top, I&amp;rsquo;m running all of this with systemd services so everything autostarts properly on boot and recordings terminate if anything crashes and restarts.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cnc_js/&#34;&gt;&lt;img alt=&#34;CNC Router Web Control Appliance&#34; src=&#34;https://www.apalrd.net/posts/2022/cnc_js/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>A Viewer&#39;s Donation (Part 1) - Dell Wyse 7010</title>
      <link>https://www.apalrd.net/posts/2022/wyse_7010/</link>
      <pubDate>Mon, 16 May 2022 07:07:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/wyse_7010/</guid>
      <description>Casually tearing down the Dell Wyse 7010 (Zx0) that was kindly sent in by a viewer named Tom! Thanks Tom for making this happen. Tom also sent an HP thin client, but you guys only get one treat per video, and that one needed Torx bits that I didn&amp;rsquo;t have handy on the bench. tl;dr the CPU supports AMD-V (not that you really have enough RAM to think about virtualization, but you can expand it with ordinary DDR3 DIMMs), the GPU is kinda awful, and it has a Realtek NIC.</description>
      <content>&lt;p&gt;Casually tearing down the Dell Wyse 7010 (Zx0) that was kindly sent in by a viewer named Tom! Thanks Tom for making this happen. Tom also sent an HP thin client, but you guys only get one treat per video, and that one needed Torx bits that I didn&amp;rsquo;t have handy on the bench. tl;dr the CPU supports AMD-V (not that you really have enough RAM to think about virtualization, but you can expand it with ordinary DDR3 DIMMs), the GPU is kinda awful, and it has a Realtek NIC. I&amp;rsquo;d rather have the 3040 personally, it&amp;rsquo;s compatable in performance in a much smaller package. But, the 7010 is an older model which has upgradeable RAM and might be able to be found more cheaply.&lt;/p&gt;
&lt;h2 id=&#34;teardown-video&#34;&gt;Teardown Video&lt;/h2&gt;
&lt;p&gt;As usual, a teardown video of the hardware!
&lt;a href=&#34;https://youtu.be/SyPwwYmMopg&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/wyse_7010/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;hardware-info-for-the-curious&#34;&gt;Hardware Info for the curious&lt;/h2&gt;
&lt;p&gt;All of this was taken via an Xubuntu 20.04 Live CD, so your kernel may be configured slightly differently&lt;/p&gt;
&lt;h3 id=&#34;lscpu&#34;&gt;lscpu&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;xubuntu@xubuntu:~$ lscpu
Architecture:                    x86_64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
Address sizes:                   36 bits physical, 48 bits virtual
CPU(s):                          2
On-line CPU(s) list:             0,1
Thread(s) per core:              1
Core(s) per socket:              2
Socket(s):                       1
NUMA node(s):                    1
Vendor ID:                       AuthenticAMD
CPU family:                      20
Model:                           2
Model name:                      AMD G-T56N Processor
Stepping:                        0
CPU MHz:                         922.265
BogoMIPS:                        3292.78
Virtualization:                  AMD-V
L1d cache:                       64 KiB
L1i cache:                       64 KiB
L2 cache:                        1 MiB
NUMA node0 CPU(s):               0,1
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Not affected
Vulnerability Meltdown:          Not affected
Vulnerability Spec store bypass: Vulnerable
Vulnerability Spectre v1:        Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2:        Mitigation; Full AMD retpoline, STIBP disabled, RSB filling
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected
Flags:                           fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 c
                                 lflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm 
                                 constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf pni m
                                 onitor ssse3 cx16 popcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm ss
                                 e4a misalignsse 3dnowprefetch ibs skinit wdt hw_pstate vmmcall arat npt l
                                 brv svm_lock nrip_save pausefilter
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Of note, it does support AMD-V if you want to do virtualization. AES is not in the list, so crypto offload for TLS is not available, making this a worse choice for a home server.&lt;/p&gt;
&lt;h3 id=&#34;lspci&#34;&gt;lspci&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;00:00.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 14h Processor Root Complex
00:01.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Wrestler [Radeon HD 6320]
00:01.1 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] Wrestler HDMI Audio
00:11.0 SATA controller: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 SATA Controller [IDE mode] (rev 40)
00:12.0 USB controller: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 USB OHCI0 Controller
00:12.2 USB controller: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 USB EHCI Controller
00:13.0 USB controller: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 USB OHCI0 Controller
00:13.2 USB controller: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 USB EHCI Controller
00:14.0 SMBus: Advanced Micro Devices, Inc. [AMD/ATI] SBx00 SMBus Controller (rev 42)
00:14.2 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] SBx00 Azalia (Intel HDA) (rev 40)
00:14.3 ISA bridge: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 LPC host controller (rev 40)
00:14.4 PCI bridge: Advanced Micro Devices, Inc. [AMD/ATI] SBx00 PCI to PCI Bridge (rev 40)
00:14.5 USB controller: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 USB OHCI2 Controller
00:15.0 PCI bridge: Advanced Micro Devices, Inc. [AMD/ATI] SB700/SB800/SB900 PCI to PCI bridge (PCIE port 0)
00:15.1 PCI bridge: Advanced Micro Devices, Inc. [AMD/ATI] SB700/SB800/SB900 PCI to PCI bridge (PCIE port 1)
00:15.2 PCI bridge: Advanced Micro Devices, Inc. [AMD/ATI] SB900 PCI to PCI bridge (PCIE port 2)
00:16.0 USB controller: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 USB OHCI0 Controller
00:16.2 USB controller: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 USB EHCI Controller
00:18.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 0 (rev 43)
00:18.1 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 1
00:18.2 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 2
00:18.3 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 3
00:18.4 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 4
00:18.5 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 6
00:18.6 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 5
00:18.7 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 7
04:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 06)
05:00.0 USB controller: NEC Corporation uPD720200 USB 3.0 Host Controller (rev 04)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see, it uses a Realtek Ethernet Controller&lt;/p&gt;
&lt;h3 id=&#34;vainfo&#34;&gt;vainfo&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;libva info: VA-API version 1.7.0
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/r600_drv_video.so
libva info: Found init function __vaDriverInit_1_7
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.7 (libva 2.6.0)
vainfo: Driver version: Mesa Gallium driver 21.2.6 for AMD PALM (DRM 2.50.0 / 5.13.0-30-generic, LLVM 12.0.0)
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            :	VAEntrypointVLD
      VAProfileMPEG2Main              :	VAEntrypointVLD
      VAProfileVC1Simple              :	VAEntrypointVLD
      VAProfileVC1Main                :	VAEntrypointVLD
      VAProfileVC1Advanced            :	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileNone                   :	VAEntrypointVideoProc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Significantly less capability than the other devices in codecs and there are no encoder slices available.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Net Booting the Proxmox VDI Client (feat. Alpine Linux)</title>
      <link>https://www.apalrd.net/posts/2022/alpine_vdiclient/</link>
      <pubDate>Thu, 12 May 2022 07:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/alpine_vdiclient/</guid>
      <description>This is a continuation of my previous article on the Net Booted Thin Client. The instructions got way too long, so I created a new article for the client setup. You need a functional server setup (TFTP, HTTP, iPXE) which I did in my previous post. I could use something like Linux Terminal Server Project, but that&amp;rsquo;s a bit overkill for this, and I wanted to learn Alpine anyway, so I&amp;rsquo;ve chosen to use Alpine Linux for the client operating system.</description>
      <content>&lt;p&gt;This is a continuation of my previous article on the Net Booted Thin Client. The instructions got way too long, so I created a new article for the client setup. You need a functional server setup (TFTP, HTTP, iPXE) &lt;a href=&#34;https://www.apalrd.net/post/2022/alpine_pxe/&#34;&gt;which I did in my previous post&lt;/a&gt;. I could use something like Linux Terminal Server Project, but that&amp;rsquo;s a bit overkill for this, and I wanted to learn Alpine anyway, so I&amp;rsquo;ve chosen to use Alpine Linux for the client operating system. It&amp;rsquo;s extremely basic.&lt;/p&gt;
&lt;p&gt;Here, we&amp;rsquo;re gonna create an apkovl file. This is essentially a minimal set of the data on the system, so the system can be recreated. It includes all of the system configuration in &lt;code&gt;/etc&lt;/code&gt;, any other directories you specify, and the &lt;code&gt;/etc/apk/world&lt;/code&gt; file. When the APKOVL is loaded, it will install all of the apk packages in the world file, and apply the apkovl files on top of any defaults.&lt;/p&gt;
&lt;p&gt;We are going to take the ISO image for Alpine Linux, boot it in a VM without a hard disk (live, no installation), and configure it to our liking as a thin client. Once we&amp;rsquo;re happy, we&amp;rsquo;re going to generate an apkovl file and save it to our http server, then delete the VM.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a table of contents. This assumes you have a functional netboot environment including TFTP, HTTP, and iPXE - &lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/&#34;&gt;such as what I setup in my previous article/video&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_vdiclient/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_vdiclient/#basic-alpine-environment&#34;&gt;Basic Alpine Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_vdiclient/#install-pve-vdi-client&#34;&gt;Install PVE VDI Client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_vdiclient/#configure-openbox&#34;&gt;Configure Openbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_vdiclient/#test-that-the-vdi-client-works&#34;&gt;Test that the VDI Client Works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_vdiclient/#autostart-on-boot&#34;&gt;Autostart on Boot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_vdiclient/#create-apkovl&#34;&gt;Create APKOVL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_vdiclient/#copy-apkovl-to-netboot-server&#34;&gt;Copy APKOVL to Netboot Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_vdiclient/#testing&#34;&gt;Testing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;Click on the thumbnail to watch the video for this!
&lt;a href=&#34;TBD&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;basic-alpine-environment&#34;&gt;Basic Alpine Environment&lt;/h2&gt;
&lt;p&gt;The basics of getting Alpine setup:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Login as &lt;code&gt;root&lt;/code&gt; in the base system (no password by default)&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;setup-alpine&lt;/code&gt;, with the following selections:
&lt;ol&gt;
&lt;li&gt;Pick your keyboard layout&lt;/li&gt;
&lt;li&gt;Setup hostname. I chose &lt;code&gt;thinclient&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Setup eth0 for DHCP with no additional configuration&lt;/li&gt;
&lt;li&gt;Set a root password&lt;/li&gt;
&lt;li&gt;Choose timezone (I chose America/Detroit)&lt;/li&gt;
&lt;li&gt;No HTTP proxy information&lt;/li&gt;
&lt;li&gt;Choose &amp;lsquo;1&amp;rsquo; for the mirror (this is alpine&amp;rsquo;s primary mirror)&lt;/li&gt;
&lt;li&gt;Choose none for SSH&lt;/li&gt;
&lt;li&gt;Try boot media as a package repository (for now)&lt;/li&gt;
&lt;li&gt;Disk = none (this will not install Alpine anywhere, just setup the system in RAM)&lt;/li&gt;
&lt;li&gt;Where to store configs = none (this means it won&amp;rsquo;t have a place for &lt;code&gt;lbu&lt;/code&gt;, but it&amp;rsquo;s okay)&lt;/li&gt;
&lt;li&gt;APK cache directory = none (this means it has to go out to the internet to install anything)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Install nano - &lt;code&gt;apk add nano&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Edit &lt;code&gt;/etc/apk/repositories&lt;/code&gt; to comment out the cdrom (first line) and uncomment the community repository (third line)&lt;/li&gt;
&lt;li&gt;Setup the X11 server for graphics - &lt;code&gt;setup-xorg-base&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Install all the stuff we need for a basic kiosk via apk - &lt;code&gt;apk add openbox xterm terminus-font font-noto&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add user - &lt;code&gt;adduser vdi&lt;/code&gt;, follow prompts, then add to input and video groups &lt;code&gt;addgroup vdi input&lt;/code&gt; and &lt;code&gt;addgroup vdi video&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If you want to be fun, you can edit &lt;code&gt;/etc/motd&lt;/code&gt; with your own message, but nobody should see it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;install-pve-vdi-client&#34;&gt;Install PVE VDI Client&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re creating your own netbooted appliance based on this guide, you would install whatever software you want here (like Firefox or Remmina) using apk, set it up, and skip down to &lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_vdiclient/#configure-openbox&#34;&gt;Configure Openbox&lt;/a&gt; to launch your kiosk software of choice graphically. Make sure all files you need for your appliance are stored in either your home directory (&lt;code&gt;/home/vdi&lt;/code&gt;) or in &lt;code&gt;/etc&lt;/code&gt;, otherwise they will be lost when we bundle the APK Overlay.&lt;/p&gt;
&lt;p&gt;Install and configure PVE VDI Client in the simplest way possible. You&amp;rsquo;re free to add your own icons, etc. if you wish, but this uses the ones that Josh created already.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install packages we need specific to the thin client - &lt;code&gt;apk add python3 py3-pip py3-pyside2 virt-viewer git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Login as new user vdi (&lt;code&gt;exit&lt;/code&gt; to logout)&lt;/li&gt;
&lt;li&gt;Install pip packages - &lt;code&gt;pip3 install proxmoxer PySimpleGUIQt requests&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Upgrade PySimpleGUI to 0.35.0 since it doesn&amp;rsquo;t find pyside2 installed via apk - &lt;code&gt;pip3 install PySimpleGUIQt==0.35.0 --no-deps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Clone PVE-VDIClient - &lt;code&gt;git clone https://github.com/joshpatten/PVE-VDIClient.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Make executable - &lt;code&gt;chmod +x ~/PVE-VDIClient/vdiclient.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create config dir - &lt;code&gt;mkdir -p ~/.config/VDIClient&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create config file - &lt;code&gt;nano ~/.config/VDIClient/vdiclient.ini&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And the contents:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[General]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#All of the settings in general can be customized if you want&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;apalrd VDI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;theme&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;DarkAmber&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;icon&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/home/vdi/PVE-VDIClient/vdiicon.ico&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;logo&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/home/vdi/PVE-VDIClient/vdiclient.png&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Authentication]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auth_backend&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;pve&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auth_totp&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tls_verify&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Hosts]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Replace this with your Proxmox host or DNS name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;1.2.3.4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;8006&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configure-openbox&#34;&gt;Configure Openbox&lt;/h2&gt;
&lt;p&gt;Openbox is going to be the window manager here, so we need to configure it to start when X initializes, to launch the VDI client in a run loop, and to start X when the user vdi logs in&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set X to launch on login - &lt;code&gt;echo &#39;exec startx&#39; &amp;gt;&amp;gt; ~/.profile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set openbox as default session - &lt;code&gt;echo &#39;exec openbox-session&#39; &amp;gt;&amp;gt; ~/.xinitrc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Copy Openbox default config - &lt;code&gt;cp -r /etc/xdg/openbox ~/.config&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Remove autostart file - &lt;code&gt;rm ~/.config/openbox/autostart&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;New autostart file - &lt;code&gt;nano ~/.config/openbox/autostart&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And the contents:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ~/PVE-VDIClient/vdiclient.py
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;test-that-the-vdi-client-works&#34;&gt;Test that the VDI Client Works&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;startx&lt;/code&gt; and ensure that the client starts correctly. If it doesn&amp;rsquo;t, right-click on the black background and launch xterm, then try running &lt;code&gt;~/PVE-VDIClient/vdiclient.py&lt;/code&gt; manually to see the terminal output.&lt;/p&gt;
&lt;p&gt;Once you are done, right-click on the black background and launch xterm, then run &lt;code&gt;killall xinit&lt;/code&gt; which should kick you back to the login screen. Try logging in again to make sure you are launched directly into the X session.&lt;/p&gt;
&lt;h2 id=&#34;autostart-on-boot&#34;&gt;Autostart on Boot&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Log back out of vdi (if you are currently in the X session, you have to do &lt;code&gt;killall xinit&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Log in as root with password&lt;/li&gt;
&lt;li&gt;Edit inittab to login as vdi automatically - &lt;code&gt;nano /etc/inittab&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Find this line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tty1::respawn:/sbin/getty &lt;span style=&#34;color:#ae81ff&#34;&gt;38400&lt;/span&gt; tty1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Replace with this line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tty1::respawn:/bin/login -f vdi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;create-apkovl&#34;&gt;Create APKOVL&lt;/h2&gt;
&lt;p&gt;Now we can generate the &lt;code&gt;apkovl.tar.gz&lt;/code&gt;, still logged in as root:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Remove the &lt;code&gt;.ash_history&lt;/code&gt; from vdi so our command history isn&amp;rsquo;t visible to anyone - &lt;code&gt;rm -f /home/vdi/.ash_history&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;(Optional) Remove the packages we installed but only needed for setup so they aren&amp;rsquo;t usable in the final system - &lt;code&gt;apk del git xterm nano&lt;/code&gt; - if you do this, you will have absolutely no way of debugging the setup once it netboots, so make sure it works at this point.&lt;/li&gt;
&lt;li&gt;Include &lt;code&gt;/home&lt;/code&gt; in the lbu package - &lt;code&gt;lbu include /home&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Package the system using lbu - &lt;code&gt;lbu package thinclient.apkovl.tar.gz&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;copy-apkovl-to-netboot-server&#34;&gt;Copy APKOVL to Netboot Server&lt;/h2&gt;
&lt;p&gt;Now we are going to temporarily stand up an HTTP server to offload our .tar.gz. Busybox includes an httpd server, but it&amp;rsquo;s not compiled in the busybox that Alpine includes by default. Thankfully, Alpine provides another busybox binary as a package that includes all options.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install busybox-extras so we have the version with httpd - &lt;code&gt;apk add busybox-extras&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Get our IP address - &lt;code&gt;ip a&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Use busybox-extras to launch an httpd server here - &lt;code&gt;busybox-extras httpd -f -v&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Switch to the netboot server we set up in the previous episode, log in as root&lt;/li&gt;
&lt;li&gt;Change to the www directory - &lt;code&gt;cd /srv/www&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Download the file - &lt;code&gt;wget http://&amp;lt;temp client ip&amp;gt;/thinclient.apkovl.tar.gz&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;testing&#34;&gt;Testing&lt;/h2&gt;
&lt;p&gt;If all goes well, you should be able to boot your client, and as long as PXE is enabled higher than any other bootable devices in the boot order, it should launch into our thin client. You can even configure a VM in Proxmox with no disk and no DVD drive and it should netboot.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Not Every Project Works, And That&#39;s Okay (Multiseat USB Dongles)</title>
      <link>https://www.apalrd.net/posts/2022/failure_blog/</link>
      <pubDate>Mon, 09 May 2022 08:49:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/failure_blog/</guid>
      <description>Sometimes, projects don&amp;rsquo;t work. Today, I&amp;rsquo;m going to describe a bit about a few of them. Thank you for coming to my ted talk lol.
I&amp;rsquo;ve been working on Linux Multiseat for awhile now, it&amp;rsquo;s a topic that has fascinated me for over a decade now. But, getting it to actually work with cheap hardware has eluded me. So, here&amp;rsquo;s a bit of an overview of what I&amp;rsquo;ve learned so far.</description>
      <content>&lt;p&gt;Sometimes, projects don&amp;rsquo;t work. Today, I&amp;rsquo;m going to describe a bit about a few of them. Thank you for coming to my ted talk lol.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been working on Linux Multiseat for awhile now, it&amp;rsquo;s a topic that has fascinated me for over a decade now. But, getting it to actually work with cheap hardware has eluded me. So, here&amp;rsquo;s a bit of an overview of what I&amp;rsquo;ve learned so far.&lt;/p&gt;
&lt;p&gt;The hardware I&amp;rsquo;ve tried:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;WYSE Zero Client - Under $10 shipped, so it didn&amp;rsquo;t hurt to try. It uses a SIS USB VGA chip, which once had support in the Linux kernel, but a lot of the heavy lifting appears to be in the userspace xorg sis driver, and of course neither the kernel driver or xorg driver have been maintained in the past decade. Recompiling the kernel module and adding the USB IDs to the IDs which the driver supports got the kernel to load the correct module, but it provides a special device (not our favorite Linux framebuffer) and I wasn&amp;rsquo;t able to bind an xorg to it. Maybe with some work I could build a kernel space module which exposes a framebuffer instead of their awful junk, but it was done this way originally since the hardware has support for partial redrawing and hardware cursor (so the CPU doesn&amp;rsquo;t have to redraw the regions under the cursor as it moves), which is why it was originally part of the X server. If I get bored, maybe I&amp;rsquo;ll become a kernel developer I guess.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pluggable USB2 DisplayLink dock - This one just came in the mail, and I haven&amp;rsquo;t even plugged it in yet, but this was designed to be used for multiseat way way back when, and Displaylink USB2 drivers for a framebuffer device are in the kernel and &lt;em&gt;should&lt;/em&gt; work just fine. The hardware is a bit dated, with DVI outputs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Random USB-C laptop dock - I tried several docks that I could borrow from friends and family to see how they respond. Most use USB-C DisplayPort, which is to be expected, so they rely entirely on the host GPU. This of course makes them cheaper to produce, but potentially at the expense of USB3 bandwidth. In lsusb they show up as a USB Billboard device, which basically means the USB endpoint exists purely to display a message on your computer saying it doesn&amp;rsquo;t support the dock. No data goes over the USB connection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;USB-C DisplayLink dock - One of the docks I tried supports DisplayLink over USB3. Unfortunately, DisplayLink has decided to go the Nvidia route and produce a proprietary Linux driver, and unlike Nvidia their Linux support is actually terrible. They claim it will support Ubuntu 20.04 LTS and don&amp;rsquo;t guarantee anything else, but even there it didn&amp;rsquo;t really do what I wanted. I was able to get display mirroring to work, but not multiseat. Maybe, with more time, I&amp;rsquo;d be able to fight with the driver enough to get multiseat to work. It&amp;rsquo;s really unfortunate too, since USB3 DisplayLink docks are really common and somewhat affordable now, at least compared to adding a new GPU like I did in my multiseat gaming video.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And of course, the video:
&lt;a href=&#34;https://youtu.be/MdlUhnCo2Ok&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/failure_blog/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Making the $250 Proxmox HA Cluster Hyperconverged</title>
      <link>https://www.apalrd.net/posts/2022/cluster_ceph/</link>
      <pubDate>Thu, 05 May 2022 08:14:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/cluster_ceph/</guid>
      <description>I previously setup a Proxmox high availability cluster on my $35 Dell Wyse 5060 thin clients. Now, I&amp;rsquo;m improving this cluster to make it hyperconverged. It&amp;rsquo;s a huge buzzword in the industry now, and basically, it combines storage and compute in the same nodes, with each node having some compute and some storage, and clustering both the storage and compute. In traditional clustering you have a storage system (SAN) and compute system (virtualization cluster / kubernetes / &amp;hellip;), so merging the SAN into the compute nodes means all of the nodes are identical and network traffic is, in aggregate, going from all nodes to all nodes without a bottleneck between the compute and SAN nodes.</description>
      <content>&lt;p&gt;I previously setup a Proxmox high availability cluster on my $35 Dell Wyse 5060 thin clients. Now, I&amp;rsquo;m improving this cluster to make it &lt;em&gt;hyperconverged&lt;/em&gt;. It&amp;rsquo;s a huge buzzword in the industry now, and basically, it combines storage and compute in the same nodes, with each node having some compute and some storage, and clustering both the storage and compute. In traditional clustering you have a storage system (SAN) and compute system (virtualization cluster / kubernetes / &amp;hellip;), so merging the SAN into the compute nodes means all of the nodes are identical and network traffic is, in aggregate, going from all nodes to all nodes without a bottleneck between the compute and SAN nodes.&lt;/p&gt;
&lt;p&gt;This is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/cluster/&#34;&gt;Hyper-Converged Cluster Megaproject&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_ceph/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_ceph/#cost-accounting&#34;&gt;Cost Accounting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_ceph/#ceph-install&#34;&gt;Ceph Install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_ceph/#ceph-manager-and-dashboard&#34;&gt;Ceph Manager and Dashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_ceph/#object-storage-daemons&#34;&gt;Object Storage Daemons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_ceph/#absolute-basics-of-pools&#34;&gt;Absolute Basics of Pools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the video! Click on the thumbnail to view it
&lt;a href=&#34;https://youtu.be/Vd8GG9twjRU&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/cluster_ceph/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;cost-accounting&#34;&gt;Cost Accounting&lt;/h2&gt;
&lt;p&gt;Since the $250 number is important in the Youtube title, here&amp;rsquo;s the cost breakdown:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I spent $35 each on the thin clients. The seller had a 10% discount for buying 2 or more, so I bought one at full price followed by two more at $31.50 each.&lt;/li&gt;
&lt;li&gt;I spent $25 each on the 8G ram sticks to bring each node up to 12G of RAM&lt;/li&gt;
&lt;li&gt;I spent $16 on each 128G flash drive for my hyperconverged storage. I should note that these guys are pretty darn slow comapred to spinning rust even.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;ceph-install&#34;&gt;Ceph Install&lt;/h2&gt;
&lt;p&gt;Step Zero, have a functional Proxmox cluster. You don&amp;rsquo;t need any storage or VMs, but at least have the nodes already physically connected, Proxmox installed, and joined.&lt;/p&gt;
&lt;p&gt;Step One, go to one node and click the Ceph tab. It will tell you Ceph is not installed. Install the latest, as of the writing of this the latest is Pacific (16.2). You may have to hit enter when the console asks you if you&amp;rsquo;re sure you want to install, then wait for apt to do its magic.&lt;/p&gt;
&lt;p&gt;Since this is our first node, we don&amp;rsquo;t have a Ceph configuration yet, so it will guide us through creating one.&lt;/p&gt;
&lt;p&gt;Select your public and cluster (private) networks. I&amp;rsquo;m going to make a more detailed video on Ceph networking at some point hopefully, but the cluster network is used when Ceph communicates with itself (i.e. rebalancing, distributing copies of data between cluster members) and the public network is used when clients (including Proxmox&amp;rsquo;s RBD client) communicate with the Ceph cluster. Normally the cluster network will handle roughly twice as much traffic as the public network, since data replicated 3 times will be first sent over the public network to the first OSD, which will then send it to the other two OSDs via the cluster network. However, during any drive additions or removals, or when rebalancing is needed, the cluster network can potentially handle significantly more data. You can use a single network for both public and cluster if it is fast enough.&lt;/p&gt;
&lt;p&gt;Also, select the node for the first monitor. I&amp;rsquo;m not sure why they bother asking, if you don&amp;rsquo;t have a cluster setup yet it &lt;em&gt;must&lt;/em&gt; be the node you just installed Ceph onto, since you won&amp;rsquo;t have Ceph installed anywhere else.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve finished the wizard on the first node, go to each other node, click Ceph, it&amp;rsquo;ll say Ceph is not installed, and install it. Once you finish with the apt install, it should say the cluster is already configured and not let you configure it again, so click to finish.&lt;/p&gt;
&lt;p&gt;After everything is installed, you should have a configured cluster, with the monitor and manager installed on the node you chose first. Click on any node under Datacenter, go to Ceph -&amp;gt; Monitors, and create two more so there are 3 total in the cluster. If you have a bigger Proxmox cluster, spread them around a bit if possible, but you don&amp;rsquo;t need more than 3.&lt;/p&gt;
&lt;h2 id=&#34;ceph-manager-and-dashboard&#34;&gt;Ceph Manager and Dashboard&lt;/h2&gt;
&lt;p&gt;Proxmox doesn&amp;rsquo;t install Ceph&amp;rsquo;s dashboard by default, and they have their own dashboard which shows an overview of the cluster, but I like Ceph&amp;rsquo;s dashboard a bit better. Plus, it&amp;rsquo;s much easier to manage more complex pool arrangements through Ceph&amp;rsquo;s GUI than using the command line.&lt;/p&gt;
&lt;p&gt;So, we need to install it. The dashboard runs as part of the manager, so you only need to install it on nodes which are going to run the manager. You don&amp;rsquo;t need many managers, I only setup 2 in this (they are active/passive, not active/active).&lt;/p&gt;
&lt;p&gt;The setup steps, from the shell of the Proxmox system:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the manager package with &lt;code&gt;apt install ceph-mgr-dashboard&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Enable the dashboard module with &lt;code&gt;ceph mgr module enable dashboard&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create a self-signed certificate with &lt;code&gt;ceph dashboard create-self-signed-cert&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create a password for the new admin user and store it to a file. Ceph is actually picky about password rules here. &lt;code&gt;echo MyPassword1 &amp;gt; password.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create a new admin user in the Ceph dashboard with &lt;code&gt;ceph dashboard ac-user-create &amp;lt;name&amp;gt; -i password.txt administrator&lt;/code&gt; - &amp;lsquo;administrator&amp;rsquo; is the role that Ceph has by default, so this user can then create more users through the dashboard&lt;/li&gt;
&lt;li&gt;Delete the password file - &lt;code&gt;rm password.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Restart the manager or disable and re-enable the dashboard (&lt;code&gt;ceph mgr module disable dashboard&lt;/code&gt; and &lt;code&gt;ceph mgr module enable dashboard&lt;/code&gt;). I rebooted the node here. The documentation suggests this shouldn&amp;rsquo;t be required.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As of 2024, &lt;code&gt;create-self-signed-cert&lt;/code&gt; is no longer functional, however, it will return an error message telling you exactly what OpenSSL commands to execute to generate a self-signed cert, so you can follow those instructions.&lt;/p&gt;
&lt;h2 id=&#34;object-storage-daemons&#34;&gt;Object Storage Daemons&lt;/h2&gt;
&lt;p&gt;Ceph stores data a bit differently than a filesystem most of my viewers/readers are probably familiar with - the venerable ZFS.&lt;/p&gt;
&lt;p&gt;In ZFS, you group disks into vdevs, where redundancy is handled at the vdev level. You can then designate certain vdevs with device classes, which are different from normal data disks. This includes L2ARC (second tier of cache), SLOG (dedicated fast space for the synchronous ZFS Intent Log), SPECIAL (separate devices to store metadata separately from file contents, to speed up access to directory listings and the like), and DDT (dedicated to storing deduplication tables). ZFS&amp;rsquo;s metadata stored on disk (or the special vdev) contains the vdev and sector on disk where the data is, so ZFS can start from the uberblock (which contains the pointer to the root of the metadata tree and is stored at several well-known locations on disk) and follow all of the vdev+sector addresses all the way down to individual blocks of files.&lt;/p&gt;
&lt;p&gt;In Ceph, each disk is an OSD (Object Storage Daemon). The OSD should be backed by a single data disk, not hardware or software RAID and not a partition. Each data disk then has its own daemon which communicates with the Ceph monitor and other OSDs, so there&amp;rsquo;s an almost 1:1 correlation between the daemon and physical data disks. Reduncandy is done at a higher level, with Ceph computing which OSD should store data blocks. The Ceph system uses the &amp;lsquo;CRUSH Map&amp;rsquo; to compute the location of data to the OSD level, so the client can communicate directly with the OSD hosting the data. However, within the OSD, the OSD needs to keep track of which sectors on its local disk it has put that data, and this goes in the database. The OSD can keep the database on the data disk, or we can optionally put the OSD&amp;rsquo;s database on a separate disk (guidance suggests allocating 2-4% the size of the disk depending on the workload) to speed up metadata access, similar to a SPECIAL devices in ZFS. Additionally, like ZFS, we can optionally give it a faster device to store synchronous writes to reduce the commit latency (although this does NOT improve throughput), known as the WAL (Write-Ahead Log). If you give the OSD a dedicated DB disk it will automatically use a small bit of that as the WAL, but if you don&amp;rsquo;t have space for a dedicated DB disk you can take a small partition of another disk to just have a dedicated WAL (or both, I guess).&lt;/p&gt;
&lt;p&gt;Since redundancy is usually specified at the host level, it&amp;rsquo;s safe to assume that all disks within a single host could fail at the same time (unless you change the redundancy to be at the OSD level), therefore it&amp;rsquo;s safe to use a partition of a faster disk as the DB for multiple data disks. For example, with a 10TB spinning disk you would want ~400G of DB, so taking a 2TB NVMe SSD and partitioning it to use as the DB disk for 5x spinning disks would be reasonable. Failure of the DB would mean all 5 spinning disks would effectively be lost (since the data can&amp;rsquo;t be located on disk), but we already assumed host-level failure anyway. If you ARE using OSD level redundancy, then don&amp;rsquo;t use partitions for your DB disks.&lt;/p&gt;
&lt;p&gt;The final note here is the device class. You can specify either HDD, SSD, or NVMe by default. This isn&amp;rsquo;t immediately useful, but later we can set rules specifying certain data pools must be located on a certain device class, so setting it correctly is always a good idea. This allows you to avoid creating multiple Ceph clusters in a mixed storage environment. For example, you could create a hyperconverged cluster with Proxmox, having a mix of NVMe and Sata SSD at each node, plus additional storage only nodes with a ton of HDDs. Your VM disks can be pushed to NVMe tiered with SSD, and CephFS can then use SSD tiered with HDD, all in the same cluster, like magic.&lt;/p&gt;
&lt;p&gt;Now to actually set it up: First find the location of the disk (/dev/* path) and zap it: &lt;code&gt;ceph-volume lvm zap /dev/sdX --destroy&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Once the drive is zapped you can add it in Proxmox. Go to the node with the drive, go to Ceph -&amp;gt; OSD, click Create OSD, and it should find the unused disk.&lt;/p&gt;
&lt;h2 id=&#34;absolute-basics-of-pools&#34;&gt;Absolute Basics of Pools&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m just covering the absolute basics of pools here, what you can create in Proxmox&amp;rsquo;s storage pool dialog. There are of course many other ways to configure pools, and I may produce more content in the future on Ceph.&lt;/p&gt;
&lt;p&gt;Create a pool in Proxmox by going to Ceph -&amp;gt; Pools, click Create, enter the information. Of note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name it whatever you want. Proxmox will use this name as the name of it&amp;rsquo;s corresponding storage.&lt;/li&gt;
&lt;li&gt;PG Autoscale should usually be on. This dynamically resizes the number of placement groups (PGs) based on how much data is in the pool.&lt;/li&gt;
&lt;li&gt;Size of 3 means the pool will try to have 3 copies of all data. Min size of 2 means the pool will allow write operations to complete when only 2 of the copies are completed, and allow continued operation on the pool when at least 2 of the copies are intact. This means you can never get into a scenario where losing a host causes loss of any data (as long as Ceph has completed the write), as the write is not completed until the data is on at least 2 hosts, and you can continue operating with at least one host down.&lt;/li&gt;
&lt;li&gt;The CRUSH rule (replicated_rule) is the default, we will get into how to configure this in figure episodes of the series. But the CRUSH rule says things like which disk type and what the failure domain is (defualt host redundancy, and default any disk type). Proxmox has no GUI to configure this.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Mikrotik SXT US with T-Mobile - LTE Backup for the Homelab?</title>
      <link>https://www.apalrd.net/posts/2022/network_lte/</link>
      <pubDate>Mon, 02 May 2022 09:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/network_lte/</guid>
      <description>I&amp;rsquo;ve wanted to play with multi-WAN routing setups for awhile. I thought about buying Starlink, but it&amp;rsquo;s a bit pricey as a purely backup solution, and I&amp;rsquo;m in a situation where my primary internet is very reliable for about the same price. So I settled for LTE backup. I looked around for awhile, trying to decide what the right solution is for me. I really wanted to pass through the IPv4 address and IPv6 prefix from the ISP through to my OPNsense router, since I don&amp;rsquo;t want to deal with triple-NAT and dual layer firewall.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve wanted to play with multi-WAN routing setups for awhile. I thought about buying &lt;a href=&#34;starlink.com&#34;&gt;Starlink&lt;/a&gt;, but it&amp;rsquo;s a bit pricey as a purely backup solution, and I&amp;rsquo;m in a situation where my primary internet is very reliable for about the same price. So I settled for LTE backup. I looked around for awhile, trying to decide what the right solution is for me. I really wanted to pass through the IPv4 address and IPv6 prefix from the ISP through to my &lt;a href=&#34;opnsense.org&#34;&gt;OPNsense&lt;/a&gt; router, since I don&amp;rsquo;t want to deal with triple-NAT and dual layer firewall. A lot of LTE hotspots, even those that support wired Ethernet, still act as firewall routers, and I didn&amp;rsquo;t want that hassle.&lt;/p&gt;
&lt;p&gt;Oh, and also a rant on how we should stop encouraging people to continue using IPv4 and deploying IPv4-only networks because it&amp;rsquo;s &lt;code&gt;easier&lt;/code&gt;. IPv4 is legacy and should be for backwards compatibility only when you are traversing the internet.&lt;/p&gt;
&lt;h2 id=&#34;the-video&#34;&gt;The Video&lt;/h2&gt;
&lt;p&gt;Feel free to watch my video on this topic! Click the thumbnail to view it
&lt;a href=&#34;https://youtu.be/Kk4US5r1Hqc&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/network_lte/thumbnail.png&#34;&gt;&lt;/a&gt;
I made a &lt;code&gt;big oof&lt;/code&gt; in the video and used &lt;code&gt;fast.t-mobile.net&lt;/code&gt; instead of &lt;code&gt;fast.t-mobile.com&lt;/code&gt;. oops.&lt;/p&gt;
&lt;h2 id=&#34;slight-background-on-mobile-networking-and-ipv6-rant&#34;&gt;Slight Background on Mobile Networking, and IPv6 Rant&lt;/h2&gt;
&lt;p&gt;Back in the early days of cellular data, there was a lot of overhead in encapsulating IP frames within cellular data channels. The oldest digital cellular system in use, GSM, was originally designed to carry circuit switched voice traffic and had the option for circuit switched data (basically using the fixed-bandwidth voice channel as an extremely expensive modem). Packet traffic was eventually layered on top, and packets had to be carried across the T1/E1 network which was really not designed to carry packets. GSM used TDMA, &amp;lsquo;Time Division Multiple Access&amp;rsquo;, so each client had a certain time slot in the sequence to transmit a fixed amount of data.&lt;/p&gt;
&lt;p&gt;Eventually 3G came, and it could do variable-bandwidth channels using its CDMA scheme. Both the worldwide UMTS standard and the US/CA CDMA2000 standard used Code Division Multiple Access, where transmissions between all clients and the tower were done at the same time and encoded using different orthogonal codes (Walsh/Hadamard codes). This basically added a ton of error correction code and then relied on the fact that the error correction encoding was different for each client to decipher the message intended for this specific client. The upside to this scheme was the variable bandwidth of the channel, so instead of transferring the client from the RACH channel (random access channel - mobile requests a control channel) to the low-bandwidth control channel to a different higher bandwidth data channel, the tower could change the channel bandwidth as needed. But the system was still primarily circuit-based, with better support for packets.&lt;/p&gt;
&lt;p&gt;Now we have LTE. LTE is a purely packet based network. The entire system is based around IPv6. The RAN (radio access network) translates radio waves to/from IPv6 right at the tower - the eNodeB. From there, it&amp;rsquo;s all networking gear and specialized software.&lt;/p&gt;
&lt;p&gt;The upside to this is we get native IPv6 subnets routed to the client device, and the use of IPv6-only mobile networks has really improved IPv6 uptake (and we desperately need to improve IPv6 uptake). The downside is we don&amp;rsquo;t have native IPv4, like at all. No dual-stack like the cable and fiber companies. You just don&amp;rsquo;t get IPv4.&lt;/p&gt;
&lt;p&gt;The solution mobile operators have to deal with legacy IPv4 services is to use a technique called 464XLAT as well as CGNAT, and also DNS64 is an optional solution as well.&lt;/p&gt;
&lt;p&gt;464XLAT is a way to rewrite the IP header of an IPv4 packet into an IPv6 one, using a special 96-bit prefix and filling the remainder with the IPv4 address. The mobile device (CLAT - client / customer side) will rewrite IPv4 packets into IPv6 ones, send them over the RAN and throught the mobile network, where they are terminated by the PLAT (provider-side), which is the gateway to the IPv4 world.&lt;/p&gt;
&lt;p&gt;DNS64 is a method which can replace the CLAT by rewriting A records (IPv4) with AAAA records (IPv6) using the 96-bit xlat prefix when the site has no native AAAA records, so the application which requested access will then do a native IPv6 connction to the PLAT. For sites which have native AAAA records, the application can stay on IPv6 the entire time.&lt;/p&gt;
&lt;p&gt;Due to IPv4 address exhaustion, at this point we really need to stop giving out public IPv4s to home internet users. If your game server can&amp;rsquo;t handle IPv6 the devs have only had two decades to fix it. So, anyway, mobile ISPs can&amp;rsquo;t allocate a public IPv4 to each device so it can talk to the legacy IPv4 world, so the PLAT will also do CGNAT - network address translation. In theory the devices should be assigned an IPv4 in the 100.64/10 prefix, but T-Mobile seems to be re-using the 6/8 prefix that belongs to the DoD, presumably because the 100.64/10 prefix hadn&amp;rsquo;t been formalized and they were already doing IPv4 CGNAT long before LTE and IPv6 for their GSM network dating back to the late 90s.&lt;/p&gt;
&lt;h2 id=&#34;the-hardware&#34;&gt;The Hardware&lt;/h2&gt;
&lt;p&gt;I ended up selecting the Mikrotik SXT US Kit, which includes a US band LTE modem, decently directional antenna, wired Ethernet with PoE, and RouterOS. RouterOS is &amp;hellip;. dense with configuration options, and I&amp;rsquo;m not that good at managing it, but it&amp;rsquo;s supposed to be able to do a pure passthrough of the LTE modem to an interface without interfering with the network at all.&lt;/p&gt;
&lt;p&gt;I was able to configure this in RouterOS eventually. I&amp;rsquo;m happy with the hardware so far. I stuck it in a window facing roughly the direction of my nearest T-mobile tower and it just worked. I&amp;rsquo;m sure if I was more on the fringes of cell service I would have needed an actual pole and to actually aim it.&lt;/p&gt;
&lt;h2 id=&#34;routeros&#34;&gt;RouterOS&lt;/h2&gt;
&lt;p&gt;I started with the default config that the SXT had. It really wanted to be a firewall router, but I gave it a static IP on my internal LAN network instead and turned off DHCP and firewalling. I then created a new VLAN interface in RouterOS for the LTE modem, and bridged the LTE modem to the VLAN using this command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface lte apn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add apn&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;fast.t-mobile.com ip-type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ipv4-ipv6 passthrough-interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;LTEWAN
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For some reason RouterOS defaulted to ipv4 only, no idea why. adding &lt;code&gt;ip-type&lt;/code&gt; fixed that.&lt;/p&gt;
&lt;p&gt;I then plugged it into my Mikrotik CRS328-24P-4S+ switch, it got 802.3af PoE, used the untagged network with its LAN IP for management, and has a tagged network for the internet connection back to OPNsense.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the full config I ended up with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;admin@MikroTik&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &amp;gt; export 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# apr/26/2022 20:06:56 by RouterOS 6.45.9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# software id = XXXX-XXXX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# model = RBSXTR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# serial number = XXXXXXXXX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface bridge
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add admin-mac&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;xx:xx:xx:xx:xx:xx auto-mac&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface vlan
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ether1 name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;LTEWAN vlan-id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;WAN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;LAN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface lte apn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add apn&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;fast.t-mobile.com ip-type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ipv4-ipv6 passthrough-interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;LTEWAN passthrough-mac&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;auto
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface lte
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; find &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; apn-profiles&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;fast.t-mobile.com mac-address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;xx:xx:xx:xx:xx:xx name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;lte1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface wireless security-profiles
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; find default&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; supplicant-identity&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;MikroTik
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip hotspot profile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; find default&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; html-directory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;flash/hotspot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip pool
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;default-dhcp ranges&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.88.10-192.168.88.254
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip dhcp-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address-pool&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;default-dhcp interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface bridge port
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add bridge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ether1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add bridge&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ether2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/interface list member
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;bridge list&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;LAN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;lte1 list&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;WAN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip address
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;172.27.0.9/20 comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf interface&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ether1 network&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;172.27.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip dhcp-server network
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.88.0/24 comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf gateway&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.88.1 netmask&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip dns
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set allow-remote-requests&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip dns static
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;172.27.0.9 comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;defconf name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;router.lan
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip firewall filter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;accept chain&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;forward comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;defconf: accept in ipsec policy&amp;#34;&lt;/span&gt; ipsec-policy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;in,ipsec
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;accept chain&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;forward comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;defconf: accept out ipsec policy&amp;#34;&lt;/span&gt; ipsec-policy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;out,ipsec
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;fasttrack-connection chain&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;forward comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;defconf: fasttrack&amp;#34;&lt;/span&gt; connection-state&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;established,related
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;accept chain&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;forward comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;defconf: accept established,related, untracked&amp;#34;&lt;/span&gt; connection-state&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;established,related,untracked
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;drop chain&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;forward comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;defconf: drop invalid&amp;#34;&lt;/span&gt; connection-state&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;invalid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;drop chain&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;forward comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;defconf: drop all from WAN not DSTNATed&amp;#34;&lt;/span&gt; connection-nat-state&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;!dstnat connection-state&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;new in-interface-list&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;WAN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ip firewall nat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;masquerade chain&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;srcnat comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;defconf: masquerade&amp;#34;&lt;/span&gt; disabled&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;yes ipsec-policy&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;out,none out-interface-list&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;WAN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/system clock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set time-zone-name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;America/Chicago
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;opnsense&#34;&gt;OPNsense&lt;/h2&gt;
&lt;p&gt;I was able to get DHCP (IPv4) and SLAAC (IPv6) working. T-Mobile doesn&amp;rsquo;t do IPv6 PD via DHCPv6, so SLAAC is what I get. It seems like the SLAAC prefix is stable as long as the modem is powered on, and it gets a new one when the modem reboots. This correlates with phone users reporting a stable prefix through tower handover and phone sleep unless they reboot the phone. Not totally unexpected. Unlike DHCPv6 there isn&amp;rsquo;t a native IPv6 way to request a static SLAAC prefix since the DUID is only used in DHCPv6 (although they could tie prefix to IMEI for a mobile-specific solution). The lack of a delegated prefix means we can either have exactly one IPv6 subnet in the LAN side (passing through the prefix we got from upstream) OR we can use exclusively DHCPv6 and smaller than /64 subnets internally. Android&amp;rsquo;s core devs are stupidly opposed to using DHCPv6 in Android, but every other OS supports it.&lt;/p&gt;
&lt;p&gt;I tested with a temporary server instead of OPNsense and was able to successfully receive inbound connections to my IPv6 address (with the server connected directly to the LTE modem), although I&amp;rsquo;ve heard T-mobile blocks ICMP (ping) packets. HTTP inbound worked just fine. There&amp;rsquo;s sometimes a huge latency in initiating the connection (up to 1 sec for the TCP socket to connect). Presumably it has to wait for the mobile side to wake / check for notifications from the tower, and LTE is designed to conserve battery power so it has a relatively lengthy wake up interval compared to WiFi. Once the session is up it seems like latency isn&amp;rsquo;t bad at all.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Setting up a Netboot (PXE) Server for Alpine Linux</title>
      <link>https://www.apalrd.net/posts/2022/alpine_pxe/</link>
      <pubDate>Wed, 27 Apr 2022 08:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/alpine_pxe/</guid>
      <description>I&amp;rsquo;ve played with network booting before (and I even tried to netboot Windows, what a nightmare that was), but now I want to get serious about it. I want to netboot my VDI Clients. I&amp;rsquo;ve been working on a thin client series, and the next step is to get rid of the installation entirely. I could use something like Linux Terminal Server Project, but that&amp;rsquo;s a bit overkill for this, and I wanted to learn Alpine anyway, so I&amp;rsquo;ve chosen to use Alpine Linux for the client operating system.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve played with network booting before (&lt;a href=&#34;https://www.apalrd.net/posts/2021/pxe_windows/&#34;&gt;and I even tried to netboot Windows&lt;/a&gt;, what a nightmare that was), but now I want to get serious about it. I want to netboot my VDI Clients. I&amp;rsquo;ve been working on a thin client series, and the next step is to get rid of the installation entirely. I could use something like Linux Terminal Server Project, but that&amp;rsquo;s a bit overkill for this, and I wanted to learn Alpine anyway, so I&amp;rsquo;ve chosen to use Alpine Linux for the client operating system. It&amp;rsquo;s extremely basic. However, even using Alpine is still a huge setup, so this article will focus on setting up a netboot server (also using Alpine Linux), to prepare for the next video where I create the Proxmox VDI Client using this netboot system.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a table of contents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/#the-basics&#34;&gt;The Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/#netboot-server-setup&#34;&gt;Netboot Server Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/#setup-http-server&#34;&gt;Setup HTTP Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/#download-alpine-netboot&#34;&gt;Download Alpine Netboot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/#setup-tftp-server&#34;&gt;Setup TFTP Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/#download--configure-ipxe&#34;&gt;Download &amp;amp; Configure iPXE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/#configure-netboot-in-opnsense&#34;&gt;Configure Netboot in OPNsense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/#testing&#34;&gt;Testing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;Click on the thumbnail to watch the video for this!
&lt;a href=&#34;https://youtu.be/xmVGIdScCQA&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-basics&#34;&gt;The Basics&lt;/h2&gt;
&lt;p&gt;The boot process looks something like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;BIOS/UEFI on victim machine decides it should network boot, either because that&amp;rsquo;s the highest priority boot order or it can&amp;rsquo;t find any other options.&lt;/li&gt;
&lt;li&gt;BIOS/UEFI loads the PXE ROM from the network card and executes it.&lt;/li&gt;
&lt;li&gt;PXE code does a DHCP DISCOVER, finds the DHCP server, and receives a &lt;code&gt;next-server&lt;/code&gt;. It may also receive one or more boot filenames for UEFI/BIOS.&lt;/li&gt;
&lt;li&gt;PXE code downloads the boot filename from the &lt;code&gt;next-server&lt;/code&gt; address via TFTP and executes it. If &lt;code&gt;filename&lt;/code&gt; is not provided, it first does a DHCP request to the address of &lt;code&gt;next-server&lt;/code&gt; (instead of broadcast like normal) to get the filename. This method is called &amp;lsquo;Proxy DHCP&amp;rsquo;. We will be using that method today.&lt;/li&gt;
&lt;li&gt;We&amp;rsquo;ve compiled a special version of iPXE with an embedded script, and that is the boot code being executed at this point. iPXE is a &amp;lsquo;better&amp;rsquo; PXE ROM. Here we have the option of hardcoding the boot commands into an embedded script. The script also has the option of requesting more commands over HTTP, so you can compile a single version of iPXE and use the HTTP server along with CGI/PHP/&amp;hellip; to decide what boot commands a specific client needs, since the HTTP request can include things like the MAC address formatted in the URL. We will not be doing this today, but it&amp;rsquo;s a future enhancement.&lt;/li&gt;
&lt;li&gt;The script includes commands to download and load the kernel and initrd over HTTP instead of TFTP, so using iPXE saves us a ton of time over using TFTP and gives us more control over what arguments to pass to the kernel.&lt;/li&gt;
&lt;li&gt;For Alpine we can add a modloop argument which specifies the HTTP address to download the modloop file. If you provide it, that file will contain all of the additional kernel modules that may be needed after the early boot process.&lt;/li&gt;
&lt;li&gt;For Alpine, we can pass the URL of an Alpine mirror as a kernel command line argument, so the system has a working package manager by default. Normal systems would use the CD/USB IMG as the mirror until you configure networking, so this can get a fully functional working system without an image at all.&lt;/li&gt;
&lt;li&gt;For Alpine, we can pass the URL to an APKOVL file which will be applied on top of the initramfs root image. This usually includes &lt;code&gt;/etc&lt;/code&gt; but can include more. It also includes the &lt;code&gt;/etc/apk/world&lt;/code&gt; file, which is the list of packages that should be installed. Essentially, given an apkovl file, Alpine will rebuild the installation that was saved previously, using a combination of downloading and installing packages from the mirror configured in the &lt;code&gt;/etc/apk/repositories&lt;/code&gt; file and the configuration and user data in the APKOVL file.&lt;/li&gt;
&lt;li&gt;Due to the modloop and apkovl, we have a completely running system using only 4 files on the server (vmlinuz, initramfs, modloop, apkovl) which will then configure itself exactly as we want. We can export the configuration of a running system using &lt;code&gt;lbu&lt;/code&gt; to generate the apkovl file, and the other 3 files are provided by Alpine for netbooting. If we include &lt;code&gt;/home&lt;/code&gt; in our apkovl, we can include all of the configuration we need for the thin client without having to mount anything off NFS.&lt;/li&gt;
&lt;li&gt;(Optional) If we are doing this in a big organization, we shouldn&amp;rsquo;t hammer the Alpine package servers every time a thin client boots, so you should setup your own local mirror. That&amp;rsquo;s beyond the scope of this tutorial. Alpine provides a public rsync server for mirrors to synchronize from, and you can configure your mirror to only mirror specific Alpine versions and architectures to save space and pass requests to the primary mirrors otherwise.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;netboot-server-setup&#34;&gt;Netboot Server Setup&lt;/h2&gt;
&lt;p&gt;For the server, we can choose whatever OS we want. But, I&amp;rsquo;m into Alpine now, so I&amp;rsquo;m going to use Alpine for the server as well. I&amp;rsquo;m installing it on Proxmox VE as a VM. I used the full extended ISO, but I don&amp;rsquo;t think that&amp;rsquo;s necessary. I ran &lt;code&gt;setup-alpine&lt;/code&gt; to install it to disk using sys mode, which is the full system installed on disk and not running from RAM.&lt;/p&gt;
&lt;p&gt;Alpine is pretty darn minimal. We need a text editor, it doesn&amp;rsquo;t come with nano.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Nano is a text editor that&amp;#39;s useful&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apk add nano
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that we have nano we can add the community repository (&lt;code&gt;nano /etc/apk/repositories&lt;/code&gt;) and uncomment the line ending in &lt;code&gt;community&lt;/code&gt;, but not the ones with &lt;code&gt;edge&lt;/code&gt; in them.&lt;/p&gt;
&lt;p&gt;And finally, enable root SSH login for now so we can setup the system (disable this once you are done):
&lt;code&gt;nano /etc/ssh/sshd_config&lt;/code&gt;, find the line starting with &lt;code&gt;#PermitRootLogin&lt;/code&gt; and change the line to &lt;code&gt;PermitRootLogin yes&lt;/code&gt;. Restart the server using &lt;code&gt;rc-service sshd restart&lt;/code&gt;. From now on you can use ssh for the rest of the commands.&lt;/p&gt;
&lt;h2 id=&#34;setup-http-server&#34;&gt;Setup HTTP Server&lt;/h2&gt;
&lt;p&gt;Going to use nginx here, since we need PHP support in the future. You could also use lighttpd.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apk add nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add www user for nginx to run as&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adduser -D -g &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;www&amp;#39;&lt;/span&gt; www
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir /srv/www
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R www:www /var/lib/nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R www:www /srv/www
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup old nginx config since we will rewrite it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we need to create an nginx config as simple as possible, since the default one will 404 on everything. So &lt;code&gt;nano /etc/nginx/nginx.conf&lt;/code&gt; and paste this in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user www;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;worker_processes auto;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;error_log /var/log/nginx/error.log warn;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pid /var/run/nginx/nginx.pid;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;events &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    worker_connections 1024;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;http &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    include /etc/nginx/mime.types;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    default_type application/octet-stream;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sendfile on;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    access_log /var/log/nginx/access.log;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    keepalive_timeout 3000;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    server &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        listen 80;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        root /srv/www;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        index index.html index.htm;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        server_name localhost;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        client_max_body_size 32m;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        error_page &lt;span style=&#34;color:#ae81ff&#34;&gt;500&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;502&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;503&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;504&lt;/span&gt; /50x.html;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        location &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; /50x.html &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            root /var/lib/nginx/html;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally configure it to start on boot:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Start on boot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rc-update add nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Start now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rc-service nginx start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;download-alpine-netboot&#34;&gt;Download Alpine Netboot&lt;/h2&gt;
&lt;p&gt;Alpine provides netboot images in a .tar.gz format. We need to put these in our &lt;code&gt;/srv/www&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Go to the &lt;a href=&#34;https://alpinelinux.org/downloads/&#34;&gt;Alpine download page&lt;/a&gt; and copy the link to the netboot x86_64. As of the writing of this, the file is called &lt;code&gt;alpine-netboot-3.15.4-x86_64.tar.gz&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now download the file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Move to web directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /srv/www
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Download alpine link&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &amp;lt;paste the link here&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Untar it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar -xzf alpine*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Delete the tar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm alpine-netboot*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Files are now in boot folder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are two versions of the files, virt and lts. Virt is stripped down to only include the drivers needed to run on common hypervisors, while lts should include more driver support.&lt;/p&gt;
&lt;h2 id=&#34;setup-tftp-server&#34;&gt;Setup TFTP Server&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;re gonna need a TFTP server for the ipxe image, since PXE normally requires TFTP to be used. Let&amp;rsquo;s get that setup now.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apk add tftp-hpa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add it to run as a service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rc-update add in.tftpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Start service now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rc-service in.tftpd start
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Default directory is /var/tftpboot/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since tftp-hpa creates a chroot for itself, it can&amp;rsquo;t follow symlinks up the directory tree, so we will need to copy our files into &lt;code&gt;/var/tftpboot/&lt;/code&gt; instead of symlinking them. We will need to be aware of this when we install iPXE later.&lt;/p&gt;
&lt;h2 id=&#34;download--configure-ipxe&#34;&gt;Download &amp;amp; Configure iPXE&lt;/h2&gt;
&lt;p&gt;Now that we have a functional server, we need to write our embedded ipxe script to download vmlinuz and friends over HTTP, then compile this into an ipxe binary and put it on our tftp server.&lt;/p&gt;
&lt;p&gt;First we need to install git then clone the ipxe repo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install git, make, gcc, perl, all the stuff ipxe will need&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apk add git make binutils mtools perl xz-dev libc-dev gcc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Going to put ipxe in the srv folder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /srv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Clone ipxe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/ipxe/ipxe.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#cd into it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ipxe/src
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can create an embedded script (&lt;code&gt;nano netboot.ipxe&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!ipxe
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Init networking&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dhcp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Networking info we got from the DHCP server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo next-server is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;next-server&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo filaneme is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;filename&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo MAC address is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;net0/mac&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo IP address is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;ip&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Set flavor to lts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set flavor lts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo flavor is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;flavor&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Set command line &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set cmdline modules&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;loop,squashfs quiet
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo cmdline is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;cmdline&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Server address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set server http://&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;next-server&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo server is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;server&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Kernel file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set vmlinuz &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;server&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/boot/vmlinuz-&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;flavor&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo vmlinuz is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;vmlinuz&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set initramfs &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;server&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/boot/initramfs-&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;flavor&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo initramfs is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;initramfs&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Modloop file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set modloop &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;server&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/boot/modloop-&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;flavor&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo modloop is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;modloop&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Repository for apk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Update this if you&amp;#39;d like a newer version of Alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Alternatively, set branch to edge for the absolutel latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set mirror http://dl-cdn.alpinelinux.org/alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set branch v3.15
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set repo &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;mirror&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;branch&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/main
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo repo is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;repo&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#apkovl file - set this if you want to apply&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#an apkovl file to configure the Alpne instance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set apkovl &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;server&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/thinclient.apkovl.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo apkovl is &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;apkovl&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Uncomment this if you want to see the information before continuing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#prompt Press any key to continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Kernel, initrd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#For EFI, we need to tell the kernel the initrd filename. For BIOS it doens&amp;#39;t hurt to leave the initrd argument.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you want to use Alpine bare, use this line:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#kernel ${vmlinuz} ${cmdline} alpine_repo=${repo} modloop=${modloop} initrd=initramfs-${flavor}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you want to use Alpine with an apkovl, use this line:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kernel &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;vmlinuz&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;cmdline&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt; modloop&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;modloop&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt; apkovl&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;apkovl&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt; initrd&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;initramfs-&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;flavor&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;initrd &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;initramfs&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Boot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;boot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Pause if errors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prompt Some error occurred, press any key to &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we build ipxe (make a script &lt;code&gt;nano build.sh&lt;/code&gt; then &lt;code&gt;chmod +x build.sh&lt;/code&gt; to automate this):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Build BIOS version (x86 but should boot into x64 environment)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make bin-i386-pcbios/undionly.kpxe EMBED&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;netboot.ipxe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Build EFI version (x86)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make bin-x86_64-efi/ipxe.efi EMBED&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;netboot.ipxe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy files to tftp root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp bin-i386-pcbios/undionly.kpxe /var/tftpboot/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp bin-x86_64-efi/ipxe.efi /var/tftpboot/ipxe64.efi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The APKOVL we are using is for x64, so not building ipxe32.efi right now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Also not building arm variants for this project&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After this, we should have the binaries in our tftp directory and can enable netbooting in our DHCP server&lt;/p&gt;
&lt;h3 id=&#34;gcc-12-resolution&#34;&gt;GCC 12 Resolution&lt;/h3&gt;
&lt;p&gt;Error-checking in GCC 12 results in many compile errors for iPXE, as referenced by &lt;a href=&#34;https://github.com/ipxe/ipxe/issues/620&#34;&gt;this issue&lt;/a&gt;. Until the issue is resolved on their end, use this script instead to treat errors as warnings:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Build BIOS version (x86 but should boot into x64 environment)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NO_WERROR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; make bin-i386-pcbios/undionly.kpxe EMBED&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;netboot.ipxe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Build EFI version (x86)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NO_WERROR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; make bin-x86_64-efi/ipxe.efi EMBED&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;netboot.ipxe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy files to tftp root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp bin-i386-pcbios/undionly.kpxe /var/tftpboot/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp bin-x86_64-efi/ipxe.efi /var/tftpboot/ipxe64.efi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The APKOVL we are using is for x64, so not building ipxe32.efi right now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Also not building arm variants for this project&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configure-netboot-in-opnsense&#34;&gt;Configure Netboot in OPNsense&lt;/h2&gt;
&lt;p&gt;I use OPNsense as my firewall, so here&amp;rsquo;s how I added the next-server and filenames to OPNsense&amp;rsquo;s DHCP server.&lt;/p&gt;
&lt;h2 id=&#34;testing&#34;&gt;Testing&lt;/h2&gt;
&lt;p&gt;If all goes well, you should be able to boot your client, and as long as PXE is enabled higher than any other bootable devices in the boot order, it should launch into our thin client. You can even configure a VM in Proxmox with no disk and no DVD drive and it should netboot.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>2 gamers, 1 cpu, NO Virtualization!</title>
      <link>https://www.apalrd.net/posts/2022/multiseat_intro/</link>
      <pubDate>Thu, 21 Apr 2022 12:36:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/multiseat_intro/</guid>
      <description>I&amp;rsquo;ve been using Linux for a long time. The first distribution I ever installed was Ubuntu 6.06 &amp;lsquo;Dapper Drake&amp;rsquo;, on which I ran a phpBB server for my school friends. Security was poor. But shortly after, as I learned about Linux desktops (and first daily-drove a Linux laptop around 2012), I learned about &amp;lsquo;Multiseat&amp;rsquo;. The Wikipedia article has a cool picture of a very 90s looking desktop tower with 4x CRT monitors, and that image was published to Wikipedia in 2005, and I saw it in middle/high school years.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve been using Linux for a long time. The first distribution I ever installed was Ubuntu 6.06 &amp;lsquo;Dapper Drake&amp;rsquo;, on which I ran a phpBB server for my school friends. Security was poor. But shortly after, as I learned about Linux desktops (and first daily-drove a Linux laptop around 2012), I learned about &lt;a href=&#34;https://en.wikipedia.org/wiki/Multiseat_configuration&#34;&gt;&amp;lsquo;Multiseat&amp;rsquo;&lt;/a&gt;. The Wikipedia article has a cool picture of a very 90s looking desktop tower with 4x CRT monitors, and that image was published to Wikipedia in 2005, and I saw it in middle/high school years. This multi-seat configuration stuck with me, and for years I&amp;rsquo;ve wanted to set it up myself. Finally, in 2022, I&amp;rsquo;m ready to set this up, and I&amp;rsquo;m going all in - ONE computer, TWO users, and support for both OpenGL and Vulkan gaming!&lt;/p&gt;
&lt;p&gt;This project is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/multiuser/&#34;&gt;Multiuser, Multidesktop, and Multiseat Megaproject&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;what-is-multiseat&#34;&gt;What Is Multiseat?&lt;/h2&gt;
&lt;p&gt;Multiseat is a system that allows Linux systems to operate with multiple users at the same time. Linux has been inherently a multi-user system essentially for its entire life, but normally there is one graphical session plus more than one terminal session (i.e. by SSH). It&amp;rsquo;s also possible to create multiple graphical sessions using a remote access protocol like I did in my &lt;a href=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/&#34;&gt;XRDP Video&lt;/a&gt;. But, with multiseat, we take this to the extreme - we hook up multiple monitiors, keyboards, mide, peripherals to one system and partition them up so each user can use their own hardware, sharing the computational resources of one computer amongst all of the users who are physically seated within cable length of the computer.&lt;/p&gt;
&lt;p&gt;Currently, to get full GPU acceleration (OpenGL + Vulkan), we need to dedicate one GPU to each user. This is due to security concerns in the kernel devs about the potential for poor information security between multiple users, as graphical applications are given direct access to GPU VRAM to improve performance. If you don&amp;rsquo;t care about hardware acceleration, stay tuned for a future video where I omit the gaming and 3D requirement and build a many-user productivity box for poor cube farm workers to use basic desktop things.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;p&gt;This is a super long blog, so feel free to jump down to any specific segments&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/multiseat_intro/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/multiseat_intro/#hardware-and-bios-configuration&#34;&gt;Hardware and BIOS Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/multiseat_intro/#software-setup&#34;&gt;Software Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/multiseat_intro/#configure-seats&#34;&gt;Configure Seats&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;Click the thumbnail for to view the video on Youtube
&lt;a href=&#34;https://youtu.be/OSodGduWeL0&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/multiseat_intro/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;hardware-and-bios-configuration&#34;&gt;Hardware and BIOS Configuration&lt;/h2&gt;
&lt;p&gt;The hardware I&amp;rsquo;m using for this test is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AMD Ryzen 5 3400G APU - Zen+ architecture, Raven Ridge + Vega graphics (shows up as &amp;lsquo;Raven2&amp;rsquo; in &lt;code&gt;radeontop&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;AMD Radeon RX580 GPU - Polaris architecture (shows up as &amp;lsquo;Polaris10&amp;rsquo; in &lt;code&gt;radeontop&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;ASRock B450M Pro4 AM4 motherboard (it was low cost when I bought it)&lt;/li&gt;
&lt;li&gt;32G DDR4 (2x16G sticks)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I specifically chose this test hardware for this project since both the APU and GPU use the same driver - the open source &lt;code&gt;amdgpu&lt;/code&gt; driver. In theory it should be possible to mix AMD and Intel graphics (since both use Mesa), but as far as I can tell it is NOT possible to mix Nvidia and other GPUs using the proprietary drivers.&lt;/p&gt;
&lt;p&gt;I played a bit in the BIOS to make sure that both GPUs show up correctly. I found that I need to set the primary GPU in the BIOS to the internal GPU, otherwise it disables the Vega GPU entirely. This could be a quirk of the BIOS on this board. I cannot update past the current BIOS version as later versions dropped support for Summit, Raven, and Pinnacle Ridge CPUs (og Zen and Zen+). Knowing which GPU is &amp;lsquo;primary&amp;rsquo; (which should be the one that GRUB and the BIOS show up on) is going to be &lt;strong&gt;very&lt;/strong&gt; important later.&lt;/p&gt;
&lt;h2 id=&#34;software-setup&#34;&gt;Software Setup&lt;/h2&gt;
&lt;p&gt;I chose to install Ubuntu 22.04 &amp;lsquo;Jammy Jellyfish&amp;rsquo;, which is currently in beta as of the writing and filming of this video but should be released completely by the time this blog and video drop. I know that Linux distros are extremely controversial topic, but Ubuntu has excellent hardware support, 22.04 uses the Linux 5.15 kernel which is more recent than Debian ships, and the environment should be fairly well tested as it&amp;rsquo;s the basis of other very popular desktops such as Pop!OS. I&amp;rsquo;m intentionally using AMD GPUs to avoid fighting with the Nvidia proprietary drivers, and I&amp;rsquo;ve found the open source &lt;code&gt;amdgpu&lt;/code&gt; driver to be quite excellent.&lt;/p&gt;
&lt;p&gt;During the install, I selected ZFS on root (although you can choose whatever you want of coruse), and to install third-party codecs.&lt;/p&gt;
&lt;p&gt;After installing, I did some basic housekeeping (&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y&lt;/code&gt;), and installed OpenSSH server so I can access the system if I royally mess up later. In case you need to hit the display manager over the head later, you can run &lt;code&gt;sudo systemctl restart display-manager&lt;/code&gt; and it should restart &lt;code&gt;gdm3&lt;/code&gt;, logging out everyone and starting back from the login screens.&lt;/p&gt;
&lt;h3 id=&#34;switch-from-wayland-to-x11&#34;&gt;Switch from Wayland to X11&lt;/h3&gt;
&lt;p&gt;I found that, while it&amp;rsquo;s possible to configure multiseat on Wayland, Vulkan did not work properly with multiple GPUs. I chose to revert back to X11 to deal with this. It&amp;rsquo;s a fairly simple configuration change. For Ubuntu 22.04 with GNOME, edit &lt;code&gt;/etc/gdm3/custom.conf&lt;/code&gt; and find the line &lt;code&gt;#WaylandEnable=false&lt;/code&gt; and uncomment it. Once you reboot, it should be using X11 entirely.&lt;/p&gt;
&lt;h3 id=&#34;initial-benchmarking&#34;&gt;Initial Benchmarking&lt;/h3&gt;
&lt;p&gt;Before I split into multiple seats, I&amp;rsquo;m going to run with just the iGPU, followed with just the dGPU, and benchmark the system. I&amp;rsquo;m using Unigine Heaven Benchmark for OpenGL, and Portal 2 for Vulkan. Both are fairly dated titles at this point, but I&amp;rsquo;m honestly not a huge gamer and this game has good Vulkan support on Linux. I just want to make sure performance later is within the same range as it was before I added two seats. I do this by enabling just the iGPU, then just the dGPU, then switching back to both of them. You don&amp;rsquo;t need to do this, it&amp;rsquo;s just nice to confirm that we aren&amp;rsquo;t really losing GPU performance at all.&lt;/p&gt;
&lt;h2 id=&#34;configure-seats&#34;&gt;Configure Seats&lt;/h2&gt;
&lt;p&gt;Here, we do all of the hard work with configuring the seats with loginctl. Systemd supports the concept of multi-seat natively, and the most popular desktop environments should properly listen to the seat tags and assign devices correctly.&lt;/p&gt;
&lt;p&gt;First, we can list which seats currently exist:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo loginctl list-seats
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It should tell you &lt;code&gt;seat0&lt;/code&gt; and nothing else. We are going to name our new seat &lt;code&gt;seat1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious about the hardware currently on your system, use &lt;code&gt;seat-status&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo loginctl seat-status seat0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve found it&amp;rsquo;s handy to save this to a file for later reference:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo loginctl seat-status seat0 &amp;gt; seat_hardware.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By default, all hardware is attached to &lt;code&gt;seat0&lt;/code&gt;. By using loginctl, we can create rules that force specific hardware to be assigned to a different seat. Hardware can be dynamically reallocated using loginctl, and it will unassign hardware from one seat and move it to the other. A seat must have a &amp;ldquo;Master of Seat&amp;rdquo; (shown in &lt;code&gt;seat-status&lt;/code&gt; as &lt;code&gt;[MASTER]&lt;/code&gt;), which is a graphics card. Once a master of seat exists, a login prompt will be spawned for it, and once you add a keyboard/mouse, you can login using it.&lt;/p&gt;
&lt;p&gt;In order to attach hardware to a seat, we need the entire sys path (as shown in &lt;code&gt;seat-status&lt;/code&gt;) and to call attach:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo loginctl attach seat1 /sys/&amp;lt;path to device&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once we&amp;rsquo;ve saved the current seat status as a text file, we can comb through it and decide what we want to attach to the second seat. Then, we can copy paths out of the file so we don&amp;rsquo;t have to type them.&lt;/p&gt;
&lt;h3 id=&#34;graphics-sound&#34;&gt;Graphics, Sound&lt;/h3&gt;
&lt;p&gt;In my case, I have 2 graphics and 3 sound devices. Each GPU has sound, plus the on-board chipset audio. I&amp;rsquo;m using the HDMI audio output for both seats, so each graphics and its associated sound device is passed through. I left the chipset audio assigned to the initial seat, so only that one will have analog microphone. If you want the second seat to have a microphone input, you&amp;rsquo;ll need a USB audio device for it.&lt;/p&gt;
&lt;p&gt;Figure out the PCIe addressees of both of your graphics cards using &lt;code&gt;lspci&lt;/code&gt;. Look for &lt;code&gt;VGA Compatible&lt;/code&gt; devices, and their associated sound devices.&lt;/p&gt;
&lt;p&gt;In my case, the Raven GPU is &lt;code&gt;07:00.0&lt;/code&gt; and the Polaris GPU is &lt;code&gt;01:00.00&lt;/code&gt; (with the sound device at &lt;code&gt;*:00.01&lt;/code&gt; for both)&lt;/p&gt;
&lt;h3 id=&#34;usb-ports&#34;&gt;USB Ports&lt;/h3&gt;
&lt;p&gt;For USB ports, you need to forward them by USB bus, which is a combination of the PCIe root device and the port off the root complex. For most systems the USB root complex is part of the CPU itself or the chipset, possibly with USB hubs on the motherboard to split USB3 root ports into multiple USB2 ports. You will need to go through using &lt;code&gt;lsusb&lt;/code&gt; with a known USB device to see which ports on your motherboard are associated with which USB bus, and move devices around until the devices for multiple seats aren&amp;rsquo;t sharing the same bus. I recommend getting a USB3 hub for each seat to make it simpler to deal with this, since you can find the USB bus of a specific USB3 port and easily pass through all devices downstream.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve done that, go back to your seat hardware file and find the entry for the USB bus you want, then &lt;code&gt;loginctl attach&lt;/code&gt; it to the new seat. Changes should take effect immediately.&lt;/p&gt;
&lt;h3 id=&#34;removing-multiseat&#34;&gt;Removing Multiseat&lt;/h3&gt;
&lt;p&gt;If you want to completely revert, run &lt;code&gt;sudo loginctl flush-devices&lt;/code&gt; to flush the seat config, which should take you back to the seat0 configuration you started with at the beginning.&lt;/p&gt;
&lt;p&gt;The settings should be retained through reboots, so you shouldn&amp;rsquo;t need to call loginctl again after everything is setup unless you want to modify hardware assignments.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Small Proxmox Cluster Tips and Tricks, and QDevices</title>
      <link>https://www.apalrd.net/posts/2022/cluster_qdevice/</link>
      <pubDate>Thu, 14 Apr 2022 09:15:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/cluster_qdevice/</guid>
      <description>So you want to turn your one or two Proxmox nodes into a small Proxmox cluster? What do you need to know about quorum, especially as it pertains to really small clusters of 2 and 3 nodes? In this video, I go over the different ways to stabilize a 2-node cluster for high availability, the storage requirements for high available VMs, installing a QDevice using a Raspberry Pi, and if you even need one.</description>
      <content>&lt;p&gt;So you want to turn your one or two Proxmox nodes into a small Proxmox cluster? What do you need to know about quorum, especially as it pertains to really small clusters of 2 and 3 nodes? In this video, I go over the different ways to stabilize a 2-node cluster for high availability, the storage requirements for high available VMs, installing a QDevice using a Raspberry Pi, and if you even need one. I also talk about how a QDevice might not help you as much as you think in a 3 node cluster.&lt;/p&gt;
&lt;p&gt;This is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/cluster/&#34;&gt;Hyper-Converged Cluster Megaproject&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;Most of the content is in video form. If you&amp;rsquo;d like to reference any commands to install the QDevice, scroll down below.
&lt;a href=&#34;https://youtu.be/TXFYTQKYlno&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/cluster_qdevice/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;installing-a-qdevice-on-a-rasperry-pi&#34;&gt;Installing a QDevice on a Rasperry Pi&lt;/h2&gt;
&lt;p&gt;Here are the instructions for installing a QDevice, in case you would like to copy commands.&lt;/p&gt;
&lt;p&gt;First, for Proxmox to be able to configure the Pi, it will log in over SSH with the root password. So, we need to set a root password, and temporarily enable SSH login as root with a password.&lt;/p&gt;
&lt;p&gt;To set the password, use &lt;code&gt;sudo passwd root&lt;/code&gt;. Then, edit &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; until you find the key &lt;code&gt;#PermitRootLogin&lt;/code&gt; and change that line to &lt;code&gt;PermitRootLogin yes&lt;/code&gt;. Restart the ssh server using &lt;code&gt;sudo systemctl restart sshd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, we need to install the QDevice daemon. Make sure the Pi is up to date with &lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y&lt;/code&gt;, then install the daemon itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install corosync-qnetd corosync-qdevice
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point, the Pi is ready to go, now move over to Proxmox.&lt;/p&gt;
&lt;p&gt;We now need to install QDevice support onto all nodes of the cluster. From the Shell tab for each node, first run package updates (&lt;code&gt;apt update&lt;/code&gt;, you may need to setup the pve-no-subscription repo if you haven&amp;rsquo;t already) then install qdevice with &lt;code&gt;apt install corosync-qdevice&lt;/code&gt;. Repeat for each node in your cluster.&lt;/p&gt;
&lt;p&gt;Finally, we can add the QDevice to the cluster. From any node in the cluster, run the pvecm command to add your node. It needs the IP address of the node here. &lt;code&gt;-f&lt;/code&gt; forces it to overwrite any existing configuration.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pvecm qdevice setup &amp;lt;ip&amp;gt; -f
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It will then ask you to accept the SSH fingerprint and for the root password of the raspberry pi. Then, it should do its magic, and the QDevice will be setup.&lt;/p&gt;
&lt;p&gt;The QDevice won&amp;rsquo;t show up anywhere in the GUI. To check that it&amp;rsquo;s working, use &lt;code&gt;pvecm status&lt;/code&gt; and it will display the QDevice under &lt;code&gt;Membership Information&lt;/code&gt;, and under &lt;code&gt;Votequorum Information&lt;/code&gt; it will show the total number of votes and the number required for quorum. The &lt;code&gt;QDevice&lt;/code&gt; flag should also be listed under &lt;code&gt;Flags&lt;/code&gt;.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Installing Proxmox VE 7 on Debian Bullseye</title>
      <link>https://www.apalrd.net/posts/2022/pve_bullseye/</link>
      <pubDate>Mon, 11 Apr 2022 00:31:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/pve_bullseye/</guid>
      <description>I recently tried to install Proxmox on my Dell Wyse 3040 thin client so it can act as a cluster member, since it&amp;rsquo;s arguably easier to setup a full Proxmox install on x64 based devices than it is to setup a QDevice. Proxmox has a great installer, you have the full GUI to manage the node (not that you need to do much with it as a QDevice), and you have the option of setting it up for other Proxmox services and containers even if it&amp;rsquo;s really not very capable.</description>
      <content>&lt;p&gt;I recently tried to install Proxmox on my &lt;a href=&#34;https://www.apalrd.net/posts/2022/wyse_3040/&#34;&gt;Dell Wyse 3040&lt;/a&gt; thin client so it can act as a cluster member, since it&amp;rsquo;s arguably easier to setup a full Proxmox install on x64 based devices than it is to setup a QDevice. Proxmox has a great installer, you have the full GUI to manage the node (not that you need to do much with it as a QDevice), and you have the option of setting it up for other Proxmox services and containers even if it&amp;rsquo;s really not very capable. So, I&amp;rsquo;m committed to installing Proxmox on my 3040. But then the problems came. The Proxmox installer was unhappy with the eMMC storage, and wasn&amp;rsquo;t able to create a partition table on it. Well, I guess I&amp;rsquo;m diving down the more difficult path of installing Debian, and then installing Proxmox on top of it.&lt;/p&gt;
&lt;p&gt;In addition to my use case, it&amp;rsquo;s not uncommon to install Proxmox on top of Debian if you want a specific root filesystem layout, since Proxmox will not install without LVM (or ZFS). In my case, I&amp;rsquo;m going to install ext4 on root with no LVM, since the disk is so small. &lt;a href=&#34;https://pve.proxmox.com/wiki/Install_Proxmox_VE_on_Debian_Buster&#34;&gt;Proxmox has a guide on instlaling Proxmox 6 on top of Debian Buster&lt;/a&gt;, but there are a few minor changes to be aware of with the more recent version. Not a big deal though, the guide is still mostly accurate and you should be able to follow it.&lt;/p&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;Video form of this, if you prefer to follow along there:
&lt;a href=&#34;https://youtu.be/dYzMbm0p7FM&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/pve_bullseye/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;install-debian&#34;&gt;Install Debian&lt;/h2&gt;
&lt;p&gt;First we need to install Debian. I started with the Debian 11 (Bullseye) netinst image, ran through it, deseleted the desktop, and selected SSH server. From there, it&amp;rsquo;s pretty much a standard Debian install. Of course, if you&amp;rsquo;re going through the trouble of installing Proxmox on Debian instead of &amp;rsquo;natively&amp;rsquo;, you probably want to use a custom partition layout on the boot partition, and here is where you&amp;rsquo;d configure that.&lt;/p&gt;
&lt;h2 id=&#34;networking&#34;&gt;Networking&lt;/h2&gt;
&lt;p&gt;Before installing Proxmox we need to make sure we have a static IP address, and the hostname resolves back to our public static IP address by setting it in the hosts file.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s set that static address by editing &lt;code&gt;/etc/network/interfaces&lt;/code&gt;:
Find the line for your adapter (mine is &lt;code&gt;enp1s0&lt;/code&gt;) and modify it from dhcp to static and add the static IP. Here&amp;rsquo;s what mine looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iface enp1s0 inet static
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;address 172.27.1.154
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;netmask 255.255.240.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gateway 172.27.0.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After that, we need to add this static address to the hosts file by editing &lt;code&gt;/etc/hosts&lt;/code&gt;:
By default, Debian will map &lt;code&gt;127.0.1.1&lt;/code&gt; to your hostname and &lt;code&gt;127.0.0.1&lt;/code&gt; to localhost. We need to change the second entry to point to our network-accessible IP instead. This is what mine looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;127.0.0.1   localhost.localdomain localhost
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;172.27.1.154 pve3040.palnet.net pve3040
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# The following lines are desirable for IPv6- capable hosts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;::1     localhost   ip6-localhost   ip6-loopback
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ff02::1 ip6-allnodes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ff02::2 ip6-allrouters
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You should only need to change the first two lines here.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;re done, do &lt;code&gt;ifdown enp1s0&lt;/code&gt; followed by &lt;code&gt;ifup enp1s0&lt;/code&gt; (obviously put in your own interface name) so the new IP address takes effect. Be careful if you&amp;rsquo;re doing this over SSH! You can use &lt;code&gt;ip a&lt;/code&gt; to make sure the new IP is being used.&lt;/p&gt;
&lt;h2 id=&#34;add-proxmox-repository&#34;&gt;Add Proxmox Repository&lt;/h2&gt;
&lt;p&gt;Create a new file (&lt;code&gt;nano /etc/apt/sources.list.d/pve-install-repo.list&lt;/code&gt;) and paste in the following contents for PVE 7 on Bullseye:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deb &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;arch&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;amd64&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; http://download.proxmox.com/debian/pve bullseye pve-no-subscription
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now download the Proxmox GPG key that the repository is signed with. The file naming convention has changed, so you can&amp;rsquo;t just go from &lt;code&gt;proxmox-ve-release-6.x.gpg&lt;/code&gt; to &lt;code&gt;proxmox-ve-release-7.x.gpg&lt;/code&gt; like the Proxmox guide would let you believe. I believe this is because the same key now signs the PBS releases as well as PVE.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget http://download.proxmox.com/debian/proxmox-release-bullseye.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bullseye.gpg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;apt-update-upgrade-install-proxmox&#34;&gt;APT Update, Upgrade, Install Proxmox&lt;/h2&gt;
&lt;p&gt;Now do the usual &lt;code&gt;apt update&lt;/code&gt; and &lt;code&gt;apt full-upgrade&lt;/code&gt; to prepare. This should also download package lists from PVE&amp;rsquo;s repo.&lt;/p&gt;
&lt;p&gt;Now we can finally install Proxmox:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install proxmox-ve postfix open-iscsi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Postfix will ask you some questions, choose &lt;code&gt;Local Only&lt;/code&gt; unless you know you have a better answer.&lt;/p&gt;
&lt;p&gt;Proxmox also suggests we remove &lt;code&gt;os-prober&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt remove os-prober
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now reboot, and DONE!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;reboot now
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>PVE-VDIClient - A Python Graphical VDI Client for Proxmox</title>
      <link>https://www.apalrd.net/posts/2022/raspi_spice_vdi/</link>
      <pubDate>Thu, 07 Apr 2022 08:27:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/raspi_spice_vdi/</guid>
      <description>For my last trick, I setup a multi-user thin client where each user account was connected to a specific virtual machine. This is great, but if you have a lot of thin clients you might not want to create a ton of VMs and might instead want each user in the system to have one or more VMs. Well, Josh Patten has written a Python-based GUI to select thin clients which you have access to, and today we are going to turn that into an appliance on both a Raspberry Pi and an actual x86 based Thin Client (running Debian).</description>
      <content>&lt;p&gt;For my &lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/&#34;&gt;last trick&lt;/a&gt;, I setup a multi-user thin client where each user account was connected to a specific virtual machine. This is great, but if you have a lot of thin clients you might not want to create a ton of VMs and might instead want each user in the system to have one or more VMs. Well, Josh Patten has written &lt;a href=&#34;https://github.com/joshpatten/PVE-VDIClient&#34;&gt;a Python-based GUI to select thin clients which you have access to&lt;/a&gt;, and today we are going to turn that into an appliance on both a Raspberry Pi and an actual x86 based Thin Client (running Debian).&lt;/p&gt;
&lt;p&gt;This article is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/thin_client/&#34;&gt;Thin Client Series&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This article was written with Raspberry Pi OS (32-bit) Bullseye release 2022-01-28 and Debian Bullseye release 11.2.0.&lt;/p&gt;
&lt;h2 id=&#34;sections&#34;&gt;Sections&lt;/h2&gt;
&lt;p&gt;This page is really long, so here are pointers to individual sections&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_vdi/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_vdi/#setup-for-raspberry-pi&#34;&gt;Setup for Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_vdi/#setup-for-debian&#34;&gt;Setup for Debian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_vdi/#client-setup&#34;&gt;Client Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_vdi/#optional-configuring-vdi-client-on-boot&#34;&gt;(Optional) Configuring VDI Client on Boot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_vdi/#getting-your-desktop-back&#34;&gt;Getting your desktop back&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_vdi/#conclusions&#34;&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;Of course, I have a video to go along with this topic. Click the thumbnail to watch it on Youtube.
&lt;a href=&#34;https://youtu.be/oLatrZBFQrw&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/raspi_spice_vdi/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup-for-raspberry-pi&#34;&gt;Setup for Raspberry Pi&lt;/h2&gt;
&lt;p&gt;I am starting with Raspberry Pi OS Bullseye (32-bit). I struggled with this for a bit before I realized that the Pi OS packages for Qt are just a mess, so we have to install some things through apt and some through pip to get what we want. Follow along below if you&amp;rsquo;d like, or copy and paste the whole thing.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#First up, as always, make sure the system is up to date before we even start:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo apt upgrade -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now, the dependencies we need via apt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Pyside2 doesn&amp;#39;t have pip packages for armv7, but apt does&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Pip won&amp;#39;t find it though&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install python3-pip python3-pyside2* virt-viewer git -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#And finally, the dependencies via pip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#This will install PySimpleGUIQt version 0.30.0, the last one wihch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#didn&amp;#39;t require PySide2, since it won&amp;#39;t find a PySide2 package for armv7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#But it&amp;#39;ll also install all of the other deps that PySimpleGUIQt has&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip3 install proxmoxer PySimpleGUIQt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Force Pip to upgrade to the latest verion even though it can&amp;#39;t find PySide2 dep&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#PySide2 was installed via apt, so it will find it at run time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip3 install --upgrade PySimpleGuiQt&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;0.35.0 --no-deps
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now we can clone Josh&amp;#39;s repo and cd into it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/joshpatten/PVE-VDIClient.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ./PVE-VDIClient
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make it executable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod +x vdiclient.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now continue along to Client Setup!&lt;/p&gt;
&lt;h2 id=&#34;setup-for-debian&#34;&gt;Setup for Debian&lt;/h2&gt;
&lt;p&gt;I am starting with Debian Bullseye on an x64 system. I installed Debian with desktop support using the LXDE desktop environment, so it&amp;rsquo;s as similar as possible to the Pi environment. During install it will ask you if you want a desktop, so deselect GNOME and select LXDE. I also selected SSH server here so I don&amp;rsquo;t have to install it myself later.&lt;/p&gt;
&lt;p&gt;Everything installs and runs just fine on Debian, no quirks at all.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#First up, as always, make sure the system is up to date before we even start:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo apt upgrade -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now, the dependencies we need via apt:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install python3-pip virt-viewer git -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#And finally, the dependencies via pip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#On Debian pip will install PySide2 just fine if you&amp;#39;re on x64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip3 install proxmoxer PySimpleGUIQt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Now we can clone Josh&amp;#39;s repo and cd into it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/joshpatten/PVE-VDIClient.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ./PVE-VDIClient
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make it executable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod +x vdiclient.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;client-setup&#34;&gt;Client Setup&lt;/h2&gt;
&lt;p&gt;Now we need a configuration file, which I&amp;rsquo;ll put in /etc/vdiclient to simplify things:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create the directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mkdir -p /etc/vdiclient
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create the config file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo nano /etc/vdiclient/vdiclient.ini
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the contents:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[General]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;apalrd VDI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;icon&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;vdiicon.ico&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;logo&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;vdilogo.png&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;kiosk&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Authentication]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auth_backend&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;pve&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;auth_totp&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tls_verify&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Hosts]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;lt;Proxmox IP or DNS name&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;8006&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s a lot of fun you can have with configuration here, including picking a theme from PySimpleGUIQt&amp;rsquo;s theme set, choosing your own logo, and your own icon. Make sure you either copy the images to the path you call the script from (the user&amp;rsquo;s home directory later down in my example), or put them in /etc/vdiclient and use absolute paths in the ini file. Otherwise, the client won&amp;rsquo;t find the images.&lt;/p&gt;
&lt;p&gt;Optionally if you want to share this between users, you can copy the files to system wide directories, although I did not do that for this appliance setup where there are no local other local users.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy vdiclient.py to the local bin folder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo cp vdiclient.py /usr/local/bin/vdiclient
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#(Optional) Copy images too, unless you&amp;#39;re using your own&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo cp vdiclient.png /etc/vdiclient/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo cp vdiicon.ico /etc/vdiclient/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;optional-configuring-vdi-client-on-boot&#34;&gt;(Optional) Configuring VDI Client on Boot&lt;/h2&gt;
&lt;p&gt;Here we are going to modify our user so they launch into the VDI client on boot.&lt;/p&gt;
&lt;p&gt;Basically, we are doing similar steps to the &lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/&#34;&gt;graphical thin client chooser&lt;/a&gt; except we are logging in to the user by default, so LXDE remains installed and we can get it back if we ever need to.&lt;/p&gt;
&lt;p&gt;Before you do this on the Pi, setup your default audio device using the audio icon in the GUI. This should change the audio preferences for your.config which should make audio work correctly. On Debian it should pick the correct audio device by default.&lt;/p&gt;
&lt;p&gt;First we are going to remove the system autostart file and replace it with a blank one, so LXDE doesn&amp;rsquo;t autostart itself:&lt;/p&gt;
&lt;p&gt;For Debian:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Go to directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc/xdg/lxsession/LXDE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup original&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mv autostart autostart.bak
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create empty autostart file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo touch autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For Pi OS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Go to directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc/xdg/lxsession/LXDE-pi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup original&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mv autostart autostart.bak
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create empty autostart file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo touch autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we are going to create an autostart file in our user&amp;rsquo;s home directory, backing up and replacing any existing one
For Debian:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make sure directory exists if it doesn&amp;#39;t already&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p ~/.config/lxsession/LXDE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Change to it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/.config/lxsession/LXDE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup file if it exists (this may error if it doesn&amp;#39;t exist, that&amp;#39;s fine)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv autostart autostart.bak
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create new file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nano autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For Pi OS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make sure directory exists if it doesn&amp;#39;t already&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p ~/.config/lxsession/LXDE-pi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Change to it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/.config/lxsession/LXDE-pi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup file if it exists (this may error if it doesn&amp;#39;t exist, that&amp;#39;s fine)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv autostart autostart.bak
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create new file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nano autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The contents of that file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@/usr/bin/bash /home/&amp;lt;user&amp;gt;/thinclient
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now we need to actually write that file (&lt;code&gt;nano ~/thinclient&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#cd into the PVE-VDIClient directory so local paths to images work&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/PVE-VDIClient
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run loop for thin client so user can&amp;#39;t close it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    /usr/bin/python3 ~/PVE-VDIClient/vdiclient.py
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point it automatically runs the VDI client when the user logs in, but we need it to log in the user by default.&lt;/p&gt;
&lt;p&gt;For Raspberry Pi OS, run &lt;code&gt;sudo raspi-config&lt;/code&gt; and select boot mode to Desktop Autologin, and that&amp;rsquo;s it. &lt;code&gt;raspi-config&lt;/code&gt; handles the rest for you.&lt;/p&gt;
&lt;p&gt;For Debian, we need to edit &lt;code&gt;/etc/lightdm/lightdm.conf&lt;/code&gt; to enable autologin for our user. Find the line which has &lt;code&gt;#autologin-user=&lt;/code&gt; and uncomment it, adding your own username (i.e. &lt;code&gt;autologin-user=vdiuser&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&#34;getting-your-desktop-back&#34;&gt;Getting your desktop back&lt;/h2&gt;
&lt;p&gt;If you make a terrible mistake and want your desktop back to debug it, just move the autostart files back and reboot:&lt;/p&gt;
&lt;p&gt;For Debian:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/.config/lxsession/LXDE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv autostart autostart.new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv autostart.bak autostart
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc/xdg/lxsession/LXDE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv autostart autostart.new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv autostart.bak autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For Pi OS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/.config/lxsession/LXDE-pi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv autostart autostart.new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv autostart.bak autostart
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc/xdg/lxsession/LXDE-pi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv autostart autostart.new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv autostart.bak autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And of course you can do the inverse (autostart -&amp;gt; .bak and .new -&amp;gt; autostart) once you&amp;rsquo;re done using the desktop&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m happy with the progress this project is making. We&amp;rsquo;re getting closer and closer to the goal of being able to dynamically spin up new VM clones as users request them, like a commercial VDI solution. This new python tool by Josh is a great step in that direction, and hopefully you are inspired to help him out by supporting it. Certainly more episodes on this subject from me are coming in the future!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Buying More Thin Clients for more &#39;fun&#39;?</title>
      <link>https://www.apalrd.net/posts/2022/wyse_3040/</link>
      <pubDate>Mon, 04 Apr 2022 00:32:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/wyse_3040/</guid>
      <description>After really enjoying my trio of Dell Wyse 5060 Thin Clients, I bought another cheap one to see how it compares, and hopefully to give advice to the many commenters. The 5060 was a great value for $35 but it&amp;rsquo;s hard to find at that price normally, while the 3040 is always available for that price, physically much smaller, and also worse on paper. It has a quad-core Intel CPU, 2G of RAM, and was advertised as having an 8G SSD but mine is actually 16G.</description>
      <content>&lt;p&gt;After really enjoying my trio of &lt;a href=&#34;https://www.apalrd.net/posts/2022/wyse_basic/&#34;&gt;Dell Wyse 5060 Thin Clients&lt;/a&gt;, I bought another cheap one to see how it compares, and hopefully to give advice to the many commenters. The 5060 was a great value for $35 but it&amp;rsquo;s hard to find at that price normally, while the 3040 is always available for that price, physically much smaller, and also worse on paper. It has a quad-core Intel CPU, 2G of RAM, and was advertised as having an 8G SSD but mine is actually 16G. It&amp;rsquo;s eMMC instead of SATA, soldered on board, and the RAM is soldered as well (the case is tiny!). I opened it up and replaced the power connector with a short USB cord instead of trying to buy a power cord.&lt;/p&gt;
&lt;p&gt;tl;dr I was able to run Home Assistant on this easily, and I&amp;rsquo;d recommend it if you can&amp;rsquo;t get a Pi 4 (which is basically a given considering the lead times in 2022 are a year or more). This model is a step down from the 5060, but it&amp;rsquo;s still a good value for the price of the lowest Raspberry Pi models.&lt;/p&gt;
&lt;h2 id=&#34;teardown-video-and-usb-power-mod&#34;&gt;Teardown Video and USB Power Mod&lt;/h2&gt;
&lt;p&gt;I made a video showing the hardware inside my thin client, if you&amp;rsquo;re interested in seeing the teardown, USB power mod, or watching the BIOS configuration. I also prove that Home Assistant does install easily. xClick the thumbnail below to watch it.
&lt;a href=&#34;https://youtu.be/6Ls7xn4qdlk&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/wyse_3040/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I also did a USB power mod to this, since it didn&amp;rsquo;t come with a power supply and needs 5V/3A. I initially got a 3&amp;rsquo; USB cord and it functioned but it would occasionally reboot, especially under high CPU+GPU load. I cut the cord down to 18&amp;quot; to reduce the voltage drop along the cord and haven&amp;rsquo;t had any boot issues since then. It&amp;rsquo;s a cheap way to get this thing up and running, since USB bricks are really cheap.&lt;/p&gt;
&lt;h2 id=&#34;how-to-install-your-own-software&#34;&gt;How to Install your own Software&lt;/h2&gt;
&lt;p&gt;The 3040 has a pretty terrible BIOS/UEFI. The revision I have does not support legacy boot at all, so you can only boot OSes that support UEFI. It also doesn&amp;rsquo;t support configuration of the boot file path, so the boot file must be in the fallback path. This usually means you need to configure GRUB for &amp;lsquo;removable media&amp;rsquo; boot. Xubuntu and Home Assistant both did this by default, but Debian didn&amp;rsquo;t, so I had to boot back into rescue mode and re-install GRUB at the removable media path for it to boot correctly.&lt;/p&gt;
&lt;h2 id=&#34;hardware-info-for-the-curious&#34;&gt;Hardware Info for the curious&lt;/h2&gt;
&lt;p&gt;All of this was taken via an Xubuntu 20.04 Live CD, so your kernel may be configured slightly differently&lt;/p&gt;
&lt;h3 id=&#34;lscpu&#34;&gt;lscpu&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Architecture:                    x86_64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
Address sizes:                   36 bits physical, 48 bits virtual
CPU(s):                          4
On-line CPU(s) list:             0-3
Thread(s) per core:              1
Core(s) per socket:              4
Socket(s):                       1
NUMA node(s):                    1
Vendor ID:                       GenuineIntel
CPU family:                      6
Model:                           76
Model name:                      Intel(R) Atom(TM) x5-Z8350  CPU @ 1.44GHz
Stepping:                        4
CPU MHz:                         534.804
CPU max MHz:                     1920.0000
CPU min MHz:                     480.0000
BogoMIPS:                        2880.00
Virtualization:                  VT-x
L1d cache:                       96 KiB
L1i cache:                       128 KiB
L2 cache:                        2 MiB
NUMA node0 CPU(s):               0-3
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Mitigation; Clear CPU buffers; SMT disabled
Vulnerability Meltdown:          Mitigation; PTI
Vulnerability Spec store bypass: Not affected
Vulnerability Spectre v1:        Mitigation; usercopy/swapgs barriers and __user
                                  pointer sanitization
Vulnerability Spectre v2:        Mitigation; Full generic retpoline, IBPB condit
                                 ional, IBRS_FW, STIBP disabled, RSB filling
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected
Flags:                           fpu vme de pse tsc msr pae mce cx8 apic sep mtr
                                 r pge mca cmov pat pse36 clflush dts acpi mmx f
                                 xsr sse sse2 ss ht tm pbe syscall nx rdtscp lm 
                                 constant_tsc arch_perfmon pebs bts rep_good nop
                                 l xtopology tsc_reliable nonstop_tsc cpuid aper
                                 fmperf tsc_known_freq pni pclmulqdq dtes64 moni
                                 tor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse
                                 4_1 sse4_2 movbe popcnt tsc_deadline_timer aes 
                                 rdrand lahf_lm 3dnowprefetch epb pti ibrs ibpb 
                                 stibp tpr_shadow vnmi flexpriority ept vpid tsc
                                 _adjust smep erms dtherm ida arat md_clear
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Of note, it does support VT-x if you want to do virtualization, and AES-NI if you want to do anything involving crypto offload (VPN, HTTPS, &amp;hellip;)&lt;/p&gt;
&lt;h3 id=&#34;lspci&#34;&gt;lspci&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;00:00.0 Host bridge: Intel Corporation Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series SoC Transaction Register (rev 36)
00:02.0 VGA compatible controller: Intel Corporation Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Integrated Graphics Controller (rev 36)
00:0b.0 Signal processing controller: Intel Corporation Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series Power Management Controller (rev 36)
00:11.0 SD Host controller: Intel Corporation Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series SDIO Controller (rev 36)
00:14.0 USB controller: Intel Corporation Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series USB xHCI Controller (rev 36)
00:1a.0 Encryption controller: Intel Corporation Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series Trusted Execution Engine (rev 36)
00:1c.0 PCI bridge: Intel Corporation Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series PCI Express Port #1 (rev 36)
00:1f.0 ISA bridge: Intel Corporation Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series PCU (rev 36)
01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 15)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see, it uses a Realtek Ethernet Controller&lt;/p&gt;
&lt;h3 id=&#34;vainfo&#34;&gt;vainfo&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;libva info: VA-API version 1.7.0
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_7
libva error: /usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so init failed
libva info: va_openDriver() returns 1
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so
libva info: Found init function __vaDriverInit_1_6
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.7 (libva 2.6.0)
vainfo: Driver version: Intel i965 driver for Intel(R) CherryView - 2.4.0
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            :	VAEntrypointVLD
      VAProfileMPEG2Simple            :	VAEntrypointEncSlice
      VAProfileMPEG2Main              :	VAEntrypointVLD
      VAProfileMPEG2Main              :	VAEntrypointEncSlice
      VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointEncSlice
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointEncSlice
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointEncSlice
      VAProfileH264MultiviewHigh      :	VAEntrypointVLD
      VAProfileH264MultiviewHigh      :	VAEntrypointEncSlice
      VAProfileH264StereoHigh         :	VAEntrypointVLD
      VAProfileH264StereoHigh         :	VAEntrypointEncSlice
      VAProfileVC1Simple              :	VAEntrypointVLD
      VAProfileVC1Main                :	VAEntrypointVLD
      VAProfileVC1Advanced            :	VAEntrypointVLD
      VAProfileNone                   :	VAEntrypointVideoProc
      VAProfileJPEGBaseline           :	VAEntrypointVLD
      VAProfileJPEGBaseline           :	VAEntrypointEncPicture
      VAProfileVP8Version0_3          :	VAEntrypointVLD
      VAProfileVP8Version0_3          :	VAEntrypointEncSlice
      VAProfileHEVCMain               :	VAEntrypointVLD
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Hardware encode/decode is certainly usable for H264, although it&amp;rsquo;s not nearly as capable as the 5060 I reviewed previously&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>A Modern Linux Graphical Terminal Server</title>
      <link>https://www.apalrd.net/posts/2022/xrdp_intro/</link>
      <pubDate>Thu, 31 Mar 2022 08:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/xrdp_intro/</guid>
      <description>I&amp;rsquo;ve made many videos on Thin Clients before, all of them relying on Proxmox and the SPICE protocol. This works well when you control both the client and the hypervisor, and allows a lot of flexibility in the guest OS at the expense of flexibility at the client. If you want to rely on a remote access / Bring-Your-Own-Device type solution, you probably care more about solid multi-platform client support than flexibility in mixing VM OSes and running with no software installation on the VM.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve made many videos on Thin Clients before, all of them relying on Proxmox and the SPICE protocol. This works well when you control both the client and the hypervisor, and allows a lot of flexibility in the guest OS at the expense of flexibility at the client. If you want to rely on a remote access / Bring-Your-Own-Device type solution, you probably care more about solid multi-platform client support than flexibility in mixing VM OSes and running with no software installation on the VM. To this end, I&amp;rsquo;ve setup a modern Linux terminal server, which can be used to allow many clients to simultaneously connect to their own Linux desktops remotely, from nearly any device OS in common use today.&lt;/p&gt;
&lt;p&gt;This project is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/multiuser/&#34;&gt;Multiuser, Multidesktop, and Multiseat Megaproject&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;p&gt;This is a very long article, filled with many commands to copy and paste along with the reasoning behind them. Feel free to jump around to the sections relevant to you using the links below.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/#choosing-a-distribution&#34;&gt;Choosing a Distribution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/#install-xrdp&#34;&gt;Install XRDP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/#rdp-security-tips&#34;&gt;RDP Security Tips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/#restrict-users-to-remote-access-group&#34;&gt;Restrict Users to Remote Access Group&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/#limiting-resources-per-user&#34;&gt;Limiting Resources Per User&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/#color-managed-device-error&#34;&gt;Color Managed Device Error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/#conclusions&#34;&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;This project has a video! Click on the thumbnail to watch it.
&lt;a href=&#34;https://youtu.be/sAllRma_0xc&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;choosing-a-distribution&#34;&gt;Choosing a Distribution&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve chosen to base this install off xubuntu 21.10 Impish Indri. I chose xubuntu becasue it&amp;rsquo;s lighter weight than the GNOME or KDE desktops, and I&amp;rsquo;m hoping the reduced fluff will improve memory usage on systems with a large number of clients. I also enjoy XFCE as a generally simple and easy to use desktop environment. As to the release, I chose 21.10 as it&amp;rsquo;s the most recent release as of this writing, although support ends in just a few months as the 22.04 LTS drops very soon.&lt;/p&gt;
&lt;p&gt;Even though I&amp;rsquo;m setting up a terminal &lt;em&gt;server&lt;/em&gt;, I installed the Desktop version, since I&amp;rsquo;m going to need the full desktop environment and all of the user applications anyway. This also means the server&amp;rsquo;s physical console is now graphical, which isn&amp;rsquo;t really a huge deal, but you cannot log in to the physical console and virtual session at the same time, and the remote user cannot kick the physical console user.&lt;/p&gt;
&lt;p&gt;Instead of using a hypervisor as I usually do, I&amp;rsquo;ve installed this on a bare metal server, since I&amp;rsquo;m trying to load it up heavily with clients. My test platform is an AMD Ryzen 3400G (4c/8t) APU with 32G of RAM and a 500G SATA SSD.&lt;/p&gt;
&lt;p&gt;After installation I ran the usual software updates (&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade&lt;/code&gt;) and installed OpenSSH server so I can comfortably access it remotely (&lt;code&gt;sudo apt install openssh-server&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&#34;install-xrdp&#34;&gt;Install XRDP&lt;/h2&gt;
&lt;p&gt;First we need to install xrdp itself. Ubuntu has a package for it, so it&amp;rsquo;s pretty simple: &lt;code&gt;sudo apt install xrdp&lt;/code&gt;
At this point, you should be able to connect to the system using an existing user and get the XFCE desktop we know and love. However, you&amp;rsquo;ll notice a decently big problem - there is no sound.&lt;/p&gt;
&lt;p&gt;XRDP relies on an internal PulseAudio API which requires it to be compiled for the specific version of PulseAudio on the system, so we have to build the PulseAudio plugin ourselves. &lt;a href=&#34;https://github.com/neutrinolabs/pulseaudio-module-xrdp/wiki/Build-on-Debian-or-Ubuntu&#34;&gt;XRDP has a great guide on this here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So, here&amp;rsquo;s all of the commands from their guide compressed into one. It&amp;rsquo;ll ask for your sudo password and for you to confirm a few things.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install packages and make sure git is installed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install build-essential dpkg-dev libpulse-dev git autoconf libtool -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Change to home directory for git checkout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Clone repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/neutrinolabs/pulseaudio-module-xrdp.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#cd into repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd pulseaudio-module-xrdp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run the script they provide to get started&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;scripts/install_pulseaudio_sources_apt_wrapper.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Configure and make&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./bootstrap &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./configure PULSE_DIR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;~/pulseaudio.src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo make install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;rdp-security-tips&#34;&gt;RDP Security Tips&lt;/h2&gt;
&lt;p&gt;RDP with modern security settings to prevent protocol downgrade attacks, is generally considered to be a secure protocol on its own. User traffic is encrypted via TLS and user sessions are secure from eavesdropping and information leakage. However, the RDP server is not so lucky. Since RDP runs on a well-known port number, it&amp;rsquo;s not uncommon for bots to scan the entire internet for open RDP servers and try to connect with common Windows usernames and passwords. So not only is the protocol only as secure as the user&amp;rsquo;s password, but in many cases the RDP server will spawn a new remote session and then allow graphical login via the remote session, so bots will increase your CPU load by spawning a bunch of login screens.&lt;/p&gt;
&lt;p&gt;For some sense of scale, &lt;a href=&#34;https://www.shodan.io/search?query=remote+desktop+protocol&#34;&gt;shodan.io currently lists 3.8 million public facing RDP servers, and lists the operating system, FQDL, and certificate info for many of them&lt;/a&gt;. You WILL be on this list if you open your server up to the internet.&lt;/p&gt;
&lt;p&gt;Given all of this, I&amp;rsquo;d recommend against opening your RDP server directly to the internet. The xrdp developers have recently merged changes to log data specifically so fail2ban can block repeat abusers (as is common with SSH), but that release isn&amp;rsquo;t yet in Ubuntu and isn&amp;rsquo;t scheduled to be in the 22.04 LTS either. And even with fail2ban, you&amp;rsquo;re still letting an attacker connect to the server, start a graphical session, and then be disconnected for authentication failure, something which uses a lot more resources with xrdp than it does with SSH.&lt;/p&gt;
&lt;p&gt;Using a proper remote-access VPN solution to your home/business network or a cloud relay point is good security practice anyway, and I&amp;rsquo;d feel comfortable leaving RDP exposed to users within my private home/business network without further protection.&lt;/p&gt;
&lt;p&gt;Even with protocol level protections, each users on the system is still a user on the same system, so it&amp;rsquo;s possible for them to interact with the system and other users in a potentially undesirable way. Here are a few options you have to restrict user access a bit, even though they aren&amp;rsquo;t a comprehensive security guide.&lt;/p&gt;
&lt;h2 id=&#34;restrict-users-to-remote-access-group&#34;&gt;Restrict Users to Remote Access Group&lt;/h2&gt;
&lt;p&gt;By default, sesman (xrdp session manager) will restrict access to only users in the group  &lt;code&gt;tsusers&lt;/code&gt;, but only if the group exists. Since the package doesn&amp;rsquo;t create it, it won&amp;rsquo;t exist, and any account can login. Additionally, &lt;code&gt;/etc/xrdp/sesman.ini&lt;/code&gt; has an option to disable root login, separately from the tsusers group.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s up to you to decide if you want to limit access or allow any user on the system to connect. Depending on how exposed this server is, allowing users with sudo permissions may be more dangerous than you&amp;rsquo;d like. This all ties into the security concerns you have for the system. You should absolutely edit &lt;code&gt;sesman.ini&lt;/code&gt; to disable root access though.&lt;/p&gt;
&lt;p&gt;So, if you want to restrict user access, let&amp;rsquo;s create this group and add our VDI users to it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo groupadd -r tsusers
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To add a user, it&amp;rsquo;s pretty simple also:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo gpasswd -a &amp;lt;username&amp;gt; tsusers
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;limiting-resources-per-user&#34;&gt;Limiting Resources Per User&lt;/h2&gt;
&lt;p&gt;This section is optional. If you want to prevent a single user from hogging all of the system resources, then you can use Linux control groups to achieve this. Depending on how you set your limits, this won&amp;rsquo;t stop multiple users from really bogging down the system, so be aware of how many resources you actually want to give each user, but at the same time give them enough to do what they need successfully. If you occasionally have 10 users but normally have 1-2, setting the limits to 1/3 of the system capacity would let the normal users perform more processor intensive work (such as compiling) without being artificially limited to a fraction of an otherwise unused CPU.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://freedesktop.org/software/systemd/man/systemd.resource-control.html&#34;&gt;Systemd has a reference on resource control for user slices here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Systemd has a folder structure where we can limit resources per user - they need to go in &lt;code&gt;/etc/systemd/system/user-1000.slice.d&lt;/code&gt; for user id 1000. However, we can create defaults by creating a .conf file in the folder folder &lt;code&gt;/etc/systemd/system/user-.slice.d/*.conf&lt;/code&gt;. Systemd recognizes the &lt;code&gt;user-&lt;/code&gt; as a default path if there is no user-specific file or folder.&lt;/p&gt;
&lt;p&gt;So, we will create this default user slice configuration folder and a configuration file inside of it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mkdir -p /etc/systemd/system/user-.slice.d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo nano /etc/systemd/system/user-.slice.d/50-vdiusers.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the contents - &lt;code&gt;CPUQuota&lt;/code&gt; is a % relative to a single thread, so if you have a 4c/8t CPU, the maximum would be 800%. In this case, I&amp;rsquo;ve limited it to a two threads. &lt;code&gt;MemoryMax&lt;/code&gt; can be specified in M or G, and the OOM Killer will come and reap processes from the user when they exceed their limits as if the system only had that much memory and could not swap. There&amp;rsquo;s also a &lt;code&gt;MemoryHigh&lt;/code&gt; option you can use which will start slowing down processes when the memory reaches above the threshold, if you&amp;rsquo;d like to set that to something less than &lt;code&gt;MemoryMax&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[Slice]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CPUAccounting&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CPUQuota&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;200%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;MemoryAccounting&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;MemoryMax&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;2G&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want to read the full systemd documentation on resource control, &lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html&#34;&gt;you can read it here&lt;/a&gt;. There are a lot of options there if you really want fine-grained control of resource usage by your users.&lt;/p&gt;
&lt;p&gt;Since XRDP runs as its own user as a system service, it&amp;rsquo;s not part of the user pool, it&amp;rsquo;s part of the service pool. This means that xdrp&amp;rsquo;s actions of performing graphical compression are not counted to the user&amp;rsquo;s quotas, but they can add up, especially if the user is doing a lot of work with motion video or graphics.&lt;/p&gt;
&lt;h2 id=&#34;color-managed-device-error&#34;&gt;Color Managed Device Error&lt;/h2&gt;
&lt;p&gt;This one is intermittent. On Ubuntu 21.10, we can fix this by adding a PolKit configuration file to allow users to change their own color profiles. Note that the version of polkit matters here, version 0.105 is shipped with Ubuntu 21.10 and requires pkla files.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo nano /etc/polkit-1/localauthority/50-local.d/45-allow-colord.pkla
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf&#34; data-lang=&#34;conf&#34;&gt;[Allow Colord all Users]
Identity=unix-user:*
Action=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile
ResultAny=no
ResultInactive=no
ResultActive=yes
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For various reasons, Ubuntu has stuck with backporting security fixes to an ancient version of polkit instead of upgrading to a more modern release that uses the javascript configuration method, as they do not want to depend on mozjs (Spidermonkey) for security critical functions. Since polkit has &lt;strong&gt;just&lt;/strong&gt; switched to a proper tiny embedded javascript engine, it&amp;rsquo;s very likely that all of the rules syntax above is going to become obsolete within a few Ubuntu releases.s&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;I chose RDP over a VNC-based solution as the protocol is extremely well standardized and has very wide client support, including clients available for the usual Windows/macOS/Linux, but also iOS, iPadOS, Android, Android TV, and even Samsung&amp;rsquo;s Tizen OS for smart TVs. It&amp;rsquo;s also extremely easy to get a basic setup working. Performance in terms of number of users on a single system is good, since we aren&amp;rsquo;t relying on virtualization at all, and all users are able to efficiently share system resources.&lt;/p&gt;
&lt;p&gt;This setup is good if you want to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Centralize computing / storage in a bring-your-own device fashion&lt;/li&gt;
&lt;li&gt;Get full desktop functionality out of an otherwise limited operating system (i.e. Android, iOS, Smart TVs)&lt;/li&gt;
&lt;li&gt;Connect back to your Linux desktop while away from home, which also keeps sensitive data off your mobile devices while traveling in case they are lost / stolen / forced to be unlocked by customs and border patrol&lt;/li&gt;
&lt;li&gt;Less system overhead and resource utilization than VMs&lt;/li&gt;
&lt;li&gt;Hardware GPU acceleration is available to all users from a single GPU for transcoding (but not OpenGL AFAIK)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s not a great solution if you want:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows (Microsoft offers this for $$$)&lt;/li&gt;
&lt;li&gt;Complete multi-user and entire filesystem isolation for each session&lt;/li&gt;
&lt;li&gt;Ephemeral clones of the entire system (VM), cleared after each user&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Multiuser, Multidesktop, and Multiseat Megaproject</title>
      <link>https://www.apalrd.net/projects/2022/multiuser/</link>
      <pubDate>Thu, 31 Mar 2022 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2022/multiuser/</guid>
      <description>In this project, I explore thin client software, and set up a Raspberry Pi to act as a thin client. This is a multi-part project, follow along below for each sub-project.
A Modern Linux Graphical Terminal Server For the first project, I setup a remote desktop terminal server, allowing many users to connect to a single server and operate indepednent graphical sessions. My test bench was able to handle a dozen simulatneous users, and a proper server should be able to handle many more.</description>
      <content>&lt;p&gt;In this project, I explore thin client software, and set up a Raspberry Pi to act as a thin client. This is a multi-part project, follow along below for each sub-project.&lt;/p&gt;
&lt;h2 id=&#34;a-modern-linux-graphical-terminal-server&#34;&gt;A Modern Linux Graphical Terminal Server&lt;/h2&gt;
&lt;p&gt;For the first project, I setup a remote desktop terminal server, allowing many users to connect to a single server and operate indepednent graphical sessions. My test bench was able to handle a dozen simulatneous users, and a proper server should be able to handle many more. Inspired by an email sent to me, my goal of this project is to create a low cost solution for schools in developing regions to be able to teach programming and other things that require a computer desktop, while using the hardware available (tablets, TVs, &amp;hellip;) as the user interface to the desktop. But it&amp;rsquo;s widely applicable to any organization using Linux, and can be expanded into a cluster and shared storage system to allow all users to do their work with centralized compute, keeping data securely at the server.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/&#34;&gt;&lt;img alt=&#34;A Modern Linux Graphical Terminal Server&#34; src=&#34;https://www.apalrd.net/posts/2022/xrdp_intro/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;2-gamers-1-cpu-no-virtualization&#34;&gt;2 gamers, 1 cpu, NO Virtualization!&lt;/h2&gt;
&lt;p&gt;The second project in the series was a ton of fun to research and produce. I was able to use Linux Multiseat to operate a single Ryzen system with two graphics cards (one integrated, one dedicated) to allow two gamers to play native Linux games with full OpenGL and Vulkan support on the same computer. Unlike other people before me, I did not rely on virtualization or hardware passthrough, but this is a purely multi-user Linux solution running on a single kernel.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/multiseat_intro/&#34;&gt;&lt;img alt=&#34;2 gamers, 1 cpu, NO Virtualization!&#34; src=&#34;https://www.apalrd.net/posts/2022/multiseat_intro/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Low-Cost Garage Door Automation with Home Assistant and Sonoff</title>
      <link>https://www.apalrd.net/posts/2022/garage_door/</link>
      <pubDate>Thu, 24 Mar 2022 07:43:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/garage_door/</guid>
      <description>Of all of the doors in a normal US McMansion, the garage doors are the biggest, and are almost always motorized. This means they are an easy target for automation, since most of the hardware is already there, we just need to bridge it to the virtual space. The cheapest way to do this is to use a door contact switch and dry contact relay which are compatible with Home Assistant, and some YAML magic to bridge them together.</description>
      <content>&lt;p&gt;Of all of the doors in a normal US McMansion, the garage doors are the biggest, and are almost always motorized. This means they are an easy target for automation, since most of the hardware is already there, we just need to bridge it to the virtual space. The cheapest way to do this is to use a door contact switch and dry contact relay which are compatible with Home Assistant, and some YAML magic to bridge them together.&lt;/p&gt;
&lt;h2 id=&#34;contents&#34;&gt;Contents&lt;/h2&gt;
&lt;p&gt;This is a pretty long one, so here&amp;rsquo;s some links to different sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/garage_door/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/garage_door/#sensing&#34;&gt;Sensing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/garage_door/#control&#34;&gt;Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/garage_door/#template-cover&#34;&gt;Template Cover&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/garage_door/#project-files-and-parts-list&#34;&gt;Project Files and Parts List&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;This article has a corresponding video! Watch it here
&lt;a href=&#34;https://youtu.be/-rLD8GzZQu4&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/garage_door/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;sensing&#34;&gt;Sensing&lt;/h2&gt;
&lt;p&gt;You can use regular magnetic door contacts with garage doors, but they also make more robust garage door contacts if you&amp;rsquo;re concerned with durability. I ended up using an Aqara Zigbee sensor, and I bought a pack of them for some other doors in the house. The are pretty functional for the cost. I attached them near the top corner of the garage door, and they can sense when the door is all the way closed. Make sure the magnet and sensor are close enough to each other, one of my 3 doors was not close enough and only intermittently detected the door as closed.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Unboxing the Sensor&#34; src=&#34;https://www.apalrd.net/posts/2022/garage_door/aqara_box.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Unboxing the sensor - packaging is kinda wasteful, but the sensor isn&#39;t too ugly&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Garage Door Contact&#34; src=&#34;https://www.apalrd.net/posts/2022/garage_door/aqara_gdoor.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Door sensor installed next to top of the door&lt;/div&gt;
&lt;h2 id=&#34;control&#34;&gt;Control&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s critical for the Control side that you get a smart relay with a dry contact. A lot of smart relays are mains or DC powered, and output mains or DC from the relay. This won&amp;rsquo;t work for a garage door opener, where you need to bridge two contacts and not connect them to anything else. The Sonoff Mini will NOT work, but the Shelly 1 will, and also has a switch input if you want a wired door switch, so it&amp;rsquo;s a great option for a single door.&lt;/p&gt;
&lt;p&gt;In my case, I have 3 doors to control. So, the Sonoff 4CH PRO R3 works for me for less cost total than the Shelly&amp;rsquo;s - it has 4 separate relays, each of which is electrically isolated from each other (only isolated on the PRO!). I flashed it with Tasmota (see my &lt;a href=&#34;https://www.apalrd.net/posts/2021/tasmota_day/&#34;&gt;Tasmota Day&lt;/a&gt; for how), which gives me full control of the device with purely local integration over MQTT.&lt;/p&gt;
&lt;p&gt;Once I had Tasmota flashed and the Sonoff connected to my network, it&amp;rsquo;s time to configure it. Start by finding the IP address (I look on my router&amp;rsquo;s DHCP leases for new Tasmota devices but Tasmotizer has a &amp;lsquo;Get IP&amp;rsquo; button that works too), and connect to it over HTTP. The 4CH has four bit &amp;lsquo;ON&amp;rsquo;/&amp;lsquo;OFF&amp;rsquo; labels as well as 4 Toggle buttons, as well as the usual Tasmota configuration buttons. Click &amp;lsquo;Configuration&amp;rsquo;, then &amp;lsquo;Configure MQTT&amp;rsquo;, and enter the broker information. I don&amp;rsquo;t like how Tasmota pollutes the root namespace in MQTT with tele, cmnd, etc. so I change the default topic structure to be &amp;lsquo;raw/%topic%/%prefix%/, which ends up with a topic like raw/tasmota_123ABC/stat/POWER1. I set this structure for my Tasmota devices when I was newer to MQTT, but now I would have chosen &amp;rsquo;tasmota/%topic%/%prefix%/&amp;rsquo;, so tasmota devices get their own folder in the namepace, followed by each individual device. This is more of a personal opinion on how to structure MQTT topics. Save configuration here, and it should restart automatically.&lt;/p&gt;
&lt;p&gt;Another configuration which is optional is to change the name. It doesn&amp;rsquo;t need a name, but if you set it, it will show the name on the main screen and in the HTML title. To set this, go to Configuration -&amp;gt; Configure Other and set Device Name to whatever is meaningful to you. If you have a bunch of Tasmota devices, having the name listed on the top of the page can really help you ensure that you&amp;rsquo;re connected to the correct one. You can also name the individual outputs, and naming them now will make things easier in Home Assistant later (using the Tasmota integration).&lt;/p&gt;
&lt;p&gt;For the outputs we are using for garage doors, we want the outputs to turn off automatically (so sending an &amp;lsquo;ON&amp;rsquo; causes the output to turn on, wait a second, then turn back off). This can be done by setting the parameter PulseTimeX, where X is the relay number (and X can be omitted entirely for single-relay modules like the Shelly). From the main screen, click Console, and type in the following commands to change the values. In my case, I am using 3 relays for my 3 doors, so I only set the pulse timer for those 3 relays. &lt;a href=&#34;https://tasmota.github.io/docs/Commands/#pulsetime&#34;&gt;Tasmota Documentation on PulseTime&lt;/a&gt;. The number changes meaning at different scales, for numbers less than 111, it means 0.1 seconds, so 15 equals 1.5 seconds.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PulseTime1 &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PulseTime2 &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PulseTime3 &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tasmota should echo the new value of the setting in JSON, such as  &lt;code&gt;{&amp;quot;Pulsetime&amp;quot;:15}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Finally, after setting up the Sonoff, add it using the Tasmota integration in Home Assistant. Rename the devices so they make sense, the usual Home Assistant stuff.&lt;/p&gt;
&lt;h2 id=&#34;template-cover&#34;&gt;Template Cover&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the Template Cover I created for one of the garage doors.&lt;/p&gt;
&lt;p&gt;First, make sure you have a covers section in your &lt;code&gt;configuration.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;cover&lt;/span&gt;: !&lt;span style=&#34;color:#ae81ff&#34;&gt;include covers.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then I put my template covers in &lt;code&gt;covers.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;covers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;garage_door_south&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;device_class&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;garage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;garage_door_south&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;friendly_name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Garage Door South&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;value_template&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ is_state(&amp;#39;binary_sensor.garage_door_south_contact&amp;#39;,&amp;#39;on&amp;#39;) }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;open_cover&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;condition&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.garage_door_south_contact&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;off&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switch.turn_on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;target&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switch.garage_door_opener_south&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;close_cover&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;condition&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.garage_door_south_contact&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;on&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switch.turn_on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;target&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switch.garage_door_opener_south&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;stop_cover&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switch.turn_on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;target&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switch.garage_door_opener_south&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;icon_template&lt;/span&gt;: &amp;gt;-&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          {% if is_state(&amp;#39;binary_sensor.garage_door_south&amp;#39;,&amp;#39;on&amp;#39;) %}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            mdi:garage-open
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          {% else %}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            mdi:garage
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          {% endif %}&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;project-files-and-parts-list&#34;&gt;Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project. Since this project has no custom parts, there are no files, just things you can buy and open source software.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://tasmota.github.io/docs/&#34;&gt;Tasmota software page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://templates.blakadder.com/sonoff_4CHPROR3.html&#34;&gt;Tasmota Sonoff 4CH PRO R3 configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tasmota/tasmotizer&#34;&gt;Tasmotizer flashing tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://s.click.aliexpress.com/e/_9ISGTx&#34;&gt;Aqara Door Switch (affiliate link)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://sonoff.tech/product/diy-smart-switch/4chr3-4chpror3/&#34;&gt;Sonoff 4CHPRO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://shelly.cloud/products/shelly-1-smart-home-automation-relay/&#34;&gt;Shelly 1 (Single Door Option)&lt;/a&gt;
Some links to products may be affiliate links, which may earn a commission for me.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Studio Upgrade - New Mic!</title>
      <link>https://www.apalrd.net/posts/2022/studio_mic/</link>
      <pubDate>Mon, 21 Mar 2022 08:27:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/studio_mic/</guid>
      <description>Today I got my first upgrade to the studio setup: A new microphone! I chose a Rode Videomic Go II, which has USB-C and 3.5mm outputs, and they have a USB-C to Lightning cable available to connect to my phone. Since I use my iPhone for filming (often my older iPhone SE), this was important to me, but the ability to connect digitally to my desktop for recording screen capture with high quality audio was also important, so I didn&amp;rsquo;t want to get the smaller mics that clip directly on to the phone&amp;rsquo;s lightning port.</description>
      <content>&lt;p&gt;Today I got my first upgrade to the studio setup: A new microphone! I chose a Rode Videomic Go II, which has USB-C and 3.5mm outputs, and they have a USB-C to Lightning cable available to connect to my phone. Since I use my iPhone for filming (often my older iPhone SE), this was important to me, but the ability to connect digitally to my desktop for recording screen capture with high quality audio was also important, so I didn&amp;rsquo;t want to get the smaller mics that clip directly on to the phone&amp;rsquo;s lightning port. The mic has a &amp;lsquo;cold shoe&amp;rsquo; style mount, and since I don&amp;rsquo;t have any equipment with that, I 3D printed a bracket to hold the mic on top of my monitor that can also act as a kick-stand to hold the mic on a table.&lt;/p&gt;
&lt;p&gt;Anyway here&amp;rsquo;s the video to go along with this blog:
&lt;a href=&#34;https://youtu.be/hcVXoQuwAtU&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/studio_mic/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I also 3D printed a mount for the mic, and you can download them below. As usual, CAD files are licensed CC-BY-SA. You&amp;rsquo;ll need a 1&amp;quot; #8-23 UNF fastener and nylock nut to attach the foot to the base.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/studio_mic/WebcamColdShoe-Base.amf&#34;&gt;Base Model (amf format)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/studio_mic/WebcamColdShoe-Foot.amf&#34;&gt;Foot Model (amf format)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/studio_mic/WebcamColdShoe.3mf&#34;&gt;PrusaSlicer 3MF file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/studio_mic/WebcamColdShoe.FCStd&#34;&gt;FreeCAD Original&lt;/a&gt;
No idea if the nearest metric equivalent (M5) will fit in the nut pocket, the struggles of living in a country with backwards units.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Setting up a Proxmox HA Cluster</title>
      <link>https://www.apalrd.net/posts/2022/cluster_intro/</link>
      <pubDate>Thu, 17 Mar 2022 09:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/cluster_intro/</guid>
      <description>I&amp;rsquo;ve been playing with the Dell Wyse 5060 I bought before and I &amp;hellip;. might have bought a few more. I was so impressed by the performance for $35, the CPU and GPU were very functional, and the system had enough SSD storage and RAM to do actual real work. So, considering people have tried to run Proxmox on the Raspberry Pi 4, these things must be adequate for a Proxmox HA cluster.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve been playing with the &lt;a href=&#34;https://www.apalrd.net/posts/2022/wyse_basic/&#34;&gt;Dell Wyse 5060&lt;/a&gt; I bought before and I &amp;hellip;. might have bought a few more. I was so impressed by the performance for $35, the CPU and GPU were very functional, and the system had enough SSD storage and RAM to do actual real work. So, considering people have tried to run Proxmox on the Raspberry Pi 4, these things must be adequate for a Proxmox HA cluster. Proxmox has a ton of clustering features, so using these cheap thin clients I was able to play with Proxmox&amp;rsquo;s HA and migration features. A fun bit of experimentation for sure.&lt;/p&gt;
&lt;p&gt;This is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/cluster/&#34;&gt;Hyper-Converged Cluster Megaproject&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;the-video&#34;&gt;The Video&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the video that goes along with this. I don&amp;rsquo;t really have much to add here, I basically just run through the Proxmox cluster setup and demonstrate some features of Proxmox&amp;rsquo;s cluster features.
&lt;a href=&#34;https://youtu.be/jRroVNHBDeI&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/cluster_intro/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Hyper-Converged Cluster Megaproject</title>
      <link>https://www.apalrd.net/projects/2022/cluster/</link>
      <pubDate>Thu, 17 Mar 2022 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2022/cluster/</guid>
      <description>In this project, I explore using low cost thin clients as cluster nodes, the fundamentals of Proxmox clustering, redundant storage, and hyper-converged infrastructure using Proxmox and Ceph.
Setting up a Proxmox HA Cluster In the first video, I take the Dell Wyse 5060 I bought before and &amp;hellip; bought 2 more. Once I had 3, I built a complete high availability cluster using them, demonstrating the very basics of Proxmox clustering, high availability resources, and how Proxmox handles failure.</description>
      <content>&lt;p&gt;In this project, I explore using low cost thin clients as cluster nodes, the fundamentals of Proxmox clustering, redundant storage, and hyper-converged infrastructure using Proxmox and Ceph.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-a-proxmox-ha-cluster&#34;&gt;Setting up a Proxmox HA Cluster&lt;/h2&gt;
&lt;p&gt;In the first video, I take the &lt;a href=&#34;https://www.apalrd.net/posts/2022/wyse_basic/&#34;&gt;Dell Wyse 5060&lt;/a&gt; I bought before and &amp;hellip; bought 2 more. Once I had 3, I built a complete high availability cluster using them, demonstrating the very basics of Proxmox clustering, high availability resources, and how Proxmox handles failure.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_intro/&#34;&gt;&lt;img alt=&#34;Setting up a Proxmox HA Cluster&#34; src=&#34;https://www.apalrd.net/posts/2022/cluster_intro/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;small-proxmox-cluster-tips-and-tricks-and-qdevices&#34;&gt;Small Proxmox Cluster Tips and Tricks, and QDevices&lt;/h2&gt;
&lt;p&gt;In this video, I walk through the nuances of 2 and 3 node Proxmox clusters, maintaining quorum, and installing a QDevice if you need one.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_qdevice/&#34;&gt;&lt;img alt=&#34;Small Proxmox Cluster Tips and Tricks, and QDevices&#34; src=&#34;https://www.apalrd.net/posts/2022/cluster_qdevice/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;making-the-250-proxmox-ha-cluster-hyperconverged&#34;&gt;Making the $250 Proxmox HA Cluster Hyperconverged&lt;/h2&gt;
&lt;p&gt;In this video, I add additional RAM and storage to each node, and turn it into a hyper-converged cluster using Ceph. Ceph is the filesystem of BIG DATA, scale out solutions, so I&amp;rsquo;m excited to learn it. But Ceph is also a BIG topic, so in this episode I just focused on setting it up within Proxmox and setting up a basic replicated pool for RBD (RADOS Block Device) storage of virtual machines, all features that can be doen through the Proxmox GUI. I&amp;rsquo;ll dive into deeper Ceph topics in the future.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_ceph/&#34;&gt;&lt;img alt=&#34;Making the $250 Proxmox HA Cluster Hyperconverged&#34; src=&#34;https://www.apalrd.net/posts/2022/cluster_ceph/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;all-about-pools--proxmox--ceph-hyperconverged-cluster-fäncy-configurations-for-rbd&#34;&gt;All about POOLS | Proxmox + Ceph Hyperconverged Cluster fäncy Configurations for RBD&lt;/h2&gt;
&lt;p&gt;In this video, I expand on the last video of my hyper-converged Proxmox + Ceph cluster to create more custom pool layouts than Proxmox&amp;rsquo;s GUI allows. This includes setting the storage class (HDD / SSD / NVME), failure domain, and even erasure coding of pools. All of this is then setup as a storage location in Proxmox for RBD (RADOS Block Device), so we can store VM disks on it.&lt;/p&gt;
&lt;p&gt;After all of this, I now have the flexibility to assign VM disks to HDDs or SSDs, and use erasure coding to get 66% storage efficiency instead of 33% (doubling my usable capacity for the same disks!). With more nodes and disks, I could improve both the storage efficiency and failure resilience of my cluster, but with only the small number of disks I have, I opted to go for a basic 2+1 erasure code.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/cluster_ceph_pools/&#34;&gt;&lt;img alt=&#34;All about POOLS | Proxmox + Ceph Hyperconverged Cluster fäncy Configurations for RBD&#34; src=&#34;https://www.apalrd.net/posts/2022/cluster_ceph_pools/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Orders of Magnitude</title>
      <link>https://www.apalrd.net/posts/2022/orders_of_magnitude/</link>
      <pubDate>Tue, 15 Mar 2022 00:10:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/orders_of_magnitude/</guid>
      <description>When I reached 100 subscribers, I was very excited and posted about it here. But now, I&amp;rsquo;ve crossed 1000. After reaching 100, I was excited for the next hundred, but it came by so fast that within a few weeks I blew by 200,300,400&amp;hellip; and was at 1000. The next goal becomes not a doubling, but the next order of magnitude. Exponential growth. I don&amp;rsquo;t expect to reach 100k (two more orders of magnitude), but maybe I&amp;rsquo;ll eventually reach the next order of magnitude.</description>
      <content>&lt;p&gt;When I reached 100 subscribers, I was very excited and &lt;a href=&#34;https://www.apalrd.net/posts/2022/youtube_100/&#34;&gt;posted about it here&lt;/a&gt;. But now, I&amp;rsquo;ve crossed 1000. After reaching 100, I was excited for the next hundred, but it came by so fast that within a few weeks I blew by 200,300,400&amp;hellip; and was at 1000. The next goal becomes not a doubling, but the next order of magnitude. Exponential growth. I don&amp;rsquo;t expect to reach 100k (two more orders of magnitude), but maybe I&amp;rsquo;ll eventually reach the next order of magnitude.&lt;/p&gt;
&lt;p&gt;On the flip side, every subscriber is more meaningful with lower numbers. Going from zero to one, one to ten, those individual users all meant something individually. Now, it&amp;rsquo;s more of a trend, tracking what my viewers like in aggregate, how videos respond with hundreds of views.&lt;/p&gt;
&lt;p&gt;Just some late night thoughts on statistics and growth.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/0fKBhvDjuy0&#34;&gt;Also, a very cool video by Charles and Ray Eames titled &amp;lsquo;powers of ten&amp;rsquo;, for your curiosity.&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Choose a Thin Client Session Graphically</title>
      <link>https://www.apalrd.net/posts/2022/raspi_spice_login/</link>
      <pubDate>Thu, 10 Mar 2022 08:27:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/raspi_spice_login/</guid>
      <description>In previous posts, I&amp;rsquo;ve been building up a thin client / VDI infrastructure based on Proxmox hosted virtual machines, using the SPICE protocol. This has gone well. However, the current setup basically launches the computer into a purely thin client mode, where it&amp;rsquo;s hardcoded to a specific VM and can do nothing else. There has been some interest in making some kind of launcher to select VMs to log in to, and I decided to find a solution for this.</description>
      <content>&lt;p&gt;In previous posts, I&amp;rsquo;ve been building up a thin client / VDI infrastructure based on Proxmox hosted virtual machines, using the SPICE protocol. This has gone well. However, the current setup basically launches the computer into a purely thin client mode, where it&amp;rsquo;s hardcoded to a specific VM and can do nothing else. There has been some interest in making some kind of launcher to select VMs to log in to, and I decided to find a solution for this. I started on the latest Raspberry Pi OS, but I found that they&amp;rsquo;ve hacked at their display manager / desktop environment enough that it&amp;rsquo;s not exactly like any other distribution, so in this blog post I&amp;rsquo;m going to try and implement this using both Raspberry Pi OS and Debian with LXDE installed. This is as close as I can get to the same environment as the Pi, so the instructions are similar.&lt;/p&gt;
&lt;p&gt;This article is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/thin_client/&#34;&gt;Thin Client Series&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This article was written with Raspberry Pi OS (32-bit) Bullseye release 2022-01-28 and Debian Bullseye release 11.2.0.&lt;/p&gt;
&lt;h2 id=&#34;sections&#34;&gt;Sections&lt;/h2&gt;
&lt;p&gt;This page is really long, so here are pointers to individual sections&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/#video&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/#setup-for-raspberry-pi&#34;&gt;Setup for Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/#setup-for-debian&#34;&gt;Setup for Debian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/#installing-dependencies&#34;&gt;Installing Dependencies (and the thin client script)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/#creating-virtual-session-users&#34;&gt;Creating Virtual Session Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/#configuring-lxde-autostart&#34;&gt;Configuring LXDE Autostart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/#conclusions&#34;&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;Of course, I have a video to go along with this topic. Click the thumbnail to watch it on Youtube.
&lt;a href=&#34;https://youtu.be/sNgmMxrnLn8&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup-for-raspberry-pi&#34;&gt;Setup for Raspberry Pi&lt;/h2&gt;
&lt;p&gt;Getting started, we need to use Raspberry Pi Imager to image an SD card with the latest version of Raspberry Pi OS. This time, we are starting from the full version, not lite, so we get the full graphical environment.&lt;/p&gt;
&lt;p&gt;Once it&amp;rsquo;s installed, boot it up, and go through the &amp;lsquo;Welcome to Raspberry Pi&amp;rsquo; wizard, which sets your keyboard layout, timezone, etc, and let it run updates. It might take awhile.&lt;/p&gt;
&lt;p&gt;Now, we have a few more configuration things to do. Open a terminal, and run &lt;code&gt;sudo raspi-config&lt;/code&gt;. We need to configure the following things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;System Options -&amp;gt; Boot / Auto Login, set to Desktop instead of Desktop Autologin (we want to require a login)&lt;/li&gt;
&lt;li&gt;Interface Options -&amp;gt; SSH and enable it (we will use it to configure the Virtual Session users)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now reboot and continue with the software install below.&lt;/p&gt;
&lt;h2 id=&#34;setup-for-debian&#34;&gt;Setup for Debian&lt;/h2&gt;
&lt;p&gt;I started with the Debian Netinst image and selected &amp;lsquo;Install&amp;rsquo; (NOT &amp;lsquo;Graphical Install&amp;rsquo;), so we will end up with a console environment and need to install the graphical bits later. Important bits for the installer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do not set a root password, so Debian installs sudo&lt;/li&gt;
&lt;li&gt;The new user you create will be the administrative user (with sudo permissions), so choose something good, not something you&amp;rsquo;re going to want to use later as a virtual session user&lt;/li&gt;
&lt;li&gt;Choose Guided -&amp;gt; Use Entire Disk for partition type&lt;/li&gt;
&lt;li&gt;Choose &amp;lsquo;All files in one partition&amp;rsquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Eventually, it will ask you if you would like to install a desktop environment.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deselect GNOME&lt;/li&gt;
&lt;li&gt;Select LXDE&lt;/li&gt;
&lt;li&gt;Select SSH server (so we can debug like we could on the Pi)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We have one last configuration bit to modify: editing the lightdm configuration to show the user list. Edit it with &lt;code&gt;sudo nano /etc/lightdm/lightdm.conf&lt;/code&gt;. Scroll down until you find &lt;code&gt;#greeter-hide-users=false&lt;/code&gt; and remove the &lt;code&gt;#&lt;/code&gt;, so the user list is not hidden.&lt;/p&gt;
&lt;h2 id=&#34;installing-dependencies&#34;&gt;Installing Dependencies&lt;/h2&gt;
&lt;p&gt;We already have a working graphical environment, so we need to update (just to be safe) and install remote-viewer (part of the virt-viewer package), and then create our thin client script. We also need curl, which isn&amp;rsquo;t installed by default on Debian but is on Raspberry Pi OS.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt upgrade
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install virt-viewer curl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;thin-client-script&#34;&gt;Thin Client Script&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;re using basically the same script as the previous iteration of this project, except this time we are sharing the script across users and passing in the VM ID as an argument. In addition, at the end of the script, we are killing lxsession which effectively logs us out, so instead of the user being stuck in kiosk mode forever, any attempt to exit the thin client results in being sent back to the login screen. Since both Raspberry Pi OS and Debian are using LXDE, the same script works for both.&lt;/p&gt;
&lt;p&gt;Important note here. This script will ask the Proxmox API to return a spiceproxy file. The spiceproxy file, by default, will contain the DNS name of the Proxmox node currently running the VM (the name you set in the Proxmox installer). If that name does not resolve correctly on your network, you will need to add an argument to curl to force the spiceproxy file to use the specified proxy address instead (which is &lt;code&gt;$PROXY&lt;/code&gt;, likely the IP address). I&amp;rsquo;ve left a line commented out that shows what the alternate command would be, so replace the uncommented curl command with the commented one if you need the proxy argument.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo nano /usr/local/bin/thinclient
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;set -e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set auth options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PASSWORD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;vdiuser&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;USERNAME&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;vdiuser@pve&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set VM ID from the first and only argument&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;VMID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$1&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set Node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# This must either be a DNS address or name of the node in the cluster&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NODE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pvehost&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Proxy equals node if node is a DNS address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Otherwise, you need to set the IP address of the node here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PROXY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$NODE&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The rest of the script originated from a Proxmox example&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Strip the DNS name to get the node name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NODE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;NODE%%&lt;span style=&#34;color:#ae81ff&#34;&gt;\.&lt;/span&gt;*&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Authenticate to the API and get a ticket and CSRF token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DATA&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;curl -f -s -S -k --data-urlencode &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;username=&lt;/span&gt;$USERNAME&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; --data-urlencode &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;password=&lt;/span&gt;$PASSWORD&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://&lt;/span&gt;$PROXY&lt;span style=&#34;color:#e6db74&#34;&gt;:8006/api2/json/access/ticket&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;AUTH OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Extract the ticket an CSRF token from the returned data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TICKET&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;DATA//&lt;span style=&#34;color:#ae81ff&#34;&gt;\&amp;#34;&lt;/span&gt;/&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TICKET&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TICKET##*ticket:&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TICKET&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TICKET%%,*&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TICKET&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TICKET%%&lt;span style=&#34;color:#ae81ff&#34;&gt;\}&lt;/span&gt;*&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CSRF&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;DATA//&lt;span style=&#34;color:#ae81ff&#34;&gt;\&amp;#34;&lt;/span&gt;/&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CSRF&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CSRF##*CSRFPreventionToken:&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CSRF&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CSRF%%,*&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CSRF&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CSRF%%&lt;span style=&#34;color:#ae81ff&#34;&gt;\}&lt;/span&gt;*&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Request a SPICE config file from the API&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Note that I&amp;#39;ve removed the proxy argument&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#This results in Proxmox pointing remote-viewer to the node that is currently running the VM,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#instead of the node that we specified with PROXY. Only useful in clustered scenarios,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#but it doesn&amp;#39;t hurt to leave it out.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#I left the other command commented out, so you can replace the first curl with the second if you need the argument&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -f -s -S -k -b &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PVEAuthCookie=&lt;/span&gt;$TICKET&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CSRFPreventionToken: &lt;/span&gt;$CSRF&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://&lt;/span&gt;$PROXY&lt;span style=&#34;color:#e6db74&#34;&gt;:8006/api2/spiceconfig/nodes/&lt;/span&gt;$NODE&lt;span style=&#34;color:#e6db74&#34;&gt;/qemu/&lt;/span&gt;$VMID&lt;span style=&#34;color:#e6db74&#34;&gt;/spiceproxy&amp;#34;&lt;/span&gt; -X POST &amp;gt; spiceproxy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#curl -f -s -S -k -b &amp;#34;PVEAuthCookie=$TICKET&amp;#34; -H &amp;#34;CSRFPreventionToken: $CSRF&amp;#34; &amp;#34;https://$PROXY:8006/api2/spiceconfig/nodes/$NODE/qemu/$VMID/spiceproxy&amp;#34; -X POST -d &amp;#34;proxy=$PROXY&amp;#34; &amp;gt; spiceproxy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Launch remote-viewer with spiceproxy file, in full screen mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#You can add USB passthrough options here if you&amp;#39;d like&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Not calling via exec, so the script continues after remote-viewer exits&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;remote-viewer -f spiceproxy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Kill lxsession&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#This is how LXDE is designed to logout, it&amp;#39;s not a hack lol&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;killall lxsession
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And of course, don&amp;rsquo;t forget to make it executable&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo chmod +x /usr/local/bin/thinclient
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;creating-virtual-session-users&#34;&gt;Creating Virtual Session Users&lt;/h2&gt;
&lt;p&gt;Since we are going to abuse the login system to select which thin client to launch, we need to create a new user on the local system for each VM we want to be directed to.&lt;/p&gt;
&lt;p&gt;To do this, we use &lt;code&gt;sudo adduser &amp;lt;username&amp;gt;&lt;/code&gt;
It will ask you for a password, and you must give the account a password. If you don&amp;rsquo;t want users to require a password, we will get there later. When it asks you for user information, fill in the &amp;lsquo;Full Name&amp;rsquo; field with the description of the VM. This field is what&amp;rsquo;s displayed in the login box, so you could set the full name to something like &lt;code&gt;Windows 10 w/ GPU&lt;/code&gt; so users know what VM they are logging into.&lt;/p&gt;
&lt;h3 id=&#34;passwordless-login-optional&#34;&gt;Passwordless Login (optional)&lt;/h3&gt;
&lt;p&gt;To allow users to login without specifying a password, we&amp;rsquo;re going to modify the PAM configuration to automatically succeed if the user is part of the nopasswdlogin group. To do this, we need to modify &lt;code&gt;/etc/pam.d/lightdm&lt;/code&gt; and add the following line right after &lt;code&gt;#%PAM-1.0&lt;/code&gt; at the top of the file:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;auth    sufficient  pam_succeed_if.so user ingroup nopasswdlogin
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And of course we need to actually create that group&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo groupadd -r nopasswdlogin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, for each no-password virtual session user, add them to the group nopasswdlogin&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo gpasswd -a &amp;lt;username&amp;gt; nopasswdlogin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configuring-lxde-autostart&#34;&gt;Configuring LXDE Autostart&lt;/h2&gt;
&lt;p&gt;This is the step where we break everything and then fix it. Make sure SSH works so you can correct anything broken.&lt;/p&gt;
&lt;p&gt;In short, when LXDE starts, it runs the autostart file for the system, followed by the autostart file for the user. The autostart file for the system includes things like a program which displays desktop icons (pcmanfm), and a program which displays the menu toolbar with useful buttons and widgets (lxpanel), and also the screensaver (xscreensaver). For virtual session users, we aren&amp;rsquo;t really a fan of any of these programs, since thin client shouldn&amp;rsquo;t have access to the underlying Linux system. However, we still need to retain a way to launch these programs when a local user logs in.&lt;/p&gt;
&lt;p&gt;In order to achieve this, we need to completely empty the system autostart file and put all of the usual system-wide LXDE utilities (pcmanfm, lxpanel, xscreensaver) into the user&amp;rsquo;s autostart file, but only for users which have local control. This means any new users you create will be trapped with a desktop background and no way to do anything until you create a user autostart file, so be careful with this process.&lt;/p&gt;
&lt;p&gt;To do this, log in as the user you want to retain local access (probably Pi?), backup the autostart file in case we need it later, and then copy it as the local users autostart file.&lt;/p&gt;
&lt;p&gt;Commands for Raspberry Pi:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup old system autostart file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mv /etc/xdg/lxsession/LXDE-pi/autostart /etc/xdg/lxsession/LXDE-pi/autostart.bak
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create new empty system autostart file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo touch /etc/xdg/lxsession/LXDE-pi/autostart
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create configuration directory and parents for the local user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p ~/.config/lxsession/LXDE-pi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy the original system autostart as our new user autostart&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp /etc/xdg/lxsession/LXDE-pi/autostart.bak ~/.config/lxsession/LXDE-pi/autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Commands for Debian:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup old system autostart file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mv /etc/xdg/lxsession/LXDE/autostart /etc/xdg/lxsession/LXDE/autostart.bak
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create new empty system autostart file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo touch /etc/xdg/lxsession/LXDE/autostart
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create configuration directory and parents for the local user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p ~/.config/lxsession/LXDE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy the original system autostart as our new user autostart&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp /etc/xdg/lxsession/LXDE/autostart.bak ~/.config/lxsession/LXDE/autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, one at a time, we are going to create autostart files for each thin client user. Since you need to run these commands as the user in question, it&amp;rsquo;s easiest if you login over ssh as the virtual session user. Repeat this step for each virtual session user you have.&lt;/p&gt;
&lt;p&gt;Commands for Raspberry Pi:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create folder where the autostart file goes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p ~/.config/lxsession/LXDE-pi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create autostart file and edit it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nano ~/.config/lxsession/LXDE-pi/autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Commands for Debian:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create folder where the autostart file goes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p ~/.config/lxsession/LXDE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create autostart file and edit it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nano ~/.config/lxsession/LXDE/autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Contents of the file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@/usr/bin/bash /usr/local/bin/thinclient &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace 100 with the VM ID you want this user to be launch. This file is not a shell script and is not executed as such, so we need to call bash (with the full path!), and pass it an argument for the script to run and arguments to further pass to the script.&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;This is a great solution if you don&amp;rsquo;t want the thin client to be tied to a specific VM. Ideally we&amp;rsquo;d be able to dynamically clone VMs as commercial VDI solutions do, but at this point, each virtual session user is tied to a specific VM ID in Proxmox.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Thin Client Megaproject</title>
      <link>https://www.apalrd.net/projects/2022/thin_client/</link>
      <pubDate>Wed, 09 Mar 2022 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2022/thin_client/</guid>
      <description>In this project, I explore thin client software, and set up a Raspberry Pi to act as a thin client. This is a multi-part project, follow along below for each sub-project.
Raspberry Pi SPICE Thin Client The first project in this series creates a Raspberry Pi Thin Client which is permanently bound to a specific VM in Proxmox, and boots directly into the thin client session. You would use this when you have a 1:1 relationship between clients and VMs, such as a computer lab.</description>
      <content>&lt;p&gt;In this project, I explore thin client software, and set up a Raspberry Pi to act as a thin client. This is a multi-part project, follow along below for each sub-project.&lt;/p&gt;
&lt;h2 id=&#34;raspberry-pi-spice-thin-client&#34;&gt;Raspberry Pi SPICE Thin Client&lt;/h2&gt;
&lt;p&gt;The first project in this series creates a Raspberry Pi Thin Client which is permanently bound to a specific VM in Proxmox, and boots directly into the thin client session. You would use this when you have a 1:1 relationship between clients and VMs, such as a computer lab. When the user sits down at the client, we&amp;rsquo;re trying hard to keep them from doing anything at all on the local system, and channeling their work over the network to be performed by the virtual machine.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/&#34;&gt;&lt;img alt=&#34;Using a Raspberry Pi as a Thin Client for Proxmox VMs&#34; src=&#34;https://www.apalrd.net/posts/2022/raspi_spice/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;adding-usb-redirection-to-the-thin-client&#34;&gt;Adding USB Redirection to the Thin Client&lt;/h2&gt;
&lt;p&gt;The next project in this series explores USB redirection, and passing USB devices such as flash drives from the client to the guest virtual machine. This wasn&amp;rsquo;t completely successful, as auto redirection didn&amp;rsquo;t work properly, but hopefully this gives you a bit of a guide on making this work as you expect.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_usb/&#34;&gt;&lt;img alt=&#34;USB Pass Through for the Raspberry Pi Thin Client&#34; src=&#34;https://www.apalrd.net/posts/2022/raspi_spice_usb/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;login-screen-for-multiple-thin-client-sessions&#34;&gt;Login Screen for multiple Thin Client sessions&lt;/h2&gt;
&lt;p&gt;In this project, I add a login screen, allowing users to log in to the local system, with certain users automatically launching thin client sessions instead of a desktop environment. This project is more useful when you want to give users access to one of many virtual environments, possibly with password protection for some. We still don&amp;rsquo;t dynamically allocate VMs or anything like that, but we&amp;rsquo;re working closer to the ideal scenario of a &amp;lsquo;virtual computer lab&amp;rsquo; where you can choose the type of machine you need when you log in.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/&#34;&gt;&lt;img alt=&#34;Choose a Thin Client Session Graphically&#34; src=&#34;https://www.apalrd.net/posts/2022/raspi_spice_login/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;pve-vdiclient---a-python-graphical-vdi-client-for-proxmox&#34;&gt;PVE-VDIClient - A Python Graphical VDI Client for Proxmox&lt;/h2&gt;
&lt;p&gt;For the previous episode (see above), I setup a multi-user thin client where each user account was connected to a specific virtual machine. This is great, but if you have a lot of thin clients you might not want to create a ton of VMs and might instead want each user in the system to have one or more VMs. Well, Josh Patten has written &lt;a href=&#34;https://github.com/joshpatten/PVE-VDIClient&#34;&gt;a Python-based GUI to select thin clients which you have access to&lt;/a&gt;, and in this episode I turn his project into a Raspberry Pi (or Debian) appliance. This is even closer to my goal of a virtual computer lab, even if the administrator has to individually allocate VMs for users.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice_vdi/&#34;&gt;&lt;img alt=&#34;PVE-VDIClient - A Python Graphical VDI Client for Proxmox&#34; src=&#34;https://www.apalrd.net/posts/2022/raspi_spice_vdi/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;setting-up-a-netboot-pxe-server-for-alpine-linux&#34;&gt;Setting up a Netboot (PXE) Server for Alpine Linux&lt;/h2&gt;
&lt;p&gt;While not strictly a thin client, this video is important since I&amp;rsquo;m going to use this netboot server going forward for my netbooted thin client projects. So, stay tuned for the second part of this video where I netboot PVE-VDIClient!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/&#34;&gt;&lt;img alt=&#34;Setting up a Netboot (PXE) Server for Alpine Linux&#34; src=&#34;https://www.apalrd.net/posts/2022/alpine_pxe/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>USB Pass Through for the Raspberry Pi Thin Client</title>
      <link>https://www.apalrd.net/posts/2022/raspi_spice_usb/</link>
      <pubDate>Thu, 03 Mar 2022 21:27:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/raspi_spice_usb/</guid>
      <description>As promised in my previous blog post on the topic, the SPICE protocol is capable of USB redirection. I didn&amp;rsquo;t dive into it for that post, but now the future is here and I&amp;rsquo;ve added USB redirection to my Raspberry Pi thin client. I&amp;rsquo;ve tested it with USB flash drives, webcams, and pretty much all of the USB devices I could find. And I&amp;rsquo;m here to tell you how it all works.</description>
      <content>&lt;p&gt;As promised in &lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/&#34;&gt;my previous blog post on the topic&lt;/a&gt;, the SPICE protocol is capable of USB redirection. I didn&amp;rsquo;t dive into it for that post, but now the future is here and I&amp;rsquo;ve added USB redirection to my Raspberry Pi thin client. I&amp;rsquo;ve tested it with USB flash drives, webcams, and pretty much all of the USB devices I could find. And I&amp;rsquo;m here to tell you how it all works.&lt;/p&gt;
&lt;h2 id=&#34;the-video&#34;&gt;The Video&lt;/h2&gt;
&lt;p&gt;This blog post has a corresponding video. Click on the thumbnail below to watch it. For the commands and scripts used, continue down below.
&lt;a href=&#34;https://youtu.be/VfGnAGT8eRI&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/raspi_spice_usb/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;adding-usb-ports-in-proxmox&#34;&gt;Adding USB Ports in Proxmox&lt;/h2&gt;
&lt;p&gt;This one is pretty simple. In the VM&amp;rsquo;s Hardware panel, you just add USB ports, and select &amp;lsquo;SPICE&amp;rsquo;. You can add as many as you want. Each USB port you add can be used to pass through one USB device from the client, so add plenty of them. You need to restart the VM when you change the number of USB ports, but you can remap the USB ports you&amp;rsquo;ve already created while the machine is running (including changing them from SPICE to pass-through of host devices and back).&lt;/p&gt;
&lt;p&gt;You can choose either USB2 or USB3 for this. In Proxmox, the underlying emulator (qemu) is emulating a USB host chipset and then attaching all of the USB ports to it, so choosing USB2 or USB3 changes the model fo the emulated chipset. It&amp;rsquo;s been recommended that the USB2 chipset is more reliable than USB3, and in our use case, it&amp;rsquo;s unlikely we will ever be able to exceed USB2 bandwidth in a thin client setup anyway (or that we&amp;rsquo;d want our users to tie up 1G+ of network bandwidth).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Proxmox USB configuration&#34; src=&#34;https://www.apalrd.net/posts/2022/raspi_spice_usb/proxmox_usb.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;configuring-remote-viewer&#34;&gt;Configuring Remote Viewer&lt;/h2&gt;
&lt;p&gt;At this point, I edited the &lt;code&gt;thinclient.sh&lt;/code&gt; file I created in the previous topic to switch from the locked down kiosk mode to simple full screen mode. you do this by changing &lt;code&gt;-k --kiosk-quit on-disconnect&lt;/code&gt; to &lt;code&gt;-f&lt;/code&gt; in the line which calls remote-viewer. This lets you use the UI of remote viewer by moving your mouse to the top of the screen.&lt;/p&gt;
&lt;p&gt;Once you restart remote viewer so you have access to the UI (either reboot, or run &lt;code&gt;killall xinit&lt;/code&gt; over SSH and then &lt;code&gt;startx --&lt;/code&gt; on the local terminal), you can pick USB devices to redirect from the USB button in the menu at the top. If you don&amp;rsquo;t have a USB button on the menu, then remote-viewer thinks there are no SPICE USB ports configured on the server, so check your Proxmox config and make sure you reboot if necessary to add more ports.&lt;/p&gt;
&lt;p&gt;Of course, when passing through hardware, make sure you don&amp;rsquo;t pass through something critical to the system. Don&amp;rsquo;t pass through your actual keyboard and mouse, since you&amp;rsquo;ll lose the ability to even close the USB redireciton window.&lt;/p&gt;
&lt;h2 id=&#34;raspberry-pi-internal-usb-peripherals&#34;&gt;Raspberry Pi Internal USB peripherals&lt;/h2&gt;
&lt;p&gt;On many models of the Raspberry Pi, devices are connected to the internal USB bus via a USB hub chip. On the Model A, the internal USB root is directly connected to the single USB port. But, on all Model B variants except the Pi 4, the single USB 2 root is connected to a USB hub and USB Ethernet chip. So, if we pass through absolutely everything, then the Ethernet chip will get passed through, and the Pi will lose ethernet. Not a great experience. So, we need to figure out what the USB vendor/product IDs of the Ethernet chip are so we can not pass them through automatically. To do this, use &lt;code&gt;lsusb&lt;/code&gt; which should show a list of connected USB devices. In my case, I get something like this for a Pi 1 with nothing connected:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. SMC9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this case, the Fast Ethernet Adapter at 0424:ec00 is the device we are concerned about. Make sure you do this on the same model of Pi, since each Pi model uses slightly different hardware, especially the 3, 3+, and 4.&lt;/p&gt;
&lt;h2 id=&#34;spice-client-usb-redirection-rules&#34;&gt;SPICE Client USB Redirection Rules&lt;/h2&gt;
&lt;p&gt;If you want to automatically connect some devices when the thin client starts, or automtaically while it runs, there are command line options for this. However, I was unable to get auto redirect to work in my setup once the thin client was already running - auto connect on start worked fine, and the USB redirection menu also worked fine, but plugging in a device and automatically passing it through didn&amp;rsquo;t happen.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.spice-space.org/usbredir.html&#34;&gt;The manual page is here for reference&lt;/a&gt;. It&amp;rsquo;s essentially all of the information available on the topic.&lt;/p&gt;
&lt;p&gt;The key to this is that the rules (on-connect and auto-redirect) are written as a list which follows the following format:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;class&amp;gt;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;vendor&amp;gt;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;product&amp;gt;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;allow&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You then chain together rules, which are processed in order, like this&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;rule1|rule2|rule3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The example given is to block USB human interface devices and pass everything else, which is this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;0x03,-1,-1,-1,0|-1,-1,-1,-1,1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you&amp;rsquo;re crafting rules, a handy reference is the &lt;a href=&#34;https://www.usb.org/defined-class-codes&#34;&gt;USB device class list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In my case, I wanto automatically redirect everything but USB HID devices and the USB Fast Ethernet controller on my Pi, so I wrote this rule:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;0x03,-1,-1,-1,0|-1,0x0424,0xec00,-1,0|-1,-1,-1,-1,1
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;auto-redirect-script-changes&#34;&gt;Auto Redirect Script Changes&lt;/h2&gt;
&lt;p&gt;I added a few new lines to &lt;code&gt;thinclient.sh&lt;/code&gt; from the previous article. Here&amp;rsquo;s the new last few lines of the file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Define USB redirection rule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;USBREDIR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0x03,-1,-1,-1,0|-1,0x0424,0xec00,-1,0|-1,-1,-1,-1,1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Call remote-viewer in fullscreen with redirection on connect and auto redirection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exec remote-viewer -f --spice-usbredir-auto-redirect-filter&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$USBREDIR&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; --spice-usbredir-redirect-on-connect&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$USBREDIR&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; spiceproxy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this script, USB devices plugged in to the Pi will redirect when the Pi starts, although I wasn&amp;rsquo;t able to get them to redirect automatically in this environment.&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;This is a very useful feature that really sets SPICE apart from a lot of other open source or free VDI protocols. Some VNC servers/clients implement USB on their own (outside of the standard), but as far as I know, the Proxmox VNC server does not support these. Windows Remote Desktop Protocol (RDP) supports both high level redirection (of devices like USB drives and audio with the driver running on the client) as well as low level USB redirection, but it&amp;rsquo;s disabled by default and requires editing the group policies to allow it. RDP also doesn&amp;rsquo;t work natively with Linux guests, where SPICE works with all guests (even as far back as Windows XP).&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>My First 100 Subscribers!</title>
      <link>https://www.apalrd.net/posts/2022/youtube_100/</link>
      <pubDate>Tue, 01 Mar 2022 15:03:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/youtube_100/</guid>
      <description>As of today, my Youtube Channel has reached 100 subscribers! It&amp;rsquo;s really exciting to me, slowly starting to build a brand and produce content that I enjoy. I&amp;rsquo;ve enjoyed documenting my hobbies and projects on this website for almost a year now, and making videos is a fun way for me to expand that.
Thank you to everyone who&amp;rsquo;s enjoyed and commented on my content so far, it&amp;rsquo;s great to see that others are enjoying it too.</description>
      <content>&lt;p&gt;As of today, my Youtube Channel has reached 100 subscribers! It&amp;rsquo;s really exciting to me, slowly starting to build a brand and produce content that I enjoy. I&amp;rsquo;ve enjoyed documenting my hobbies and projects on this website for almost a year now, and making videos is a fun way for me to expand that.&lt;/p&gt;
&lt;p&gt;Thank you to everyone who&amp;rsquo;s enjoyed and commented on my content so far, it&amp;rsquo;s great to see that others are enjoying it too.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t have any analytics on this site at all, and I hope you appreciate the desire to respect your data privacy, but I do know how much bandwidth I use per month, and last month, I passed more than 1GB for the site. I don&amp;rsquo;t get any decimals, but based on how small the site is on disk (the entire site, including static content, is currently 54MB), crossing above 1GB of traffic means &lt;em&gt;someone&lt;/em&gt; must be reading it.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Buying a used Thin Client for &#39;Fun&#39;</title>
      <link>https://www.apalrd.net/posts/2022/wyse_basic/</link>
      <pubDate>Tue, 01 Mar 2022 13:00:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/wyse_basic/</guid>
      <description>I recently was browsing eBay for used computer parts (as one does) and I found how cheap some used thin clients are. These are mini desktops with minimal IO which are designed to act as a modern terminal for modern VDI setups, something like Citrix or Microsoft Remote Desktop based enterprise systems. The thin client itself just has to deal with the local displays, keyboard, mouse, and local USB ports, the actual computation is done on a server somewhere else.</description>
      <content>&lt;p&gt;I recently was browsing eBay for used computer parts (as one does) and I found how cheap some used thin clients are. These are mini desktops with minimal IO which are designed to act as a modern terminal for modern VDI setups, something like Citrix or Microsoft Remote Desktop based enterprise systems. The thin client itself just has to deal with the local displays, keyboard, mouse, and local USB ports, the actual computation is done on a server somewhere else. This is all well and good, but a lot of these thin clients run Linux themselves, and we can repurpose them to run our own Linux environment for whatever we want. They&amp;rsquo;re also dirt cheap, presumably since the specs are pretty terrible if you want to use it as an actual desktop, but thankfully that&amp;rsquo;s not what I want to run at all&lt;/p&gt;
&lt;h2 id=&#34;the-specs&#34;&gt;The Specs&lt;/h2&gt;
&lt;p&gt;The model I ended up with is A Dell Wyse 5060, which features an AMD Puma based quad core APU, 4GB of RAM, and a 16GB SATA SSD. It also includes a power supply, a somewhat rare find for it&amp;rsquo;s $35 shipped price. It&amp;rsquo;s very important to look at the specs of what you&amp;rsquo;re getting, since I found a ton of them with 2G of RAM and no SSD or an even smaller SSD. Expect none of the parts to be upgradeable, and 2G is a bit low these days. Many also have dual-core Atom CPUs, which use less power than the AMD Puma, but the Puma is functional as a desktop CPU in Linux.&lt;/p&gt;
&lt;p&gt;Basically, this is a step up from a Raspberry Pi, but it costs less and you can buy it today. Consider it as an alterative for Raspberry Pi projects that don&amp;rsquo;t need IO or can benefit from gigabit, dual DisplayPort, or USB 3.&lt;/p&gt;
&lt;h2 id=&#34;how-to-install-your-own-software&#34;&gt;How to Install your own Software&lt;/h2&gt;
&lt;p&gt;By default, the BIOS is configured for legacy (non-UEFI) boot, and USB boot is disabled, so we need to fix both of those things. To enter the BIOS, press the DEL key while booting, and enter the BIOS password &lt;code&gt;Fireport&lt;/code&gt; (capital F). From there, go to the Advanced tab and enable boot from USB and also set boot mode to Both. Then, go to the boot order tab and make the USB HDD higher than SATA 0 (by moving SATA down or USB up, using the +- keys). Save and exit. This should allow you to boot into a bootable USB drive and install whatever you want&lt;/p&gt;
&lt;h2 id=&#34;teardown-video&#34;&gt;Teardown Video&lt;/h2&gt;
&lt;p&gt;I made a video showing the hardware inside my thin client, if you&amp;rsquo;re interested in seeing a teardown, or watching the BIOS configuration. Click the thumbnail below to watch it.
&lt;a href=&#34;https://youtu.be/UofIjXUpHKQ&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/wyse_basic/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;my-plans&#34;&gt;My Plans&lt;/h2&gt;
&lt;p&gt;I bought this to use in my new studio space as a screen recorder. Basically, I&amp;rsquo;d have a USB HDMI capture device connected, so I can record directly to a network drive. I was able to set this up really easily by installing Xubuntu and OBS Studio, and the Puma CPU&amp;rsquo;s integrated graphics enabled transcoding seemed to work well enough to handle 1080p30 without a major sweat from the thin client. The CPU also has enough power to handle x264 software encoding, but it uses almost all of the CPU to do so.&lt;/p&gt;
&lt;h2 id=&#34;hardware-info-for-the-curious&#34;&gt;Hardware Info for the curious&lt;/h2&gt;
&lt;p&gt;All of this was taken via an Xubuntu 20.04 Live CD, so your kernel may be configured slightly differently&lt;/p&gt;
&lt;h3 id=&#34;lscpu&#34;&gt;lscpu&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Architecture:                    x86_64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
Address sizes:                   40 bits physical, 48 bits virtual
CPU(s):                          4
On-line CPU(s) list:             0-3
Thread(s) per core:              1
Core(s) per socket:              4
Socket(s):                       1
NUMA node(s):                    1
Vendor ID:                       AuthenticAMD
CPU family:                      22
Model:                           48
Model name:                      AMD GX-424CC SOC with Radeon(TM) R5E Graphics
Stepping:                        1
CPU MHz:                         1000.000
CPU max MHz:                     2400.0000
CPU min MHz:                     1000.0000
BogoMIPS:                        4791.14
Virtualization:                  AMD-V
L1d cache:                       128 KiB
L1i cache:                       128 KiB
L2 cache:                        2 MiB
NUMA node0 CPU(s):               0-3
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Not affected
Vulnerability Meltdown:          Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled v
                                 ia prctl and seccomp
Vulnerability Spectre v1:        Mitigation; usercopy/swapgs barriers and __user
                                  pointer sanitization
Vulnerability Spectre v2:        Mitigation; Full AMD retpoline, STIBP disabled,
                                  RSB filling
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected
Flags:                           fpu vme de pse tsc msr pae mce cx8 apic sep mtr
                                 r pge mca cmov pat pse36 clflush mmx fxsr sse s
                                 se2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtsc
                                 p lm constant_tsc rep_good acc_power nopl nonst
                                 op_tsc cpuid extd_apicid aperfmperf pni pclmulq
                                 dq monitor ssse3 cx16 sse4_1 sse4_2 movbe popcn
                                 t aes xsave avx f16c lahf_lm cmp_legacy svm ext
                                 apic cr8_legacy abm sse4a misalignsse 3dnowpref
                                 etch osvw ibs skinit wdt topoext perfctr_nb bpe
                                 xt ptsc perfctr_llc hw_pstate ssbd vmmcall bmi1
                                  xsaveopt arat npt lbrv svm_lock nrip_save tsc_
                                 scale flushbyasid decodeassists pausefilter pft
                                 hreshold overflow_recov
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Of note, it does support AMD-V if you want to do virtualization, and AES-NI if you want to do anything involving crypto offload (VPN, HTTPS, &amp;hellip;)&lt;/p&gt;
&lt;h3 id=&#34;lspci&#34;&gt;lspci&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;00:00.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 16h (Models 30h-3fh) Processor Root Complex
00:01.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Mullins [Radeon R4/R5 Graphics] (rev 01)
00:01.1 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] Kabini HDMI/DP Audio
00:02.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 16h (Models 30h-3fh) Host Bridge
00:02.1 PCI bridge: Advanced Micro Devices, Inc. [AMD] Family 16h Processor Functions 5:1
00:02.2 PCI bridge: Advanced Micro Devices, Inc. [AMD] Family 16h Processor Functions 5:1
00:02.3 PCI bridge: Advanced Micro Devices, Inc. [AMD] Family 16h Processor Functions 5:1
00:02.4 PCI bridge: Advanced Micro Devices, Inc. [AMD] Family 16h Processor Functions 5:1
00:02.5 PCI bridge: Advanced Micro Devices, Inc. [AMD] Family 16h Processor Functions 5:1
00:08.0 Encryption controller: Advanced Micro Devices, Inc. [AMD] Kabini/Mullins PSP-Platform Security Processor
00:10.0 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB XHCI Controller (rev 11)
00:11.0 SATA controller: Advanced Micro Devices, Inc. [AMD] FCH SATA Controller [AHCI mode] (rev 39)
00:12.0 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB EHCI Controller (rev 39)
00:13.0 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB EHCI Controller (rev 39)
00:14.0 SMBus: Advanced Micro Devices, Inc. [AMD] FCH SMBus Controller (rev 42)
00:14.2 Audio device: Advanced Micro Devices, Inc. [AMD] FCH Azalia Controller (rev 02)
00:14.3 ISA bridge: Advanced Micro Devices, Inc. [AMD] FCH LPC Bridge (rev 11)
00:18.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 16h (Models 30h-3fh) Processor Function 0
00:18.1 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 16h (Models 30h-3fh) Processor Function 1
00:18.2 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 16h (Models 30h-3fh) Processor Function 2
00:18.3 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 16h (Models 30h-3fh) Processor Function 3
00:18.4 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 16h (Models 30h-3fh) Processor Function 4
00:18.5 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 16h (Models 30h-3fh) Processor Function 5
04:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 15)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see, it uses a Realtek Ethernet Controller&lt;/p&gt;
&lt;h3 id=&#34;vainfo&#34;&gt;vainfo&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;error: XDG_RUNTIME_DIR not set in the environment.
libva info: VA-API version 1.7.0
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/radeonsi_drv_video.so
libva info: Found init function __vaDriverInit_1_7
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.7 (libva 2.6.0)
vainfo: Driver version: Mesa Gallium driver 21.0.3 for AMD KABINI (DRM 2.50.0, 5.11.0-27-generic, LLVM 12.0.0)
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            :	VAEntrypointVLD
      VAProfileMPEG2Main              :	VAEntrypointVLD
      VAProfileVC1Simple              :	VAEntrypointVLD
      VAProfileVC1Main                :	VAEntrypointVLD
      VAProfileVC1Advanced            :	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointEncSlice
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointEncSlice
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointEncSlice
      VAProfileNone                   :	VAEntrypointVideoProc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Hardware encode/decode is certainly usable for H264&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Backup System Build</title>
      <link>https://www.apalrd.net/projects/2022/backup_sw/</link>
      <pubDate>Sat, 26 Feb 2022 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2022/backup_sw/</guid>
      <description>As I outlined in my first blog post on the topic, I want to build a new backup server, and I want to explore the different options I have. This project included a lot of testing, and will eventually culminate in actually building and setting up a proper backup system. It&amp;rsquo;s definitely an important and often overlooked part of a homelab, or even small business networks. Ideally, I can also get a functional offsite backup working, but that might be a future project.</description>
      <content>&lt;p&gt;As I outlined in my &lt;a href=&#34;https://www.apalrd.net/posts/2021/backup_intro/&#34;&gt;first blog post on the topic&lt;/a&gt;, I want to build a new backup server, and I want to explore the different options I have. This project included a lot of testing, and will eventually culminate in actually building and setting up a proper backup system. It&amp;rsquo;s definitely an important and often overlooked part of a homelab, or even small business networks. Ideally, I can also get a functional offsite backup working, but that might be a future project.&lt;/p&gt;
&lt;h1 id=&#34;small-scale-tests&#34;&gt;Small Scale Tests&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;d like to back up bulk data stored in TrueNAS, as well as virtual machines and their associated storage stored in Proxmox. Ideally, the backup server will contain mostly lower cost spinning rust, store the complete contents of both the TrueNAS and Proxmox servers, and manage the long term archival and offsite backup. I have tried the software below, each has its own longer blog post on the topic and a short summary is listed here (More may be added in the future as I test more):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2022/backup_sw/#truenas&#34;&gt;TrueNAS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2022/backup_sw/#proxmox-backup-server-pbs&#34;&gt;Proxmox Backup Server (PBS)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have a few decisions I can make on the primary server side which affect the backup options in the backup server, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Proxmox could use shared storage on a TrueNAS system, so backups are primarily done by TrueNAS instead of Proxmox. I could also use ZFS over iSCSI for this instead of NFS or CIFS so the images are zvols in TrueNAS instead of files on a dataset.&lt;/li&gt;
&lt;li&gt;Proxmox in an cluster requires all of the backup and storage to be defined entirely in Proxmox, there is no way to reliably pull ZFS snapshots from Proxmox servers to TrueNAS in a cluster since the VM could potentially migrate from host to host.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;truenas&#34;&gt;TrueNAS&lt;/h2&gt;
&lt;p&gt;TrueNAS is a great solution for network storage, but is it also a good backup server?&lt;/p&gt;
&lt;h3 id=&#34;data-transfer-to-backup-server&#34;&gt;Data Transfer to Backup Server&lt;/h3&gt;
&lt;p&gt;For TrueNAS -&amp;gt; TrueNAS, the feature is built in and works great. ZFS datasets and their snapshots are easily replicated from one system to another. All is golden.&lt;/p&gt;
&lt;p&gt;For Proxmox -&amp;gt; TrueNAS, there are two options and neither are perfect. Proxmox supports a snapshot export, which makes a clone of the VM disk and compresses it, along with an archive of the VM configuration. This can optionally be pushed to remote storage (Even if the VM disk is on local storage). The downside to this is the TrueNAS backup server will end up with a dataset full of files, each of which are compressed VM disks. I can either deduplicate this dataset and hope it can recover some of this massive space penalty, leave the VM disks uncompressed and hope deduplication works better on uncompressed data, or waste a ton of space with the compressed images as files. The other option is the path I went down in my &lt;a href=&#34;https://www.apalrd.net/posts/2022/truenas_pve/&#34;&gt;&amp;ldquo;Can TrueNAS backup a Proxmox host using ZFS replication?&amp;rdquo;&lt;/a&gt; blog post - create native ZFS snapshots of the zvol backing the VM, and pull them from PVE using TrueNAS&amp;rsquo;s builtin replication function. This works great for the VM disks, we get a history of snapshots natively in ZFS without the overhead of storing image files cloned from the zvol on a dataset, and incremental transfer of the backups. But, we don&amp;rsquo;t get the configuration file of the VM, and would either need to separately back them up or recreate them to restore.&lt;/p&gt;
&lt;h3 id=&#34;offsite-backup-options&#34;&gt;Offsite Backup Options&lt;/h3&gt;
&lt;p&gt;The options you have here are to replicate to another offsite ZFS system, or to a supported cloud storage provider. Most people would probably use an S3 compatible provider or Backblaze B2, neither of which are particularly cheap if you are storing a lot of data, but the software support in TrueNAS is good if you are using a compatible service. While I didn&amp;rsquo;t make a blog post about it, I did make a &lt;a href=&#34;https://youtu.be/jwHCvYFSVbM&#34;&gt;quick video&lt;/a&gt; about using Linode Object Storage with TrueNAS, although I only pay for this for my most critical data.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;In summary, TrueNAS is an excellent backup server when the primary server is also using ZFS and send/recv can be used to transfer snapshots. It&amp;rsquo;s less excellent when the primary server isn&amp;rsquo;t as cooperative or doesn&amp;rsquo;t run ZFS at all. If you are using shared storage on TrueNAS to host your PVE VMs anyway, then you can manage backups entirely in TrueNAS aside from the Proxmox configuration. If you are using local ZFS storage, then the method I tried in my blog post will work. If you are using anything else, you&amp;rsquo;re stuck with Proxmox compressing disk images and dumping them on a NFS/CIFS share on the backup server.&lt;/p&gt;
&lt;h2 id=&#34;proxmox-backup-server-pbs&#34;&gt;Proxmox Backup Server (PBS)&lt;/h2&gt;
&lt;p&gt;Proxmox Backup Server is a new offering from Proxmox, and designed for backup and archival storage of Proxmox VMs, CTs, and file storage (&amp;lsquo;hosts&amp;rsquo;). It internally stores the data using its own archival / chunk format with deduplication, and client-side incremental sending, even in cases where the client&amp;rsquo;s underlying filesystem doesn&amp;rsquo;t support snapshots. It also has support for tape archival and tape loader management.&lt;/p&gt;
&lt;h3 id=&#34;data-transfer-to-backup-server-1&#34;&gt;Data Transfer to Backup Server&lt;/h3&gt;
&lt;p&gt;For PVE -&amp;gt; PBS, the process is entirely automated in PVE. Proxmox supports scheduled backups to PBS, incremental backups, deduplication on the PBS side, and also live restores! The live restore function starts the VM as soon as it starts copying data, and transfers blocks from the server as the VM requests them. This means the VM is up and running immediately, even if it&amp;rsquo;s running slowly until all of the blocks have been read.&lt;/p&gt;
&lt;p&gt;For TrueNAS -&amp;gt; PBS, the process requires us to run TrueNAS SCALE (Debian based) and run the Proxmox Backup Client through the command line via a cron job. I went through an exercise to script this backup in my blog post &lt;a href=&#34;https://www.apalrd.net/posts/2022/truenas_pbs/&#34;&gt;&amp;ldquo;Can TrueNAS backup to Proxmox Backup Server?&amp;rdquo;&lt;/a&gt;, where I created a shell script to backup ZFS datasets in TrueNAS to the Proxmox Backup Server. Since the backup isn&amp;rsquo;t done with zfs send/recv, the ZFS attributes and dataset properties aren&amp;rsquo;t copied as they are in TrueNAS -&amp;gt; TrueNAS. This means we are backing up the files, their contents, and their UNIX permissions, but not the associated ZFS dataset attributes (quotas, special properties, and dataset layout itself). We can separately backup TrueNAS&amp;rsquo;s configuration database (it&amp;rsquo;s in &lt;code&gt;/data&lt;/code&gt; on the boot pool and copied to the system dataset nightly) as well as any ssh keys we might need to rebuilt the server, but this is something that a TrueNAS -&amp;gt; TrueNAS backup wouldn&amp;rsquo;t include either.&lt;/p&gt;
&lt;h3 id=&#34;offsite-backup-options-1&#34;&gt;Offsite Backup Options&lt;/h3&gt;
&lt;p&gt;PBS offers two options to replicate backups - replication to another PBS server (a &amp;lsquo;remote&amp;rsquo;), and tape backups. The tape backup management can deal with autoloaders, scheduled backups to tape, and multiple sets of tapes. It seems fairly fully featured, although I haven&amp;rsquo;t personally tried using it.&lt;/p&gt;
&lt;h3 id=&#34;summary-1&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;PBS is the first choice for backing up a Proxmox cluster. It&amp;rsquo;s also capable of backing up Linux filesystems, but the client currently only supports x64 Linux and is only precompiled for Debian and Ubuntu. This is fine for use with TrueNAS SCALE (which is Debian based), but the backup client currently doesn&amp;rsquo;t compile for Raspberry Pi. Work is in progress to expand the client support to the Pi and it looks like a patch set is in place to build on AArch64 (ARMv8), and several other distros are beginning to compile it on for x64 for their own package repositories. The restore features with Proxmox are excellent (including live-restoring a VM!), and the Linux client can mount a backup as a filesystem to allow file recovery in a simple way. The tape archival support seems full-featured and easy to understand, especially compared to the other open source tape solutions I&amp;rsquo;ve read the documentation for.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Can TrueNAS backup a Proxmox host using ZFS replication?</title>
      <link>https://www.apalrd.net/posts/2022/truenas_pve/</link>
      <pubDate>Fri, 25 Feb 2022 17:20:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/truenas_pve/</guid>
      <description>As part of my series exploring backup options, I&amp;rsquo;m exploring the options for pulling a backup of a Proxmox Virtual Environment (PVE) host to TrueNAS SCALE server. In this case, PVE host has local ZFS storage, and the TrueNAS system is acting as the backup server. Ideally, PVE would snapshot in ZFS and we could sync those snapshots with a TrueNAS Data Replication task, but PVE doesn&amp;rsquo;t use the ZFS snapshot features by default.</description>
      <content>&lt;p&gt;As part of my series exploring backup options, I&amp;rsquo;m exploring the options for pulling a backup of a Proxmox Virtual Environment (PVE) host to TrueNAS SCALE server. In this case, PVE host has local ZFS storage, and the TrueNAS system is acting as the backup server. Ideally, PVE would snapshot in ZFS and we could sync those snapshots with a TrueNAS Data Replication task, but PVE doesn&amp;rsquo;t use the ZFS snapshot features by default. This complicates our setup somewhat. This test is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/backup_sw/&#34;&gt;Backup Software Project&lt;/a&gt;, click there for other related projects.&lt;/p&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a video for this article! Click the thumbnail below to watch it.
&lt;a href=&#34;https://youtu.be/dn-Ty2zxMc4&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/truenas_pve/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;proxmox-internal-backup-scheduler&#34;&gt;Proxmox Internal Backup Scheduler&lt;/h2&gt;
&lt;p&gt;Proxmox&amp;rsquo;s internal backup system relies on a qemu feature to export the VM disk coherently. When using the snapshot feature in the backup command, it will send a command to the qemu guest agent to tell the guest to synchronize disk activity (so ideally there aren&amp;rsquo;t in-progress writes on the VM disk), snapshot the ZFS zvol, then dump the contents of the snapshot to a compressed img file and delete the snapshot. This means that, even though the image is stored on a zvol in ZFS, we end up with a compressed img file in a dataset in ZFS, instead of a snapshot of the zvol in ZFS. Not ideal. Proxmox DOES create ZFS snapshots for the &amp;lsquo;snapshot&amp;rsquo; feature (not the &amp;lsquo;backup&amp;rsquo; method &amp;lsquo;snapshot&amp;rsquo;), but there doesn&amp;rsquo;t seem to be a way to schedule snapshots like you can schedule backups. But, I&amp;rsquo;d like ZFS snapshots to be created so TrueNAS can pull from them with zfs send/recv.&lt;/p&gt;
&lt;h2 id=&#34;using-zfs-snapshots-on-proxmox&#34;&gt;Using ZFS Snapshots on Proxmox&lt;/h2&gt;
&lt;p&gt;While the GUI won&amp;rsquo;t help us, there&amp;rsquo;s no reason we can&amp;rsquo;t execute the same commands to sync the VM and then take a zfs snapshot. In fact, &lt;a href=&#34;https://github.com/apprell/proxmox-autosnap&#34;&gt;someone has already written a python script to do this&lt;/a&gt;. So, I&amp;rsquo;m going to use his script. I first tested the script standalone and confirmed that it does in fact snapshot the zvol, then added the hourly/daily/monthly cronjobs and ensured those worked as well. Thank you to &lt;a href=&#34;https://github.com/apprell/&#34;&gt;apprell&lt;/a&gt; for this.&lt;/p&gt;
&lt;h2 id=&#34;pulling-the-snapshots-from-truenas&#34;&gt;Pulling the snapshots from TrueNAS&lt;/h2&gt;
&lt;p&gt;Now that we have PVE creating ZFS snapshots instead of files in the backup storage location, we can tell TrueNAS to pull them over SSH (using zfs send/recv). TrueNAS automates this almost entirely, which is super handy.&lt;/p&gt;
&lt;p&gt;The first step is to create an SSH key pair which can be used to log in to the PVE system from the TrueNAS system. To do this, on TrueNAS, go in to &lt;code&gt;Credentials -&amp;gt; Backup Credentials -&amp;gt; SSH Connections&lt;/code&gt; and click &lt;code&gt;Add&lt;/code&gt;. Set the connection to &lt;code&gt;Manual&lt;/code&gt; since this isn&amp;rsquo;t a remote TrueNAS system, add the host, port, username, and generate a new private key. Then, you can discover the remote host key. Save. Now, go to &lt;code&gt;SSH Keypairs&lt;/code&gt; on the same screen, open the new keypair you generated, and copy the public key. I changed the name (truenas.local) for the IP address of the system, then copied the key.&lt;/p&gt;
&lt;p&gt;We need to enter this key in PVE. Open the shell in the PVE web gui and run &lt;code&gt;nano /etc/pve/priv/authorized_keys&lt;/code&gt;. Add the new key on a new line to this file and save it. It should look like the lines before it.&lt;/p&gt;
&lt;p&gt;Now, we can add the replication task in TrueNAS, to pull the snapshots which are automatically being taken on PVE and copy them to the ZFS system on TrueNAS. To create this, go to &lt;code&gt;Data Protection -&amp;gt; Replication Tasks -&amp;gt; Add&lt;/code&gt; in TrueNAS, and follow the wizard. Here are the important fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;lsquo;Load Previous Replication Task&amp;rsquo; none&lt;/li&gt;
&lt;li&gt;Source Location = On A Different System&lt;/li&gt;
&lt;li&gt;SSH Connection = select the one you created earlier&lt;/li&gt;
&lt;li&gt;Source = rpool/data (the zfs parent where PVE creates all of the VMs / CTs)&lt;/li&gt;
&lt;li&gt;Check &amp;lsquo;Recursive&amp;rsquo; under Source to copy all of the VMs / CTs&lt;/li&gt;
&lt;li&gt;Destination = a new dataset under an existing dataset on your existing pool - type the name in, it will create a new dataset with the correct settings for you&lt;/li&gt;
&lt;li&gt;Naming Convention = Snapshot Name Regular Expression&lt;/li&gt;
&lt;li&gt;Regular Expression = .* (meaning all)&lt;/li&gt;
&lt;li&gt;Task Name = something to help you remember&lt;/li&gt;
&lt;li&gt;Setup the schedule of your choosing (at least as fast as snapshots are being taken, if no new snapshots exist it will copy nothing)&lt;/li&gt;
&lt;li&gt;Deletion = Same as Source (the destination will delete a snapshot that no longer exists on the source)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One quirk I found is that I tried to replicate the rpool/data dataset in PVE (the parent dataset), after I had created snapshots of the VMs using the autosnap script above. However, TrueNAS refused to replicate recursively from rpool/data since it found no snapshots of rpool/data itself. To fix this, I created a single snapshot of rpool/data (&lt;code&gt;zfs snapshot rpool/data@truenas&lt;/code&gt;) and found that TrueNAS was able to successfully copy the snapshots for the child datasets/zvols, even when they were newer than my manually created data snapshot. Since ZFS snapshots only affect the snapshotted item (not children), this snapshot of an empty dataset shouldn&amp;rsquo;t contain any actual data and thus I can leave it around forever just to make TrueNAS happy.&lt;/p&gt;
&lt;h2 id=&#34;restore-process&#34;&gt;Restore Process&lt;/h2&gt;
&lt;p&gt;This backup method is functional, but incomplete. It only backs up the VM / CT disks, not the PVE configuration and qemu config file. So, the minimum process to restore a VM to a brand new Proxmox system is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new VM and configure it, then delete the hard drive. The configuration is lost with the ZFS backup, so you&amp;rsquo;ll need to recreate the entire VM configuration. Alternatively, you could restore an older Proxmox vzdump backup and then replace the hard drive with a newer copy from TrueNAS&amp;rsquo;s zfs snapshots, which gets you the VM configuration at the older point when the backup was taken and the VM disk at the newer point when the snapshot was taken.&lt;/li&gt;
&lt;li&gt;Create a new replication task to push from TrueNAS to the new Proxmox system, including only the VM disk you want to restore, with the destination of rpool/data/vm-xxx-disk-y, where xxx is the VM ID from Proxmox that you are restoring to (which can be different from the existing name) and where y is the disk number within Proxmox (usually 0).&lt;/li&gt;
&lt;li&gt;Force Proxmox to rescan the storage using &lt;code&gt;qm rescan&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;You will find an &amp;lsquo;unused disk&amp;rsquo; magically appears in the VM which matches the zvol you named in step 2, and you can add it as a hard disk and configure it&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;This method is functional, but incomplete.&lt;/p&gt;
&lt;p&gt;It backs up the VM disks and CT datasets as snapshots in ZFS, and replicates the ZFS snapshots to the TrueNAS host. However, we don&amp;rsquo;t backup the Proxmox configuration metadata (including the qemu configuration file), so we would need to recreate the VM manually and replace the virtual drive with the archived zvol to retore it. You could mix this feature with Proxmox side backups, pushing compressed image files to TrueNAS over NFS/SMB, so you have periodic backups of the configuration in addition to more frequent snapshots of the disk images, but then you have two different types of backups managed in two places (pushed from Proxmox and pulled from TrueNAS) to deal with.&lt;/p&gt;
&lt;p&gt;Like with the &lt;a href=&#34;https://www.apalrd.net/posts/2022/truenas_pbs/&#34;&gt;TrueNAS -&amp;gt; PBS setup&lt;/a&gt;, we had to do some minor console work to get this set up, as the feature isn&amp;rsquo;t accessible from the GUI. In theory it should work with TrueNAS CORE or SCALE (although I only tested this on SCALE).&lt;/p&gt;
&lt;p&gt;How does it handle HA / clustered setups? You need to create a separate ssh connection for each node in the system, and a separate replication task for each node as well. Backups from each node will be in separate hierarchies on TrueNAS, and if VMs are moved between cluster nodes, the zvols on the old node will be orphaned in TrueNAS and need to be manually deleted. Likewise, if you outright delete a VM, the zvols will be orphaned in TrueNAS and also need to be manually deleted. So it could be worse, but it&amp;rsquo;s not a perfectly smooth experience.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Network Mounting OctoPrint Data from a NAS</title>
      <link>https://www.apalrd.net/posts/2022/octopi_nas/</link>
      <pubDate>Wed, 16 Feb 2022 09:27:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/octopi_nas/</guid>
      <description>Previously, I described my &amp;lsquo;Ultimate&amp;rsquo; OctoPrint setup, and part of that setup process including remounting a lot of OctoPrint folders to locations on my NAS. This setup worked well until I added OctoLapse, and wanted to backup folders not part of the folder path configuration in OctoPrint. To solve this, I used a different approach entirely, using symbolic links instead of a bunch of network mounts to cleanly and easily relocate OctoPrint data to network storage.</description>
      <content>&lt;p&gt;Previously, I described my &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/&#34;&gt;&amp;lsquo;Ultimate&amp;rsquo; OctoPrint setup&lt;/a&gt;, and part of that setup process including remounting a lot of OctoPrint folders to locations on my NAS. This setup worked well until I added OctoLapse, and wanted to backup folders not part of the folder path configuration in OctoPrint. To solve this, I used a different approach entirely, using symbolic links instead of a bunch of network mounts to cleanly and easily relocate OctoPrint data to network storage. In this post, I&amp;rsquo;ll go through this process, without the length of my previous project (which included setup of all of my plugins, building the LED hardware, etc in addition to the network mount blerb).&lt;/p&gt;
&lt;h2 id=&#34;video&#34;&gt;Video&lt;/h2&gt;
&lt;p&gt;The corresponding video for this tutorial is below. Click the thumbnail to view it on Youtube.
&lt;a href=&#34;https://youtu.be/TgySREwiP8w&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/octopi_nas/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;installing-software&#34;&gt;Installing Software&lt;/h2&gt;
&lt;p&gt;I started with OctoPi, the Raspberry Pi distribution for OctoPrint. I imaged it on an SD card, booted up the Pi, and ran through the OctoPrint setup and updates. After that, I SSH into the Pi (default username is pi, password raspberry) to configure the netowrk mounts.&lt;/p&gt;
&lt;p&gt;The required software to install is autofs. We should do an &lt;code&gt;apt update&lt;/code&gt; and &lt;code&gt;apt upgrade&lt;/code&gt; while we are at it, since the OctoPi distribution is not updated regularly and instead relies on OctoPrint to keep itself (but not necessarily the OS) up to date. At the current point in time OctoPi is still built on Raspberry Pi OS Buster instead of Bullseye, and you will get a warning that the repository has gone from &amp;lsquo;stable&amp;rsquo; to &amp;lsquo;oldstable&amp;rsquo;. Accept the warning and continue.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Just to be safe, run upgrade and update to make sure we are up to date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt upgrade
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install autofs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install autofs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Check to make sure it runs at boot, the install should have already done this.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable autofs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configure-autofs-mounts&#34;&gt;Configure Autofs Mounts&lt;/h2&gt;
&lt;p&gt;Since I wrote the last blog on this topic, I&amp;rsquo;ve found that it&amp;rsquo;s easeiest to mount a single directory from the server, and use symbolic links to point to the sub directories. So, the autofs configuration is pretty simple.&lt;/p&gt;
&lt;p&gt;First, edit &lt;code&gt;/etc/auto.master&lt;/code&gt; and add the following line, which points to a yet to be created shares file, and says any shares within that file are mounted relative to /:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/- /etc/auto.smb.shares --timeout &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt; browse
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Second, create the file (&lt;code&gt;sudo nano /etc/auto.smb.shares&lt;/code&gt;) and add the new share we want to auto mount (copy this line and modify it as necessary):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/mnt/printer -fstype&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;cifs,rw,username&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&amp;lt;user&amp;gt;,password&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&amp;lt;password&amp;gt;,noperm,dir_mode&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;0777,file_mode&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0777&lt;/span&gt; ://server/share/directory
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Key details here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/mnt/printer&lt;/code&gt; is the location we are mounting the share on the local system&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;&amp;lt;user&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;password&amp;gt;&lt;/code&gt; with the authentication information you&amp;rsquo;ve setup on your NAS for this share&lt;/li&gt;
&lt;li&gt;&lt;code&gt;noperm&lt;/code&gt;, &lt;code&gt;dir_mode&lt;/code&gt;, &lt;code&gt;file_mode&lt;/code&gt; mean that permissions are ignored on the local system. The NAS still enforces file permissions on its side. I found these options are needed for Octolapse to work correctly, since it often tries to chmod files in the timelapse folder for no apparent reason, and without the local system ignoring permissions, Octolapse will often fail to chmod files as it does not own them.&lt;/li&gt;
&lt;li&gt;Obviously, &lt;code&gt;server&lt;/code&gt; and &lt;code&gt;share&lt;/code&gt; are dependent on your NAS. IP addresses and DNS names also work here for server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, create the directory at the mount point:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mkdir /mnt/printer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And restart autofs so it reloads the configuration files&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl restart autofs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;relocating-octoprint-directories-to-the-network&#34;&gt;Relocating OctoPrint Directories to the Network&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve setup a subsection with the commands for each folder. You can copy/paste whichever sets you need. Run these as user pi. If you are running on a new installation or otherwise don&amp;rsquo;t want to copy out the existing data, you can omit the rsync step, which copies data out of the old location before deleting it.&lt;/p&gt;
&lt;p&gt;Also, you should not share the same printer directory between multiple printers. You should create a different folder on your NAS for each printer, and then create the folder structure underneath that mount point.&lt;/p&gt;
&lt;h3 id=&#34;watched&#34;&gt;Watched&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create new directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir /mnt/printer/watched
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Go to location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/.octoprint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Delete old directory, watched should be empty already&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -r watched
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make link to new directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /mnt/printer/watched
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;timelapse-and-timelapse-temp&#34;&gt;Timelapse and Timelapse Temp&lt;/h3&gt;
&lt;p&gt;This is a good candidate for network mounting.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create new directories&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir /mnt/printer/timelapse
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir /mnt/printer/timelase/tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Go to location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/.octoprint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy data to new location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rsync -r --progress timelapse/ /mnt/printer/timelapse
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Delete old directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -r timelapse
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make link to new directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /mnt/printer/timelapse
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;uploads&#34;&gt;Uploads&lt;/h3&gt;
&lt;p&gt;If you network mount this directory, do not edit it, let OctoPrint manage it on its own.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create new directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir /mnt/printer/uploads
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Go to location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/.octoprint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy data to new location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rsync -r uploads/ /mnt/printer/uploads
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Delete old directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -r uploads
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make link to new directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /mnt/printer/uploads
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;logs&#34;&gt;Logs&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;d generally recommend against relocating this folder to the network share, since you won&amp;rsquo;t get logs at all if the network share is inaccessible (autofs makes the directory inaccessible if it fails to mount). If you really want to reduce SD wear, you could mount the logs directory as a tmpfs or use folder2ram (which creates a tmpfs which is read from the SD card on boot, and written back on clean shutdown). It all depends on how you want to store your logs and what failure conditions you are most concerned about.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create new directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir /mnt/printer/logs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Go to location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/.octoprint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy data to new location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rsync -r logs/ /mnt/printer/logs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Delete old directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -r logs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make link to new directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /mnt/printer/logs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;backup&#34;&gt;Backup&lt;/h3&gt;
&lt;p&gt;You should absolutely mount this folder on the network, to keep your backups safe from SD card failure.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create new directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir /mnt/printer/backup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Go to location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/.octoprint/data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Copy data to new location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rsync -r --progress backup/ /mnt/printer/backup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Delete old directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -r backup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make link to new directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /mnt/printer/backup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;octolapse-temp&#34;&gt;Octolapse Temp&lt;/h3&gt;
&lt;p&gt;Note that Octolapse timelapses still go in the timelapse folder after they are rendered, which you can redirect using the normal timelapse commands above. However, the temp folder is in a different location.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#tmp was already created above, no need to create another&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#no need to copy tmp either, since it&amp;#39;s temporary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/.octoprint/data/octolapse
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Delete old directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -r tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Make link to new directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /mnt/printer/timelapse/tmp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Proxmox Clustering with 2 Nodes</title>
      <link>https://www.apalrd.net/posts/2022/pve_quorum/</link>
      <pubDate>Sun, 13 Feb 2022 00:01:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/pve_quorum/</guid>
      <description>I&amp;rsquo;m experimenting with Proxmox Virtual Environment (PVE), the same hypervisor I run on my Minilab. It supports clustering and high availability, and I&amp;rsquo;d like to implement the cluster option. Clustering without HA allows multiple nodes to be managed from a single user interface, and for VMs to be offline migrated between nodes. This sounds pretty useful for me, even without the high availability features like live migration. However, any cluster relies on a node voting scheme which requires agreement (quorum) from all of the nodes, and the cluster won&amp;rsquo;t function without quorum being met.</description>
      <content>&lt;p&gt;I&amp;rsquo;m experimenting with Proxmox Virtual Environment (PVE), the same hypervisor I run on my &lt;a href=&#34;https://www.apalrd.net/projects/2021/minilab/&#34;&gt;Minilab&lt;/a&gt;. It supports clustering and high availability, and I&amp;rsquo;d like to implement the cluster option. Clustering without HA allows multiple nodes to be managed from a single user interface, and for VMs to be offline migrated between nodes. This sounds pretty useful for me, even without the high availability features like live migration. However, any cluster relies on a node voting scheme which requires agreement (quorum) from all of the nodes, and the cluster won&amp;rsquo;t function without quorum being met. With only two nodes in a cluster, it&amp;rsquo;s impossible to achieve quorum and no VMs will start. The usual solution to this is to add a new device specifically to vote (a &amp;lsquo;QDevice&amp;rsquo;) running on another server or a Raspberry Pi, but it&amp;rsquo;s also possible to give one node an extra vote to break the ties.&lt;/p&gt;
&lt;p&gt;My minilab uses relatively little power (it&amp;rsquo;s fed by a ~90W DC power brick) and is self contained with local storage, and it&amp;rsquo;s adequate for many of my continuously running services, but I still have to rely on VirtualBox on my workstation for testing a lot of VMs at once. Ideally, I could setup a higher performance node for testing and power it down when I don&amp;rsquo;t need it, with the ability to migrate testing VMs to the production mini-server. In this use case, I can be fairly certain that the minilab will always be running but the testing server might not be, so giving the minilab an extra vote means it can maintain quorum on its own, even if the &amp;lsquo;megalab&amp;rsquo; is shut down. This would allow me to operate without a seprate Qdevice and still cluster the two nodes together.&lt;/p&gt;
&lt;h2 id=&#34;quick-video&#34;&gt;Quick Video&lt;/h2&gt;
&lt;p&gt;This video is a really quick tutorial which focuses on how to do it, and not the background behind why.
&lt;a href=&#34;https://youtu.be/sjS9oDEw9EQ&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/pve_quorum/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-proxmox-cluster-filesystem&#34;&gt;The Proxmox Cluster Filesystem&lt;/h2&gt;
&lt;p&gt;Proxmox stores the vast majority of configuration files in the Proxmox Cluster Filesystem (pmxcfs). Configuration for VMs and containers are stored in the cluster filesystem, along with configuration for each node and the cluster itself. Corosync is used to replicate the cluster filesystem across all of the nodes in the cluster, and deal with distributed locking of cluster configuration files. The cluster filesystem is used even for single-node Proxmox installations, but without synchronization across the cluster.&lt;/p&gt;
&lt;p&gt;The cluster filesystem is mounted at &lt;code&gt;/etc/pve&lt;/code&gt;, so files in this path can be edited by any node and synchronized automagically. The cluster configuration file itself is located at &lt;code&gt;/etc/pve/corosync.conf&lt;/code&gt;. We need to edit this configuration file to change the quorum settings, but we need to be very careful not to mess anything up since corosync will propagate any change we make to all nodes immediately.&lt;/p&gt;
&lt;h2 id=&#34;editing-the-configuration-file&#34;&gt;Editing the Configuration File&lt;/h2&gt;
&lt;p&gt;Proxmox has some warnings on editing the corosync file - &lt;a href=&#34;https://pve.proxmox.com/pve-docs/pve-admin-guide.html#_corosync_configuration&#34;&gt;see here&lt;/a&gt;. Specifically, they recommend creating a copy of the file when editing it, so accidental saving of the unfinished file doesn&amp;rsquo;t cause problems. So, we will do that.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cp /etc/pve/corosync.conf /etc/pve/corosync.new.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can edit the corosync config file in nano to give minilab two quorum votes, so it can run on its own. &lt;code&gt;nano /etc/pve/corosync.new.conf&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;First, in the nodelist section, increase &lt;code&gt;quorum votes&lt;/code&gt; to &lt;code&gt;2&lt;/code&gt; for the node that we want to run on its own:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;nodelist&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;node&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;name:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;minilab&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;nodeid:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;quorum&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;votes:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;ring0&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;addr:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;10.0.0.3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;node&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;name:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;megalab&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;nodeid:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;quorum&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;votes:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;ring0&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;addr:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;10.0.0.4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Increment the &lt;code&gt;config version&lt;/code&gt; key in the totem section by 1 (in this example, from 2 to 3):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;totem&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;cluster&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;name:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;cluster&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;config&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;version:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;linknumber:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;ip&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;version:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;ipv&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4-6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;mode:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;passive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;secauth:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;version:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally, copy the modified file back to the original:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mv /etc/pve/corosync.conf /etc/pve/corosync.conf.bak
mv /etc/pve/corosync.new.conf /etc/pve/corosync.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you really mess things up, it&amp;rsquo;s possible that the nodes won&amp;rsquo;t quorate. If this happens, the entire Proxmox cluster filesystem becomes read-only. You can temporarily reduce the required quorum to 1 to continue: &lt;code&gt;pvecm expected 1&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;For homelabs which don&amp;rsquo;t have enough nodes to maintain quorum, or which don&amp;rsquo;t run all of the nodes all the time, increasing the votes for the continuously running servers can help keep the cluster online without adding additional QDevices and depending on those to be online.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Backing Up TrueNAS Datasets to Proxmox Backup Server</title>
      <link>https://www.apalrd.net/posts/2022/truenas_pbs/</link>
      <pubDate>Thu, 03 Feb 2022 13:27:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/truenas_pbs/</guid>
      <description>As part of my series exploring backup options, I&amp;rsquo;d like to see if I can use Proxmox Backup Server to archive both datasets and zvols of a TrueNAS SCALE server. Why would you want to do this? In my case, I&amp;rsquo;m trying to choose the best starting point for my new backup server, and one potential option is to use Proxmox Backup Server (PBS), but I&amp;rsquo;d like to store data outside of the Proxmox Virtual Environment (PVE) ecosystem.</description>
      <content>&lt;p&gt;As part of my series exploring backup options, I&amp;rsquo;d like to see if I can use Proxmox Backup Server to archive both datasets and zvols of a TrueNAS SCALE server. Why would you want to do this? In my case, I&amp;rsquo;m trying to choose the best starting point for my new backup server, and one potential option is to use Proxmox Backup Server (PBS), but I&amp;rsquo;d like to store data outside of the Proxmox Virtual Environment (PVE) ecosystem. So, I need to make sure I can setup backups from TrueNAS to PBS in a way that makes sense and isn&amp;rsquo;t too difficult to manage. Based on how both PVE and TrueNAS handle backups, I&amp;rsquo;m not going to get everything I want out of either TrueNAS or PBS on the backup server, but I&amp;rsquo;d like to know how much manual scripting I&amp;rsquo;ll have to do with whichever option I choose. This test is part of the &lt;a href=&#34;https://www.apalrd.net/projects/2022/backup_sw/&#34;&gt;Backup Software Project&lt;/a&gt;, click there for other related projects.&lt;/p&gt;
&lt;h2 id=&#34;the-video&#34;&gt;The Video&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a video of the process. Feel free to watch it before or after you read the rest of the post. Click the thumbnail to go to Youtube.
&lt;a href=&#34;https://youtu.be/EcXPYLoH0FA&#34;&gt;&lt;img alt=&#34;Video&#34; src=&#34;https://www.apalrd.net/posts/2022/truenas_pbs/thumb.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;what-is-proxmox-backup-server&#34;&gt;What Is Proxmox Backup Server?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://www.proxmox.com/en/proxmox-backup-server&#34;&gt;Read their description here&lt;/a&gt;. Basically, it&amp;rsquo;s a backup system designed to integrate with Proxmox Virtual Environment (PVE), a hypervisor. However, it really manages 3 types of backups - virtual machines, containers, and hosts. The host backup option is designed to backup the entire filesystem of a host system by using a backup client on the system, proxmox backup client. With the host backup method, PBS can archive the entire contents of a file system, and the user can view the backup archive and download individual files or mount the entire archive as a read-only filesystem. This is pretty handy, and it&amp;rsquo;s the method I&amp;rsquo;m going to use to try to backup the TrueNAS storage server.&lt;/p&gt;
&lt;h2 id=&#34;what-are-the-downsides&#34;&gt;What are the downsides?&lt;/h2&gt;
&lt;p&gt;Well, TrueNAS has no integration for this, so I&amp;rsquo;m on my own with a shell script and cron job to ensure it runs. PBS deals with deduplication, snapshot management, etc. entirely on its own, so I could just run the cron job often and let PBS deal with the rapid influx of data. Another downside is that the PBS client only runs on Debian or Ubuntu Linux, which limits me to using TrueNAS SCALE instead of CORE (the traditional FreeBSD based version).&lt;/p&gt;
&lt;p&gt;Another downside is that PBS doesn&amp;rsquo;t include mount points in the backup (so backing up /mnt on a TrueNAS system won&amp;rsquo;t backup anything, since all of the ZFS datasets are separate mount points). However, we can get around this using the &lt;code&gt;--all-file-systems&lt;/code&gt; flag, if we actually want to backup all of the datasets as one folder, but this merges all of the ZFS datasets as subfolders instead of as separate pxar archives. You have the tradeoff between explicitly listing each dataset in the shell script (with the possibility of forgetting some and not backing them up) vs backing up all file systems into a single archive.&lt;/p&gt;
&lt;p&gt;PBS is also unaware of ZFS on the client side, so it&amp;rsquo;s reading the live filesystem intead of a coherent snapshot and copying that. TrueNAS&amp;rsquo;s native duplication tasks work by taking a snapshot in ZFS and then copying that using the ZFS native send/recv methods, and none of that is done with PBS.&lt;/p&gt;
&lt;p&gt;So, for a disaster recovery type backup, this seems like a functional solution, but ZFS snapshots are still much more convenient to deal with user-induced file deletion, ransomware, etc. Depending on how badly you want the PBS integration in PVE and number of datasets being backed up in PVE vs TrueNAS in your environment, it might make sense to deal with these limitations and continue using PBS to backup everything.&lt;/p&gt;
&lt;h2 id=&#34;how-do-i-set-it-up&#34;&gt;How do I set it up?&lt;/h2&gt;
&lt;p&gt;First, I need to install the proxmox backup client on the TrueNAS system. They only have install guides and binaries for Debian and Ubuntu, and we can use this on TrueNAS SCALE (which is based on Debian Bullseye as of this writing). So, you add the Proxmox public key and sources.list entry, run &lt;code&gt;apt-get update&lt;/code&gt;, then &lt;code&gt;apt-get install proxmox-backup-client&lt;/code&gt;. Fairly simple.&lt;/p&gt;
&lt;p&gt;After this, I need to write a backup script for TrueNAS to call to initiate the backup. I created a new dataset on TrueNAS specifically to hold the backup script, which is itself part of the dataset which will be backed up. This way, the script itself can be easily restored along with the data. Everything is self-contained, including setting the environment variables for the API key / secret and host of the PBS server. Here&amp;rsquo;s a version of the script I use to do the backup&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Authentication and host information for PBS server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PBS_REPOSITORY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&amp;lt;apikey&amp;gt;@pbs@&amp;lt;IP or hostname&amp;gt;:&amp;lt;datastore&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PBS_PASSWORD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&amp;lt;apisecret&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Backup Specifications&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SPEC&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup dataset media on pool tank&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SPEC&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$SPEC&lt;span style=&#34;color:#e6db74&#34;&gt; tank.pxar:/mnt/tank/media&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup dataset backup on pool tank&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SPEC&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$SPEC&lt;span style=&#34;color:#e6db74&#34;&gt; backup.pxar:/mnt/tank/backup&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Backup a zvol&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#I don&amp;#39;t use this personally, so I can&amp;#39;t test it, but this is the syntax for the backup client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Don&amp;#39;t try to back up a zvol while it is mounted / in use&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SPEC&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$SPEC&lt;span style=&#34;color:#e6db74&#34;&gt; zvol.img:/dev/zvol/tank/volume&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Perform backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#You may add your own client-side encryption if you wish&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#By default, the client hostname is used as the backup id in PBS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#You can optionally specify your own using --backup-id &amp;lt;name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you want each pool to have a unique backup ID, you&amp;#39;ll need to call the client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#one time for each backup ID, each with a different spec.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo SPEC is $SPEC
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;proxmox-backup-client backup $SPEC --all-file-systems true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, I need to tell TrueNAS to run the script routinely. PBS will deduplicate at the client level (so it won&amp;rsquo;t send the entire dataset over the network if nothing has changed), so it&amp;rsquo;s safe to call this essentially as often as you want and let PBS deal with pruning on its own.&lt;/p&gt;
&lt;p&gt;To do this, I went to &lt;code&gt;System Settings -&amp;gt; Advanced&lt;/code&gt; and added a &lt;code&gt;Cron Job&lt;/code&gt;. The job calls the backup.sh script hourly as root. Root should have the required permissions to read all of the files in the zfs pool, so it should be able to archive them as well. We could also create a new user for this job, and give them read-only permissions to the entire dataset.&lt;/p&gt;
&lt;h2 id=&#34;restore-process&#34;&gt;Restore Process&lt;/h2&gt;
&lt;p&gt;The process for restoring a file backup, after rebuilding the TrueNAS system and assuming the PBS system is still fine, is to do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Recreate the datasets and permissions (the UNIX permissions of files and folders are retained by PBS, but the ZFS datasets permissions are not).&lt;/li&gt;
&lt;li&gt;Make a new mount point in /mnt to mount the backup using the backup client &lt;code&gt;mkdir /mnt/backup&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Mount the pxar archive using proxmox backup client&amp;rsquo;s FUSE abilities &lt;code&gt;proxmox-backup-client mount host/&amp;lt;hostname&amp;gt;/&amp;lt;time&amp;gt; &amp;lt;archive&amp;gt;.pxar /mnt/backup&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;rsync the contents of the FUSE-mounted backup to the new ZFS pool&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;This method is good for backing up data, but we lose the ZFS attributes and ACLs for the datasets and will need to recreate them before we copy files off the backup.&lt;/p&gt;
&lt;p&gt;It seems like running backup jobs from TrueNAS to PBS is functional with relatively minor console work, if you just want the contents of the filesystem and not the ZFS snapshots to be archived. It&amp;rsquo;s not as clean as the replication tasks within TrueNAS, but backing up a TrueNAS dataset to a PBS server seems like a functional solution. You have to use TrueNAS SCALE at this point, since the PBS client only runs on Linux, but the TrueNAS community seems to be moving to SCALE over CORE anyway.
It&amp;rsquo;s not a bad solution&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>My History of Storage, Preparing for a new Backup Server</title>
      <link>https://www.apalrd.net/posts/2022/backup_intro/</link>
      <pubDate>Mon, 31 Jan 2022 17:32:22 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/backup_intro/</guid>
      <description>I&amp;rsquo;m working on the next revision of my homelab backend. Currently I rely on an Ubuntu server with ZFS on Linux for file storage over Samba, and a separate Proxmox Virtualization Environment (PVE) server (the Minilab) with local LVM storage for virtualization. Ideally, I&amp;rsquo;d like to add a backup server to the mix, with its own storage, that can handle both the Proxmox server and Samba shares. However, the big choice ahead is what software to use for backups - TrueNAS (CORE or SCALE), or the newer Proxmox Backup Server (PBS)?</description>
      <content>&lt;p&gt;I&amp;rsquo;m working on the next revision of my homelab backend. Currently I rely on an Ubuntu server with ZFS on Linux for file storage over Samba, and a separate Proxmox Virtualization Environment (PVE) server (the &lt;a href=&#34;https://www.apalrd.net/projects/2021/minilab/&#34;&gt;Minilab&lt;/a&gt;) with local LVM storage for virtualization. Ideally, I&amp;rsquo;d like to add a backup server to the mix, with its own storage, that can handle both the Proxmox server and Samba shares. However, the big choice ahead is what software to use for backups - TrueNAS (CORE or SCALE), or the newer Proxmox Backup Server (PBS)? Both have their advantages and disadvantages, and I&amp;rsquo;d like to explore them before deploying one as my new backup server.&lt;/p&gt;
&lt;h2 id=&#34;my-life-in-storage-a-history&#34;&gt;My Life in Storage, A History&lt;/h2&gt;
&lt;p&gt;When I started building my network, I relied on the original Raspberry Pi&amp;rsquo;s, each with a USB hard drive and each storing some files. I&amp;rsquo;d essentially manually distribute files across the Pi&amp;rsquo;s, and remember where data was stored. This was pretty terrible for my own data, but a lot of this data was media which would be indexed by XBMC (later KODI) so I didn&amp;rsquo;t really need to remember which drive it was on. I had multiple Pi&amp;rsquo;s since the original Pi had a pretty terrible processor and 100Mbit Ethernet, so using more than one meant it was possible to (on average, depending on where the files were located) access data at a reasonable speed from multiple clients. This was not a great solution, but it worked pretty well for me at the time.&lt;/p&gt;
&lt;p&gt;Eventually I upgraded to FreeNAS, and built a new server for this purpose. I used an AMD Bulldozer based APU on an ITX board, using a pair of USB sticks to boot (at the time this was somewhat common for FreeNAS), onboard SATA for the drives, and a PicoPSU for power. This worked great for file sharing, and I was happily able to migrate all of my data from the old USB drives to the new ZFS pool. The downside to this setup was the lack of virtualization support. Back when I built this it wasn&amp;rsquo;t a huge deal, but over the years I&amp;rsquo;d try to get more into virtualization and FreeNAS (built on FreeBSD) just wasn&amp;rsquo;t great at it. What it was good at were jails (the BSD equivalent and predecessor to LXC containers), so as long as I could run software on FreeBSD, I could run it in a jail. I had a MySQL server for KODI, as well as some energy monitoring software for the first &lt;a href=&#34;https://www.apalrd.net/projects/2019/onewire/&#34;&gt;one-wire network&lt;/a&gt;, but it was always a struggle for me due to my inexperience with BSD at the time.&lt;/p&gt;
&lt;p&gt;Eventually all of my USB sticks died and I got super sick of dealing with USB sticks in general (even &amp;lsquo;brand name&amp;rsquo; ones can be absolutely awful quality, even for a read-only boot drive). Initially, I wanted to run ZFS on Root on Ubuntu to avoid the need for a separate boot drive and bring me back to a more familiar Linux environment (also with better software and driver support), but Ubuntu support just wasn&amp;rsquo;t quite ready for this, so I ended up getting a cheap SSD to run Ubuntu on EXT4 and then mount the ZFS pool. This had the side effect of limiting expansion of my ZFS pool, since I no longer had enough free SATA ports to add another mirror vdev. I setup this configuration, using LXC containers for my virtual environments, and it worked well. The Bulldozer processor really couldn&amp;rsquo;t handle proper virtualization anyway, and all of the software I wanted to virtualize ran in Linux, so containerization was great. I upgraded to a 10G NIC rather painlessly, and was pretty happy. I also eventually replaced the Bulldozer system with a new AMD Ryzen 3400G, so I could use the GPU for hardware acceleration of ffmpeg with &lt;a href=&#34;https://www.apalrd.net/projects/2020/zoneminder_intro/&#34;&gt;Zoneminder&lt;/a&gt;. Being in a container, hardware passthrough is really easy (at least compared to PCIe passthrough with VMs) and all of this worked great.&lt;/p&gt;
&lt;p&gt;After this, I started using my mini desktop (Asrock A300 Deskmini with Ryzen 2400G) as an XCP-NG and later Proxmox host, with a single 500G SSD for both the OS and VM storage (using LVM-Thin). This brings us to the present day, where I need to backup both the Ubuntu server (or its replacement) and the PVE host.&lt;/p&gt;
&lt;h2 id=&#34;my-backup-needs-and-options&#34;&gt;My Backup Needs and Options&lt;/h2&gt;
&lt;p&gt;Currently, my ZFS mirror is essentially my only backup. I regularly scrub it, but the data on it isn&amp;rsquo;t all stored somewhere else. That said, a large portion of the data stored on the pool is either nearly worthless shortly after it&amp;rsquo;s created (such as the security camera recordings from &lt;a href=&#34;https://www.apalrd.net/projects/2021/frigate_intro/&#34;&gt;Frigate&lt;/a&gt;) or is using the ZFS pool as a backup location (i.e. all of my 3D printers, HomeAssistant, etc. push backups to the ZFS pool), so the data is still stored in the original working location. I&amp;rsquo;d certainly be able to recover from a failure of the storage server without much loss, but it&amp;rsquo;s not a friendly idea. At the same time, I&amp;rsquo;m kinda sick of dealing with command line Ubuntu for managing my Samba users and shares. So, upgrades are needed again.&lt;/p&gt;
&lt;p&gt;What data do I have?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;lsquo;Bulk&amp;rsquo; data in the Samba shares, including project files, raw video for editing, etc, some of this is very large and some is very important, but it&amp;rsquo;s mixed&lt;/li&gt;
&lt;li&gt;Media, which was previously used with KODI and may be used with something like Plex or Jellyfin in the future (although realistically streaming services have improved a lot in recent years)&lt;/li&gt;
&lt;li&gt;Backups of devices on the network such as HomeAssistant, and Raspberry Pi&amp;rsquo;s which push data over Samba periodically&lt;/li&gt;
&lt;li&gt;Virtual machine drives from Proxmox&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For me, the ideal setup would be to use TrueNAS (which is great at user management for sharing) for storage and Proxmox (which is great at virtualization), each running on their own hardware and with their own local ZFS pool doing what they do best. The challenge now is which to use for the single backup server?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TrueNAS has great features to push/pull from other ZFS systems using zfs senc/recv, as well as cloud sync features such as S3 which might be useful for me for very critical data. In theory, I might be able to pull snapshots from a PVE server which is using ZFS, but that&amp;rsquo;s not a feature built in to PVE.&lt;/li&gt;
&lt;li&gt;Proxmox has PBS, which integrates well with PVE to backup virtual disks as well as filesystems and deal with archival, including tape backup. I&amp;rsquo;m particularly interested in tape backup although I know it&amp;rsquo;s not cost effective for me, but it&amp;rsquo;s cool and PBS seems to have a good solution for dealing with tapes.&lt;/li&gt;
&lt;li&gt;TrueNAS as a backup server can also be a storage host on its own, allowing devices which support NFS/SMB to push their own backups to the backup server directly (i.e. Home Assistant can push a configuration backup to an SMB share, and this could be on the backup server instead of the working data server). PBS has no option to operate this way.&lt;/li&gt;
&lt;li&gt;PVE doesn&amp;rsquo;t natively support delta backups when using local storage without using PBS, although I could store the VM disks in TrueNAS and mount them over NFS so I can do snapshots on the TrueNAS side, or use TrueNAS to pull snapshots from the PVE server.&lt;/li&gt;
&lt;li&gt;PBS doesn&amp;rsquo;t support pull-style backups at all, it relies on the PBS client to push data to the backup server, so I&amp;rsquo;d need to run the PBS client on TrueNAS SCALE to use PBS as my backup system.&lt;/li&gt;
&lt;li&gt;TrueNAS backup works mostly by using ZFS send/recv, so I&amp;rsquo;d need a completely separate solution to handle tape backup if I ever want to go there.&lt;/li&gt;
&lt;li&gt;PBS doesn&amp;rsquo;t handle cloud/S3 backup like TrueNAS does, although I don&amp;rsquo;t plan on archiving a lot of data to the cloud, having the ability to back up a critical data share would be nice. I could of course do this entirely on the TrueNAS instance which stores the working data instead of the archival instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To try and answer these questions, I&amp;rsquo;m going to try and setup TrueNAS, PVE, and PBS all in virtual machines (PVE doesn&amp;rsquo;t run well in nested virtualization unfortunately) and try to see which set of interactions works best for data storage, PVE, and backups. I don&amp;rsquo;t want to virtualize TrueNAS given how much I work directly from the file shares, and I also don&amp;rsquo;t really want PVE to rely on remote storage, but those might be compromises I&amp;rsquo;ll have to deal with to get a single working backup solution.&lt;/p&gt;
&lt;p&gt;Which backup solution would you use, and why?&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Backing Up OPNsense to a Samba share using Node-Red</title>
      <link>https://www.apalrd.net/posts/2022/opnsense_backup/</link>
      <pubDate>Sat, 22 Jan 2022 01:44:05 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/opnsense_backup/</guid>
      <description>As I&amp;rsquo;ve posted about in other blogs, I use OPNsense as the firewall for my home network. It has an inbuilt method of backing up its configuration to the cloud, but I&amp;rsquo;d like to avoid that and back up locally. Unfortunately, there isn&amp;rsquo;t a plugin in the repository to have the firewall push a backup to a samba share, so I need to run code somewhere to pull the configuration from the firewall and store it on the storage server (where the backup policies will take care of it).</description>
      <content>&lt;p&gt;As I&amp;rsquo;ve posted about in other blogs, I use OPNsense as the firewall for my home network. It has an inbuilt method of backing up its configuration to the cloud, but I&amp;rsquo;d like to avoid that and back up locally. Unfortunately, there isn&amp;rsquo;t a plugin in the repository to have the firewall push a backup to a samba share, so I need to run code somewhere to pull the configuration from the firewall and store it on the storage server (where the backup policies will take care of it). I use Node-red for this, since I already have a lot of flows to pull data out of OPNsense to log in InfluxDB.&lt;/p&gt;
&lt;h2 id=&#34;opnsense-configuration&#34;&gt;OPNsense Configuration&lt;/h2&gt;
&lt;p&gt;It has a fairly robust method of storing configuration in an XML file, so backing up the XML file alone is usually sufficient to restore the configuration in a disaster recovery scenario or after a bad update and total reinstall. In fact, you can migrate between hardware without too much trouble as well, although some of the interface configuration is specific to which Ethernet drivers are in use. It&amp;rsquo;s technically possible to have configuration outside of the XML file if you write custom options for Unbound or some other services, so if you use those custom config files, beware.&lt;/p&gt;
&lt;p&gt;I quickly found a shell script which can do the backup on the OPNsense Forum, and it relies on the os-api-backup plugin (which exposes an API endpoint to download the whole configuration). &lt;a href=&#34;https://forum.opnsense.org/index.php?topic=15349.0&#34;&gt;See Here for the Shell Script&lt;/a&gt;. I will use the same os-api-backup plugin, but do the backup through Node Red instead.&lt;/p&gt;
&lt;h3 id=&#34;node-red-samba-file-access&#34;&gt;Node-Red Samba File Access&lt;/h3&gt;
&lt;p&gt;To access the filesystem via Samba, I&amp;rsquo;m using the node-red-contrib-smb plugin. It seems to work adequately, although there are a lot of caveats to this (you must do \server\share with no subsequent paths, for example). It also doesn&amp;rsquo;t always work correctly without Windows-style paths, which must be escaped of course. So, beware of the frustration.&lt;/p&gt;
&lt;h2 id=&#34;the-flow&#34;&gt;The Flow&lt;/h2&gt;
&lt;p&gt;Anyway, here&amp;rsquo;s my node-red flow to pull the backup from OPNsense&amp;rsquo;s API, write it to a file, read the contents of the directory it&amp;rsquo;s in for autobackup files, and trim the autobackups to keep the most recent only. It won&amp;rsquo;t touch other files in the folder.&lt;/p&gt;
&lt;p&gt;As always, I recommend creating a new samba user on your NAS for this client, and give it permissions to only its backup folder. How you do that is up to you.&lt;/p&gt;
&lt;p&gt;As always, my work is licensed CC-BY-SA unless otherwise specified.
&lt;a href=&#34;https://www.apalrd.net/posts/2022/opnsense_backup/backup_flow.json&#34;&gt;Link to the flow&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>My Start in Twitch streaming</title>
      <link>https://www.apalrd.net/posts/2022/twitch_intro/</link>
      <pubDate>Sun, 16 Jan 2022 01:42:05 -0900</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/twitch_intro/</guid>
      <description>I&amp;rsquo;ve decided to start Twitch streaming my evening gaming sessions. I usually spend a small amount of my evening playing games anyway, so broadcasting it to the world isn&amp;rsquo;t a big change to my routine, and hopefully I can improve my content creation skills at the same time. I play almost exclusively single-player games, particularly first person shooter, puzzle, and simulation games. I&amp;rsquo;m slowly building up my streaming stup and it should help with video creation too, which is something I&amp;rsquo;m excited about.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve decided to start Twitch streaming my evening gaming sessions. I usually spend a small amount of my evening playing games anyway, so broadcasting it to the world isn&amp;rsquo;t a big change to my routine, and hopefully I can improve my content creation skills at the same time. I play almost exclusively single-player games, particularly first person shooter, puzzle, and simulation games. I&amp;rsquo;m slowly building up my streaming stup and it should help with video creation too, which is something I&amp;rsquo;m excited about. I&amp;rsquo;ve already used OBS a lot to stream robotics competitions, so it&amp;rsquo;s not new to me, but Twitch is new, and so is being a personality.&lt;/p&gt;
&lt;p&gt;My very first stream was two weeks ago (2022-01-05), where I streamed the game INFRA, a game I&amp;rsquo;ve never played before and only watched a very short let&amp;rsquo;s play segment on. I already have a low quality webcam (Logitech C270) that I bought to use with my 3D printers (but quickly found the Ethernet cameras far superior for that use case), and had it mounted above my desk facing my keyboard so I could record build videos on my desk, which is a bit of a weird angle to stream. But, I was eager to get into the game and play, and streaming was more of an afterthought, so I setup a view in OBS with the game and the camera, and went at it. It&amp;rsquo;s a bit weird since I play on an ultrawide (21:9) monitor, and the stream is normal width (16:9), so there are black bars in the top and bottom. I&amp;rsquo;ll decide later how to handle this.&lt;/p&gt;
&lt;h2 id=&#34;my-better-setup&#34;&gt;My Better Setup&lt;/h2&gt;
&lt;p&gt;After playing INFRA on stream, I decided to get a slightly better setup. I ordered the parts, waited for them to ship, and continued playing INFRA with a progressively looking better OBS setup in the meantime. I replaced the black bars to fit the ultrawide game with an orange background to match my website, with the stream name and my cameras below the 21:9 game screen. I think this fits fairly well, the game isn&amp;rsquo;t covered by anything (so I don&amp;rsquo;t have to rearrange the screen depending on where the HUD is in-game), and I like the aesthetic.&lt;/p&gt;
&lt;p&gt;The parts I settled on are two Logitech C270 webcams (720p30 and dirt cheap at $25 each), along with one Logitech C922 Pro HD (1080p60 with autofocus and a few other nice features). I also got a Stream Deck, which is useful for more than just streaming (i.e. I can use it in Davinci Resolve, and I already paired it with &lt;a href=&#34;https://github.com/cgiesche/streamdeck-homeassistant&#34;&gt;Home Assistant using the open source plugin&lt;/a&gt; to control my room lights). I intended to use the C922 for my face, but I realized that the game is really front and center and the tiny face view quality isn&amp;rsquo;t super important, so I have a C270 looking down and C270 facing me. I&amp;rsquo;ll reserve the C922 for VR streaming, which I haven&amp;rsquo;t started to setup yet.&lt;/p&gt;
&lt;h2 id=&#34;the-future&#34;&gt;The Future&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m enjoying streaming casually at this point with the two cheap cameras, and the stream deck is definitely not a requirement but it is helpful. Eventually, I&amp;rsquo;d like to expand into VR streaming, and depending on the game, there are lot of different camera layouts I could use. For a fixed location game like Beat Saber, a single camera with Mixed Reality works well. For a more open world game like Half-Life Alyx or Boneworks, it might not work as well, but I&amp;rsquo;ll play around and see. I&amp;rsquo;ll be sure to post more here when I get my VR streaming setup dialed in.&lt;/p&gt;
&lt;h2 id=&#34;my-channel&#34;&gt;My Channel&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;twitch.tv/apalrd&#34;&gt;Link to my Twitch channel&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Using a Raspberry Pi as a Thin Client for Proxmox VMs</title>
      <link>https://www.apalrd.net/posts/2022/raspi_spice/</link>
      <pubDate>Wed, 12 Jan 2022 09:27:05 -0300</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/raspi_spice/</guid>
      <description>Virtual Desktop Infrastructure (VDI) is quite a buzz-word now in enterprise computing, and it&amp;rsquo;s something I&amp;rsquo;d like to experiment more with in my homelab. Essentially, it&amp;rsquo;s a new way to describe old school terminal servers, but with modern features and marketing. The primary difference is that VDI normally implies that each &amp;lsquo;seat&amp;rsquo; is a virtual machine and has some resources associated with it, as opposed to a terminal session running on a shared server.</description>
      <content>&lt;p&gt;Virtual Desktop Infrastructure (VDI) is quite a buzz-word now in enterprise computing, and it&amp;rsquo;s something I&amp;rsquo;d like to experiment more with in my homelab. Essentially, it&amp;rsquo;s a new way to describe old school terminal servers, but with modern features and marketing. The primary difference is that VDI normally implies that each &amp;lsquo;seat&amp;rsquo; is a virtual machine and has some resources associated with it, as opposed to a terminal session running on a shared server. By using VDI, an admin can centralize all of the compute resources and the end devices only need to provide an interface (video / keyboard / mouse), and also guarantee resources such as RAM or GPU to the virtual desktop (something a terminal server does not do). This means the end devices can be significantly cheaper, since they aren&amp;rsquo;t doing much real work, although they now have to deal with a video stream of the virtual desktop.&lt;/p&gt;
&lt;p&gt;In my specific use case, I would like to use a Raspberry Pi attached to the back of the monitor as a general purpose PC in the kitchen. I could just use the Pi itself, or a more expensive device like a NUC, but I already have a Raspberry Pi B+ and a perfectly useful server, so putting compute resources on the server would be ideal for me. Plus, I&amp;rsquo;d like to expand my knowledge of the different methods for VDI over the next few months, and this is a good start.&lt;/p&gt;
&lt;p&gt;My goals for the experiment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use a Raspberry Pi B+ as a usable general purpose web browsing desktop&lt;/li&gt;
&lt;li&gt;Host the general purpose desktop on my lab server (Proxmox)&lt;/li&gt;
&lt;li&gt;Boot the Raspberry Pi directly into the server session without needing to log in to the Pi or launch the session.&lt;/li&gt;
&lt;li&gt;Must support both Linux and Windows targets&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;p&gt;Since this is a really long post, here are some bookmarks to help you navigate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/#video-form&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/#setup-linux-vm-for-testing&#34;&gt;Setup Linux VM for testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/#setup-windows-vm-for-testing&#34;&gt;Setup Windows VM for testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/#setting-up-proxmox-authentication&#34;&gt;Setting Up Proxmox Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/#raspberry-pi-os-lite-setup&#34;&gt;Raspberry Pi OS Lite Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/#minimal-gui-dependencies&#34;&gt;Minimal GUI Dependencies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/#spice-client-for-the-pi&#34;&gt;SPICE Client for Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/#proxmox-spice-proxy&#34;&gt;Proxmox SPICE Proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/#openbox-window-manager&#34;&gt;Openbox Window Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2022/raspi_spice/#start-on-boot&#34;&gt;Start On Boot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;video-form&#34;&gt;Video Form&lt;/h1&gt;
&lt;p&gt;I produced a video which covers some of these topics, click on the thumbnail below to watch it. While recording the video, I was able to find a Raspberry Pi 2 Model B. The article was written with an original Raspberry Pi, and the Pi 2&amp;rsquo;s performance is far more usable for general desktop usage, but not video playback.
&lt;a href=&#34;https://youtu.be/TuDrmq4RQzU&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2022/raspi_spice/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;setup-linux-vm-for-testing&#34;&gt;Setup Linux VM for testing&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ll use Ubuntu 21.10 Desktop for this, since it&amp;rsquo;s the latest version of Ubuntu as of this writing. I created a new VM in Proxmox with pretty minimal hardware:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;4 CPUs&lt;/li&gt;
&lt;li&gt;2GB RAM&lt;/li&gt;
&lt;li&gt;32GB SCSI disk - emulated SSD, enable discard (TRIM support)&lt;/li&gt;
&lt;li&gt;Graphics as SPICE&lt;/li&gt;
&lt;li&gt;Add a device for audio, using ich9-intel-hda driver, with a SPICE backend&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After creating the VM, I booted it to run the installation. Since graphics are SPICE, I need to use a SPICE client on my workstation (instead of the usual noVNC web app). I installed virt-viewer from virt-manager for Windows, and it includes remote-viewer which is designed for this purpose. I selected a normal desktop for Ubuntu and let it run. I had absolutely no issues with SPICE integration on my workstation, the Ubuntu VM integrated the mouse seamlessly with the host and the keyboard worked on the guest when the moust was over the host, as expected.&lt;/p&gt;
&lt;h1 id=&#34;setup-windows-vm-for-testing&#34;&gt;Setup Windows VM for testing&lt;/h1&gt;
&lt;p&gt;I also wanted to prove that this approach to VDI works with Windows, so I installed Windows 10 64-bit in a VM as well. It&amp;rsquo;s not as happy with little RAM as Linux is, so it gets 4GB. My Proxmox test host isn&amp;rsquo;t exactly well endowed with memory. The rest of the setup is the same, emulated SSD, enable TRIM, graphics and sound as SPICE.&lt;/p&gt;
&lt;p&gt;Windows installed fine with SPICE, but once it was installed and rebooted, the SPICE keyboard and mouse didn&amp;rsquo;t work. I stopped the VM, switched back to default (VGA emulation) and rebooted it. Now using noVNC, they worked again. With this, I was able to get Windows to boot, let it deal with a ton of updates (as is Windows), and then it made me select my region and keyboard layout (all things Ubuntu did while it was copying files), and then it &amp;lsquo;had some important setup to do&amp;rsquo; and left me waiting again. What a pain. Windows also really didn&amp;rsquo;t want me to setup an offline account, telling me what a &amp;rsquo;limited experience&amp;rsquo; it would be. I perservered and got my offline account on my test VM. The whole setup experience is maddening compared to Linux. Plus, Microsoft Edge demanded a setup wizard of its own. I don&amp;rsquo;t know how people live with this.&lt;/p&gt;
&lt;p&gt;After all of this, I installed the qemu guest drivers and SPICE guest drivers and restarted the VM, re-enabling SPICE.&lt;/p&gt;
&lt;h1 id=&#34;setting-up-proxmox-authentication&#34;&gt;Setting Up Proxmox Authentication&lt;/h1&gt;
&lt;p&gt;We&amp;rsquo;re eventually going to need to authenticate with the Proxmox API to download the temporary proxy authentication token for SPICE. This requires hardcoding a username/password into the shell script which will launch on boot on the Pi. So, to prevent hardcoding our Proxmox admin password into the Pi&amp;rsquo;s shell script, we can create a new user just for this purpose and only give it permissions to view the console of our VDI servers. I&amp;rsquo;m using a single Proxmox host with built-in authentication, so if you&amp;rsquo;re using a more complex authentication method like AD or LDAP, you&amp;rsquo;ll have to figure this out on your own.&lt;/p&gt;
&lt;p&gt;First, I created a new role (&amp;lsquo;VDIViewer&amp;rsquo;) which only has access to VM.Console. This means our user can only view the console and nothing else. Viewing the console is quite powerful for the VM, but has no access to the host. You might also want to give this group VM.CDROM and VM.PowerMgmt permissions so they can insert their own virtual CDs and restart their VM when it dies or if they accidentally power it off, but that&amp;rsquo;s beyond the scope of this example.&lt;/p&gt;
&lt;p&gt;Next, I created a new user in the pve (Proxmox VE Authentication Server) realm, and gave it a password.&lt;/p&gt;
&lt;p&gt;Finally, I go to the VM(s) I want to let it access, scroll down to Permissions, and add the user to the VM with role VDIViewer.&lt;/p&gt;
&lt;p&gt;If I had a larger number of VMs or a pool of VMs and VDI users, I could also make a user group and pool, add all of the VMs to the pool, and add the user group with the role VDIViewer. Since I only have one of each, just adding the user directly to the VM is easiest.&lt;/p&gt;
&lt;h1 id=&#34;setup-the-raspberry-pi&#34;&gt;Setup the Raspberry Pi&lt;/h1&gt;
&lt;h2 id=&#34;raspberry-pi-os-lite-setup&#34;&gt;Raspberry Pi OS Lite Setup&lt;/h2&gt;
&lt;p&gt;All I had free at this time was a Raspberry Pi Model B+ rev 1.2 (the original single core Pi, upgraded to the 40-pin header). Hopefully it can handle SPICE. I downloaded and installed the lite version of Raspberry Pi OS Bullseye (NOT desktop) and imaged a new SD card. I also enabled SSH by creating an empty file named &amp;lsquo;ssh&amp;rsquo; in the boot partition. After this, the Pi booted up and was ready for me to start.&lt;/p&gt;
&lt;p&gt;As with any new Pi, we need to run raspi-config and do all of the usual new Pi setup&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo raspi-config
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The important options here are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;System Options -&amp;gt; Hostname, set it to something unique (I used &amp;lsquo;vdiclient&amp;rsquo; for this example)&lt;/li&gt;
&lt;li&gt;System Options -&amp;gt; Password, change it from &amp;lsquo;raspberry&amp;rsquo;&lt;/li&gt;
&lt;li&gt;System Options -&amp;gt; Boot / Auto Login, set to Console Autologin&lt;/li&gt;
&lt;li&gt;System Options -&amp;gt; Network at Boot, set to Yes so it won&amp;rsquo;t login until network is available (since we kinda need that to be a thin client)&lt;/li&gt;
&lt;li&gt;Localization Options -&amp;gt; Timezone, set to the right time zone&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once finished, reboot like it asks. It should now auto-login on the physical console. If you need to use Wifi, you can also configure that here. I use wired Ethernet.&lt;/p&gt;
&lt;p&gt;And, of course, we need to do updates!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;minimal-gui-dependencies&#34;&gt;Minimal GUI Dependencies&lt;/h2&gt;
&lt;p&gt;Since I want to minimize the amount of software I install on this poor Pi, I&amp;rsquo;ve skipped the desktop environment and just have a console. However, I still need a little tiny bit of graphical environment to run the SPICE client. So, I&amp;rsquo;m going to install an X server and window manager, but skip the desktop environment and login manager. This means I will not have a graphical desktop (no desktop environment), and I will need to launch in to the graphical environment from an already logged in terminal (no login manager), but I can still launch programs which expect a working X session.&lt;/p&gt;
&lt;p&gt;So, now I need to install all of this&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Install the X server and Openbox window manager&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install xserver-xorg x11-xserver-utils xinit openbox
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We must be patient, but apt will take care of us. Then, we can continue on.&lt;/p&gt;
&lt;h2 id=&#34;spice-client-for-the-pi&#34;&gt;SPICE Client for the Pi&lt;/h2&gt;
&lt;p&gt;I now need to install the SPICE client and ideally test it out before setting it up to auto-run on boot. The SPICE client is &amp;lsquo;remote-viewer&amp;rsquo;, part of the &amp;lsquo;virt-viewer&amp;rsquo; package, which itself is part of the &amp;lsquo;virt-manager&amp;rsquo; project. In this case, we can install it from the Debian repo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install virt-viewer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, more patience. Unfortunately, we can&amp;rsquo;t test it yet since we don&amp;rsquo;t have a functional graphical environment, and we also don&amp;rsquo;t have a SPICE server to connect to.&lt;/p&gt;
&lt;h2 id=&#34;proxmox-spice-proxy&#34;&gt;Proxmox SPICE Proxy&lt;/h2&gt;
&lt;p&gt;After the viewer is installed, we need to get a configuration file for the SPICE client. Proxmox generates these, but it uses a temporary auth token with a limited lifetime, so we need to download a new configuration file each time we launch the remote viewer. &lt;a href=&#34;https://git.proxmox.com/?p=pve-manager.git;a=blob_plain;f=spice-example-sh;hb=HEAD&#34;&gt;Proxmox has a script available for this&lt;/a&gt; which we will use and modify. We could just run the script as-is, but without an x environment running at this point, it won&amp;rsquo;t work. However, I did test the script as-is on a graphical version of Raspbian and it did work fine, so I trust it.&lt;/p&gt;
&lt;p&gt;I made a modified version of this script which hardcodes everything that we need. We just need to call this new script when the graphical environment is ready.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nano thinclient.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;set -e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set auth options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PASSWORD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;vdiuser&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;USERNAME&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;vdiuser@pve&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set VM ID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;VMID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;100&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set Node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# This must either be a DNS address or name of the node in the cluster&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NODE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pvehost&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Proxy equals node if node is a DNS address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Otherwise, you need to set the IP address of the node here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PROXY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$NODE&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The rest of the script from Proxmox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NODE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;NODE%%&lt;span style=&#34;color:#ae81ff&#34;&gt;\.&lt;/span&gt;*&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DATA&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;curl -f -s -S -k --data-urlencode &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;username=&lt;/span&gt;$USERNAME&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; --data-urlencode &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;password=&lt;/span&gt;$PASSWORD&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://&lt;/span&gt;$PROXY&lt;span style=&#34;color:#e6db74&#34;&gt;:8006/api2/json/access/ticket&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;AUTH OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TICKET&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;DATA//&lt;span style=&#34;color:#ae81ff&#34;&gt;\&amp;#34;&lt;/span&gt;/&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TICKET&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TICKET##*ticket:&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TICKET&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TICKET%%,*&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TICKET&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TICKET%%&lt;span style=&#34;color:#ae81ff&#34;&gt;\}&lt;/span&gt;*&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CSRF&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;DATA//&lt;span style=&#34;color:#ae81ff&#34;&gt;\&amp;#34;&lt;/span&gt;/&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CSRF&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CSRF##*CSRFPreventionToken:&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CSRF&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CSRF%%,*&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CSRF&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CSRF%%&lt;span style=&#34;color:#ae81ff&#34;&gt;\}&lt;/span&gt;*&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -f -s -S -k -b &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PVEAuthCookie=&lt;/span&gt;$TICKET&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CSRFPreventionToken: &lt;/span&gt;$CSRF&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://&lt;/span&gt;$PROXY&lt;span style=&#34;color:#e6db74&#34;&gt;:8006/api2/spiceconfig/nodes/&lt;/span&gt;$NODE&lt;span style=&#34;color:#e6db74&#34;&gt;/qemu/&lt;/span&gt;$VMID&lt;span style=&#34;color:#e6db74&#34;&gt;/spiceproxy&amp;#34;&lt;/span&gt; -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;proxy=&lt;/span&gt;$PROXY&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; spiceproxy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Launch remote-viewer with spiceproxy file, in kiosk mode, quit on disconnect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#The run loop will get a new ticket and launch us again if we disconnect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exec remote-viewer -k --kiosk-quit on-disconnect spiceproxy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And of course, don&amp;rsquo;t forget to make it executable&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod +x thinclient.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point, we are almost ready to test, but we still can&amp;rsquo;t just launch the script without a running X server, so we need to configure Openbox (our window manager)&lt;/p&gt;
&lt;h2 id=&#34;openbox-window-manager&#34;&gt;Openbox Window Manager&lt;/h2&gt;
&lt;p&gt;Openbox is the window manager I&amp;rsquo;ve installed, so we need to create a startup script for it to run which will launch our one graphical program.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo nano /etc/xdg/openbox/autostart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace all of the contents with the new startup script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Allow exit of X server with ctrl+alt+backspace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#If you don&amp;#39;t want to let the user terminate/restart, leave this out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#You can always `killall xinit` via SSH to return to a terminal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;setxkbmap -option terminate:ctrl_alt_bksp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Start the shell script we already wrote in our home directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Runloop restarts the thin client (new access token, new config file)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#if the session is terminated (i.e the VM is inaccessible or restarts)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#User will see a black screen with a cursor during this process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ~/thinclient.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, the final moment we&amp;rsquo;ve all been waiting for, from the physical terminal (not the SSH one), start the X server:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;startx --
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;start-on-boot&#34;&gt;Start On Boot&lt;/h2&gt;
&lt;p&gt;The final task is to make startx run on boot (specifically, when our console user logs in to tty1). This one is pretty simple. We need to edit the bash profile to run startx on the first console only&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nano .bash_profile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; -z $DISPLAY &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; $XDG_VTNR -eq &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; startx --
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Try rebooting to see if it works&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After all this, we have a working SPICE thin client running on a Raspberry Pi, with functional video, keyboard, mouse, and speakers.&lt;/p&gt;
&lt;h1 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;I tested this with both my Ubuntu VM and Windows 10 VM and it worked correctly in both cases. The Pi 1 is far too slow to be usable with Windows 10, stuttering through all of the menu animations. Ubuntu was better, but still not a daily driver experience. It&amp;rsquo;s still better than using the GUI on the Pi 1 itself. I&amp;rsquo;d imagine a newer Pi would work much better, but I&amp;rsquo;ve used all of my good ones for projects and am waiting on a few on backorder, so more testing will come in the future once I can get ahold of more Pi&amp;rsquo;s.&lt;/p&gt;
&lt;p&gt;While filming the video for this blog post, I was able to swap out a Pi 2 from another project and test the setup with the quad-core version. It&amp;rsquo;s still not nearly as powerful as the Pi 4, but it makes general desktop usage completely usable on both Windows 10 and Ubuntu, although video playback and animations still struggle. Still, depending on your application, a Pi 3 or Pi 4 for each node in a computer lab or a minimal setup for kids homework is very low cost and perfectly functional. The SPICE protocol on capable client hardware is capable of really anything except low latency gaming, so the real limitation is in the Pi 1 and 2&amp;rsquo;s limited CPU/GPU power to deal with the screen video stream.&lt;/p&gt;
&lt;p&gt;I found that, with the Pi 2, the Ubuntu desktop experience was excellent aside from streaming video, but Windows desktop animations and especially the login screen would occasionally cause major stuttering in display updates. It&amp;rsquo;s also very possible that this is a Windows issue due to running without hardware graphics acceleration, and not a problem with the thin client at all.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t mention this in either the article or the video, but the SPICE protocol is also capable of USB forwarding, although there are some setup hoops on the Windows client. I didn&amp;rsquo;t test this yet, so it&amp;rsquo;s a topic for a future project. Also, this setup should support audio, but the minimal Raspbian installation on the Pi doesn&amp;rsquo;t, so audio on the Pi is also a topic for a future project.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Logging Gateway Statistics from OPNsense to InfluxDB using Node-Red</title>
      <link>https://www.apalrd.net/posts/2022/opnsense_gwlog/</link>
      <pubDate>Thu, 06 Jan 2022 01:42:05 -0900</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/opnsense_gwlog/</guid>
      <description>I log data from my OPNsense firewall using Telegfaf, but there are some statistics in OPNsense which I&amp;rsquo;d like to keep track of which aren&amp;rsquo;t available to be pushed, but are accessible via The API. In particular, I want to keep track of the gateway statistics.
Gateway stats come from continuously pinging the gateway, and are used to determine if a gateway is available for routing. Normally, gateway monitoring is used with multi-WAN setups to remove a gateway from a load-balancing group, or fail over to the next tier in a failover group (or both).</description>
      <content>&lt;p&gt;I log data from my OPNsense firewall using Telegfaf, but there are some statistics in OPNsense which I&amp;rsquo;d like to keep track of which aren&amp;rsquo;t available to be pushed, but are accessible via &lt;a href=&#34;https://docs.opnsense.org/development/how-tos/api.html&#34;&gt;The API&lt;/a&gt;. In particular, I want to keep track of the gateway statistics.&lt;/p&gt;
&lt;p&gt;Gateway stats come from continuously pinging the gateway, and are used to determine if a gateway is available for routing. Normally, gateway monitoring is used with multi-WAN setups to remove a gateway from a load-balancing group, or fail over to the next tier in a failover group (or both). However, even with a single WAN gateway, gateway monitoring can be useful to keep statistics on the reliability of the ISP, or notify on failure. I&amp;rsquo;ve found that my cable modem periodically locks up and rebooting it fixes the problem, so looking for the gateway error rate and gateway status is a good indication that the modem should be rebooted. This flow handles any number of gateways, so you can still use it to keep track of multiple WAN or outgoing VPN gateways, I just don&amp;rsquo;t need it for that.&lt;/p&gt;
&lt;p&gt;I initially set this up before I was using Home Assistant, so I implemented it entirely in node-red and push the results to InfluxDB. While it might be possible to implement this in Home Assistant using the RESTful sensor, OPNsense returns the data as an array for all gateways and parsing this data is far easier in Javascript than Jinja. By pushing the data to InfluxDB first, you can query it in Home Assistant if you want to use it for automations.&lt;/p&gt;
&lt;p&gt;The API endpoint that I use is /api/routes/gateway/status, and it returns an array with the status of each gateway, containing the following information which I capture:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name of the gateway (from OPNsense)&lt;/li&gt;
&lt;li&gt;Address of the gateway&lt;/li&gt;
&lt;li&gt;Status, either &amp;rsquo;none&amp;rsquo; (no errors), &amp;rsquo;loss&amp;rsquo;, or &amp;lsquo;down&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Delay (ms) ping to the gateway&lt;/li&gt;
&lt;li&gt;Std. Dev (ms) of the ping to the gateway&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To use the flow, you should create an API user in OPNsense. It does not require any plugins in OPNsense, but does require node-red-contrib-influxdb in node-red.
As always, my work is licensed CC-BY-SA unless otherwise specified.
&lt;a href=&#34;https://www.apalrd.net/posts/2022/opnsense_gwlog/gwlog_flow.json&#34;&gt;Link to the flow&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Selecting Policy Routes in OPNsense from Home Assistant</title>
      <link>https://www.apalrd.net/posts/2022/ha_fwrules/</link>
      <pubDate>Sat, 01 Jan 2022 13:44:05 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/ha_fwrules/</guid>
      <description>Policy-based routing has a lot of applications in a home lab or home network. It can be used to change the route taken based on the source or destination, and this can be used in multi-WAN or VPN applications to selectively choose traffic to send over one WAN or which traffic to route over a VPN. It can also be used to selectively drop traffic instead of routing it. Having the ability to change some of these routes from Home Assistant makes it possible to control some of these functions from the HA app or via automations.</description>
      <content>&lt;p&gt;Policy-based routing has a lot of applications in a home lab or home network. It can be used to change the route taken based on the source or destination, and this can be used in multi-WAN or VPN applications to selectively choose traffic to send over one WAN or which traffic to route over a VPN. It can also be used to selectively drop traffic instead of routing it. Having the ability to change some of these routes from Home Assistant makes it possible to control some of these functions from the HA app or via automations. One possible use case is to drop traffic from a client entirely when selected, as a rudimentary parental filter. Another, more complicated example of this is routing a media player through a VPN service to avoid geo-restrictions - the ability to enable/disable the VPN tunnel or change which VPN interface is in use, for a specific client, is something that might be useful to allow users to control via the HA app. While I use VPNs in my configuration, all of this would apply equally well to multi-WAN routing.&lt;/p&gt;
&lt;p&gt;As a bit of a warning, everything here assumes the device you are controlling has either a known IP address (v4/v6) or a known MAC, and the device does not intentionally change its IPs or MAC to avoid the firewall rules. For MAC based entries, OPNsense will periodically scan the ARP/NDP cache for all known IP addresses and use those in the firewall rules, so it&amp;rsquo;s possible for traffic to &amp;rsquo;leak&amp;rsquo; if the host in question changes its IPv6 (e.g. due to using a temporary privacy address). However, relying on the NDP cache is the only way to identify IPv6 SLAAC client addresses.&lt;/p&gt;
&lt;h3 id=&#34;ipv6-quirks&#34;&gt;IPv6 Quirks&lt;/h3&gt;
&lt;p&gt;For IPv6, you also have to deal with the potential for devices to have a globally routable IPv6 address using the prefix from the wrong interface (assuming you are getting a prefix delegation from each of your upstream WAN/VPN interfaces). This probably means you will need to rely on NPT (network prefix translation) for all but the primary WAN, or NAT66 if you are using a VPN interface which provides a /128 address instead of a prefix. Clients expect to see a 2000::/3 address as &amp;lsquo;global&amp;rsquo;, so using a ULA range for your network and prefix translating or NATing all of the interfaces will result in many clients preferring IPv4 over IPv6 since they don&amp;rsquo;t believe an FC00::/7 address is routable to the Internet. Hence, you need to pick one of the interfaces which has a global prefix and use its prefix for your internal network, then translate or NAT all of the other interfaces to that prefix. Not great, but for homelabs / home networks where we don&amp;rsquo;t buy our own address space and peer using BGP, it&amp;rsquo;s the best we can do.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-opnsense-for-api-control&#34;&gt;Setting Up OPNsense for API Control&lt;/h2&gt;
&lt;p&gt;OPNsense has an API which we can use. They have some documentation on &lt;a href=&#34;https://docs.opnsense.org/development/how-tos/api.html&#34;&gt;using the API&lt;/a&gt;, and large tables of the API endpoints. In particular, we are interested in the &lt;a href=&#34;https://docs.opnsense.org/development/api/core/firewall.html&#34;&gt;Firewall API&lt;/a&gt;. However, there isn&amp;rsquo;t a good way to control firewall rules via the API. The best we have is control of aliases. Thankfully, this is very powerful, we can (manually, not via API) write a rule which forwards traffic in a named alias over the VPN route, and then selectively add/remove the host in question from the alias in response to the command from Home Assistant. If the host isn&amp;rsquo;t in the alias, then the traffic won&amp;rsquo;t hit the VPN forwarding rule and will instead fall through to other rules or the default gateway. Great!&lt;/p&gt;
&lt;p&gt;The basic logic of the aliases I am using is as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Alias is created with the name of both the device and the destination. Alias contains the MAC address of the device.&lt;/li&gt;
&lt;li&gt;Alias is created with the name of the destination only. Alias contains all of the other aliases which could be routed to this destination.&lt;/li&gt;
&lt;li&gt;Firewall rules (IPv4/IPv6) are created for each destination, reading the alias for their respective destination&lt;/li&gt;
&lt;li&gt;API calls will enable/disable each alias created in #1, causing the alias in #2 and rule in #3 to include or not include the IPs corresponding to the MAC of the device.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now for a graphical tutorial on how to set the OPNsense side of all of this:&lt;/p&gt;
&lt;h3 id=&#34;create-an-api-user-and-add-it-to-your-secretsyaml-file&#34;&gt;Create an API user and add it to your secrets.yaml file&lt;/h3&gt;
&lt;p&gt;Follow the directions in &lt;a href=&#34;https://docs.opnsense.org/development/how-tos/api.html&#34;&gt;OPNsense&amp;rsquo;s Using The API&lt;/a&gt; docs to create a new user for the API, and generate API keys for it. Add the API key and secret as two entries in your home assistant secrets.yaml.&lt;/p&gt;
&lt;h3 id=&#34;setup-the-device-mac-alias&#34;&gt;Setup the Device MAC Alias&lt;/h3&gt;
&lt;p&gt;Create a new alias, type is MAC, give it the MAC address of the device in question. OPNsense will periodically scan the ARP (IPv4) and NDP (IPv6) caches to determine what the most recent IP addresses of the device are. Once this is created, we can use the name of this alias later to reference this device. Since we enable/disable this alias to control routing, we need one of these for each destination, all with the same contents.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Laptop Alias&#34; src=&#34;https://www.apalrd.net/posts/2022/ha_fwrules/alias_laptop.png&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;setup-the-destination-alias&#34;&gt;Setup the Destination alias&lt;/h3&gt;
&lt;p&gt;Create a new alias, type is Host(s), enter a descrpition, and add all of the aliases of hosts which can be routed to this destination. This will be referenced in the firewall rules later.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;VPN alias&#34; src=&#34;https://www.apalrd.net/posts/2022/ha_fwrules/alias_vpn1.png&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;setup-the-destination-routing-rules&#34;&gt;Setup the Destination routing rules&lt;/h3&gt;
&lt;p&gt;Create two new firewall rules, one for IPv4 and one for IPv6, which route any traffic from the destination alias to the gateway of the destination interface. We need two rules here since IPv4 and IPv6 traffic will have separate gateways. All of this assumes you already have your desired outbound gateways setup and working properly on its own. I have an IPv4 example below, but you&amp;rsquo;d need one for each to select the correct IPv4/IPv6 gateway.&lt;/p&gt;
&lt;p&gt;If you are dropping traffic instead of routing it, you can create a single rule for both IPv4 and IPv6, and set it to Block instead of Pass.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;IPv4 Route&#34; src=&#34;https://www.apalrd.net/posts/2022/ha_fwrules/route_ipv4.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;home-assistant-configuration&#34;&gt;Home Assistant Configuration&lt;/h2&gt;
&lt;p&gt;Now we need to configure Home Assistant to enable/disable our aliases.&lt;/p&gt;
&lt;h3 id=&#34;determine-the-uuid-of-the-aliases-we-created-earlier&#34;&gt;Determine the UUID of the aliases we created earlier&lt;/h3&gt;
&lt;p&gt;The easiest way to do this is to backup the configuration in OPNsense, open the resulting XML file in a text editor, and search for the name you gave the alias. You should find an alias and it&amp;rsquo;s corresponding UUID nearby. We will need the UUID for all of the device-&amp;gt;destination aliases for our automations.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Finding the UUID&#34; src=&#34;https://www.apalrd.net/posts/2022/ha_fwrules/alias_xml_uuid.png&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;create-restful-commands-in-home-assistant&#34;&gt;Create RESTful Commands in Home Assistant&lt;/h3&gt;
&lt;p&gt;In our case, we need to access two API endpoints - one to enable/disable the alias, and another to reconfigure (which also updates firewall rules if required). The first command takes the UUID and boolean as parameters, the second takes no parameters.&lt;/p&gt;
&lt;p&gt;Add this wherever you put your rest_commands section, either in configuration.yaml or a file you&amp;rsquo;ve included below it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Rest Commands&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;rest_command&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;firewall_alias_reconfigure&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://192.168.1.1/api/firewall/alias/reconfigure&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;username&lt;/span&gt;: !&lt;span style=&#34;color:#ae81ff&#34;&gt;secret firewall_key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: !&lt;span style=&#34;color:#ae81ff&#34;&gt;secret firweall_secret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;method&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;post&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;verify_ssl&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;firwall_alias_enable&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &amp;gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            {% if enable %}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            https://192.168.1.1/api/firewall/alias/toggleItem/{{uuid}}/1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            {% else %}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            https://192.168.1.1/api/firewall/alias/toggleItem/{{uuid}}/0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            {% endif %}&lt;/span&gt;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;username&lt;/span&gt;: !&lt;span style=&#34;color:#ae81ff&#34;&gt;secret firewall_key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: !&lt;span style=&#34;color:#ae81ff&#34;&gt;secret firweall_secret        &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;method&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;post&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;verify_ssl&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;create-input-boolean-and-associated-automation&#34;&gt;Create Input Boolean and associated Automation&lt;/h3&gt;
&lt;p&gt;Finally, we can create an Input Boolean to select if my laptop should be tunneled over the VPN or not, and an Automation which runs when the Input Boolean changes. The Automation needs to call the enable service with the uuid of the rule we want to enable, the new value of the Input Boolean, and then call the reconfigure service.&lt;/p&gt;
&lt;p&gt;And, the automation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Laptop VPN Route&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;description&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;trigger&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;input_boolean.laptop_vpn_route&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;condition&lt;/span&gt;: []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;action&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;choose&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;conditions&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;condition&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;input_boolean.laptop_vpn_route&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;on&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;sequence&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rest_command.firwall_alias_enable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;data&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;uuid&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3ae2128e-9990-40a2-841e-8b5b6f7b4c92&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;enable&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rest_command.firwall_alias_enable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;data&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;uuid&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3ae2128e-9990-40a2-841e-8b5b6f7b4c92&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;enable&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rest_command.firewall_alias_reconfigure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;restart&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;what-about-dns&#34;&gt;What About DNS?&lt;/h2&gt;
&lt;p&gt;All of this routes the &lt;em&gt;traffic&lt;/em&gt; using policy routing, but DNS isn&amp;rsquo;t traffic being routed through the firewall, it&amp;rsquo;s traffic that ends at the DNS resolver (Unbound) whithin the firewall. So, we end up with a less than ideal situation where everything on the network is still using the same DNS resolver, even if the traffic takes a different path.&lt;/p&gt;
&lt;p&gt;There are a few ways to handle this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use Unbound as a DNS forwarder using DNS over TLS (DoT) and rely entirely on that (so all DNS goes directly over the default gateway, but via TLS to a provider like Quad9). This means the DNS requests don&amp;rsquo;t go to the VPN provider at all, but are still separately protected using TLS on their trip to Quad9.&lt;/li&gt;
&lt;li&gt;Use Unbound or Dnsmasq as a forwarder, and rely entirely on the DNS servers provided by the VPN provider, so all clients use the VPN for DNS via the forwarder.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition, you should create a rule ahead of the policy routing rules which specifies that traffic where the destination is &amp;lsquo;This Firewall&amp;rsquo; pass, and to &amp;lsquo;Apply action immediately on match&amp;rsquo; to prevent it from trying to route DNS traffic incorrectly. OPNsense already does this for DHCP, but not for DNS.&lt;/p&gt;
&lt;h2 id=&#34;expanding-this-to-other-applications&#34;&gt;Expanding This to Other Applications&lt;/h2&gt;
&lt;p&gt;So, now that we can enable/disable firewall rules, here are a few ideas you can take away from this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Selectively block a list of devices from accessing the internet, by enabling/disabling the alias used by a block rule, using any logic you want (parental control type rules)&lt;/li&gt;
&lt;li&gt;Manually select to use a secondary WAN interface in a similar way to selecting the VPN interface&lt;/li&gt;
&lt;li&gt;Use an input select instead of input boolean to choose one of many routing options&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Christmas Maze Boxes</title>
      <link>https://www.apalrd.net/posts/2021/christmas_mazes/</link>
      <pubDate>Fri, 24 Dec 2021 18:06:32 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/christmas_mazes/</guid>
      <description>This Christmas, I printed a whole series of maze boxes as gifts for family members. After finding a gift maze model on Thingiverse, I felt like there must be a better solution to programatically generate mazes of varying difficulty, and so each person who gets one has a unique experience. Before writing such a program myself, I checked to see if it had already been done, and sure enough it had.</description>
      <content>&lt;p&gt;This Christmas, I printed a whole series of maze boxes as gifts for family members. After finding a gift maze model on Thingiverse, I felt like there must be a better solution to programatically generate mazes of varying difficulty, and so each person who gets one has a unique experience. Before writing such a program myself, I checked to see if it had already been done, and sure enough it had. In this case, Adrian Kennard had written a &lt;a href=&#34;https://github.com/revk/PuzzleBox&#34;&gt;C program to generate puzzle mazes&lt;/a&gt;, and hosts an &lt;a href=&#34;https://www.me.uk/puzzlebox/&#34;&gt;interactive version on his website&lt;/a&gt;. His tool generates OpenSCAD code, which can then be used to generate a surface model to 3D print.&lt;/p&gt;
&lt;h2 id=&#34;the-workflow&#34;&gt;The Workflow&lt;/h2&gt;
&lt;p&gt;My workflow for this requires a few tools, all open source:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://www.me.uk/puzzlebox/&#34;&gt;Adrian&amp;rsquo;s Interactive Puzzle Box Generator&lt;/a&gt; to generate the maze&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/openscad/openscad&#34;&gt;OpenSCAD&lt;/a&gt; to generate a surface model from the solid body&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.prusa3d.com/page/prusaslicer_424/&#34;&gt;PrusaSlicer&lt;/a&gt; (or a slicer compatible with your printer) to generate G-code for the printer&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&#34;https://www.me.uk/puzzlebox/&#34;&gt;&lt;img alt=&#34;Click for Adrian&amp;rsquo;s Puzzle Box Generator&#34; src=&#34;https://www.apalrd.net/posts/2021/christmas_mazes/me_uk_puzzlebox.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Adrian&#39;s Web Version, Click to Visit&lt;/div&gt;
&lt;h3 id=&#34;generating-the-puzzles&#34;&gt;Generating the Puzzles&lt;/h3&gt;
&lt;p&gt;Adrian&amp;rsquo;s puzzle box generator is used to generate an OpenSCAD model of the maze, including all of the parts. I used mostly default parameters, but there are a few I changed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;m (total parts to make) = 2 (outer + inner) for most people, or 3 (outer + middle + inner) for people I really wanted to challenge - printing fewer parts drastically reduced my workload later on, since printing the default 4 parts in separate colors for each person would be a huge pain. That said, I did one maze with the total parts set to 4 and it was a very fun challenge for the recipient.&lt;/li&gt;
&lt;li&gt;c (core diameter for content) = 15mm - I found that 10mm default was too small for big American fingers to fit inside to get the goodies out&lt;/li&gt;
&lt;li&gt;h (core height for content) = 75mm - I wanted to be able to fit $1 bills inside, so it needed to be big enough for USD&lt;/li&gt;
&lt;li&gt;X (maze complexity) = varied from +-10 uniquely for each person - I tailored the difficulty to what I thought they could handle. Most family got a difficulty of 0 (average), close friends got 5-6 (I want to challenge them). I didn&amp;rsquo;t make anyone&amp;rsquo;s more difficult than +6, and I had to solve one or two of them for reasons I&amp;rsquo;ll describe later and the +6 was quite at least a half hour challenge for me.&lt;/li&gt;
&lt;li&gt;s (number of outer sides) = 6 - The default is 7, but the default is to have a maze with 3 nubs (i.e. the maze is triplicated around the perimeter of the shape). Since 3 is not divisible by 7 (both are prime), this means there is only one way to assemble the maze where the septagons will line up when finished, and two ways to do it wrong. This caused me to assemble one of the first mazes incorrectly, and have to solve it completely, rotate it one nub over, and close it, etc. until I realized that I should change the number of outer sides to 6 for future mazes so there&amp;rsquo;s no way to assemble it without the hexagons lining up.&lt;/li&gt;
&lt;li&gt;S (text on sides) = the person&amp;rsquo;s name&lt;/li&gt;
&lt;li&gt;T (text scaling) reduced from 1 if their name didn&amp;rsquo;t fit&lt;/li&gt;
&lt;li&gt;O (text outset / embossed) set randomly, so some are embossed and some are raised&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;rendering-in-openscad&#34;&gt;Rendering in OpenSCAD&lt;/h3&gt;
&lt;p&gt;Once the scad files were generated for every person&amp;rsquo;s unique maze, I had to render them to a format which could be sliced. OpenSCAD is a tool which uses code to generate solid bodies. OpenSCAD is a sort of scripting / programming language, so it&amp;rsquo;s very easy to generate parametric solid models using the code. The tool itself then renders the solid model, and can convert it to other solid and surface formats. Once you open the scad file from the puzzle box generator in OpenSCAD, you need to render it (Design -&amp;gt; Render), and then export the render (File -&amp;gt; Export -&amp;gt; Export as) in the format of your choice (AMF/3MF are both good choices).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Maze in OpenSCAD&#34; src=&#34;https://www.apalrd.net/posts/2021/christmas_mazes/maze_openscad.png&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;slicing-in-prusaslicer&#34;&gt;Slicing in PrusaSlicer&lt;/h3&gt;
&lt;p&gt;I have a Prusa printer, so I use PrusaSlicer to generate the gcode for the printer. However, the process so far has led to a single file which contains multiple parts, and I&amp;rsquo;d like to print each part separately (without an MMU). This means I need to split the part into multiple objects, and then generate a gcode file for each one separately.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s very easy to do in PrusaSlicer, thankfully. Right click on the object and click Split -&amp;gt; To Objects. This will take the multi-object single object and turn it into multiple objects. Now, I just disable them one at a time and generate gcode with one part of the print visible. Since I&amp;rsquo;m planning on printing these in a huge variety of colors, I didn&amp;rsquo;t bother trying to match up all of the prints of one color onto the bed, I just printed each part individually. So, now I have around 50 gcode files to print, each one taking under 2 hours (with the 0.3mm DRAFT profile, since it&amp;rsquo;s perfectly adequate for the level of detail in these mazes).&lt;/p&gt;
&lt;h2 id=&#34;final-assembly&#34;&gt;Final Assembly&lt;/h2&gt;
&lt;p&gt;After a print was done, I put it in a bag with the recipient&amp;rsquo;s name on it. I kept all of these in a bin and would print 1-4 pieces per day, depending on how I was feeling and if I had anything else to run on the printer, batching them by color. It took roughly a month to get them all done, but of course the printer wasn&amp;rsquo;t running full time, I printed other things, and I was also sick for a week and didn&amp;rsquo;t print anything.&lt;/p&gt;
&lt;p&gt;For each maze, I had to stuff the maze with a $1 bill and a note, then solve the maze in reverse to assemble it. Thankfully, when you have the puzzle box open, you can examine the maze and find the correct path to close it, whereas when solving it without knowledge of the whole maze is far more difficult. Unfortunately, there were a few times where I had to solve the maze to open it again, due to the septagon/hexagon problem described above, but this was fairly rare. However, I definitely have an appreciation for the difficulty of solving this, especially if you aren&amp;rsquo;t expecting it and aren&amp;rsquo;t entirely sure how it works.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Holiday Lighting with Sonoff, Tasmota, and Home Assistant</title>
      <link>https://www.apalrd.net/posts/2021/holiday_lights/</link>
      <pubDate>Sat, 18 Dec 2021 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/holiday_lights/</guid>
      <description>Every year, the exterior holiday lighting gets reluctantly set up. It&amp;rsquo;s part of McMansion life, a requirement to appear as though you&amp;rsquo;ve made an attempt to decorate for the season. Between the colored optical projectors, to strings of lights haphazardly strung around the front porch, it all ends up needing to be plugged in and turned on/off. For years, the solution to this was a mechanical timer, with on and off markers which could be inserted around the ring to turn the timer on and off at the right time.</description>
      <content>&lt;p&gt;Every year, the exterior holiday lighting gets reluctantly set up. It&amp;rsquo;s part of McMansion life, a requirement to appear as though you&amp;rsquo;ve made an attempt to decorate for the season. Between the colored optical projectors, to strings of lights haphazardly strung around the front porch, it all ends up needing to be plugged in and turned on/off. For years, the solution to this was a mechanical timer, with on and off markers which could be inserted around the ring to turn the timer on and off at the right time. This was all fine and good, but with little precisoin, no adjustability for the seasons or special events, and the inevitable time error if there is ever a power outage. But! No more! We can fix all of this with Home Assistant.&lt;/p&gt;
&lt;h2 id=&#34;sonoff-smart-plugs&#34;&gt;Sonoff Smart Plugs&lt;/h2&gt;
&lt;p&gt;Any smart plug will work for this, as long as it works with Home Assistant. I have a Sonoff S26 which is flashed with Tasmota (see &lt;a href=&#34;https://www.apalrd.net/posts/2021/tasmota_day/&#34;&gt;Tasmota Day&lt;/a&gt; for instructions), and this allows me to keep all of the control on my local network (no cloud dependencies) and trust in the integrity of the firmware. Tasmota speaks MQTT natively, and I will add it as an MQTT switch in my switch.yaml file. Note that there is a Tasmota integration which you can use directly, but my Sonoff&amp;rsquo;s are still setup with the MQTT topic structure from when I used Node-Red entirely, so I&amp;rsquo;m doing it this way.&lt;/p&gt;
&lt;p&gt;MQTT config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Holiday lighting switch via Sonoff relay with Tasmota&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Holiday Lights&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;holiday_lights&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Command to switch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;command_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_B70C5D/cmnd/POWER&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;payload_on&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ON&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;payload_off&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OFF&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;retain&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Availability of switch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;availability&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_B70C5D/tele/LWT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;payload_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Online&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;payload_not_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Offline&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;#Status of switch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_B70C5D/stat/POWER&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;state_on&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ON&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;state_off&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OFF&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;sun-based-timers&#34;&gt;Sun Based Timers&lt;/h2&gt;
&lt;p&gt;I started with a simple sun based timer. I used a single automation instead of an on + off automation to reduce clutter in my Automations page, but it has a trigger for each event instead of a delay to turn the lights off (which could fail due to server restarts duringt the delay time). I decided that 30 minutes after the sun is below the horizon was a good time to turn the lights on, and 4 hours after that is a good time to turn them off. As the seasons progress, this will gradually turn the lights on earlier. Because Daylight Savings Time is the &lt;strong&gt;the worst&lt;/strong&gt;, it&amp;rsquo;s basically dark out the entire time I&amp;rsquo;m at home, so I need many hours of holiday lights to cheer me up.&lt;/p&gt;
&lt;p&gt;If I have an event, I can always turn off the automation and manually control the lights. If I setup a more complex lighting system in the future, you followers will be the first to know.&lt;/p&gt;
&lt;p&gt;Here is the automation I setup, in YAML form. You should be able to copy it in as YAML and then switch back to the visual editor without issues. I like using a single automation with multiple triggers for both on and off, since it reduces the visual clutter in the automations editor, but really this could have been done with two simple automations instead.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Holiday Light Timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;description&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;trigger&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;sun&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;event&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;sunset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;On&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;offset&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;+30:00&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;sun&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;event&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;sunset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Off&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;offset&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;+4:30:00&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;condition&lt;/span&gt;: []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;action&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;choose&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;conditions&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;condition&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;trigger&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;On&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;sequence&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switch.turn_on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;target&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switch.holiday_lights&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switch.turn_off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;target&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switch.holiday_lights&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;single&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Camera Bracket for the CR-10 MAX</title>
      <link>https://www.apalrd.net/posts/2021/cr10_camera/</link>
      <pubDate>Mon, 13 Dec 2021 13:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/cr10_camera/</guid>
      <description>As I recently posted about, I got my CR-10 MAX working and did some basic upgrades to it. After that, it was printing pretty well, so I decided it needed a camera so I could start trusting it with longer unattended prints. I still don&amp;rsquo;t have power control of the printer, so I won&amp;rsquo;t let it run when I&amp;rsquo;m not home, but now I feel comfortable leaving the basement knowing I can check to see if it&amp;rsquo;s making a mess of itself.</description>
      <content>&lt;p&gt;As I &lt;a href=&#34;https://www.apalrd.net/posts/2021/cr10_startup/&#34;&gt;recently posted about&lt;/a&gt;, I got my CR-10 MAX working and did some basic upgrades to it. After that, it was printing pretty well, so I decided it needed a camera so I could start trusting it with longer unattended prints. I still don&amp;rsquo;t have power control of the printer, so I won&amp;rsquo;t let it run when I&amp;rsquo;m not home, but now I feel comfortable leaving the basement knowing I can check to see if it&amp;rsquo;s making a mess of itself.&lt;/p&gt;
&lt;p&gt;I used the &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/&#34;&gt;same camera as my Prusa&lt;/a&gt;, because I had already bought a second one and it works well enough for what I&amp;rsquo;m doing. It&amp;rsquo;s PoE, and with two Raspberry Pi&amp;rsquo;s and two PoE cameras, I had to get a little Netgear 5 port PoE switch for my 3D printer table since there are only two jacks on the wall.&lt;/p&gt;
&lt;h2 id=&#34;mounting-bracket&#34;&gt;Mounting Bracket&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not making an enclosure for the CR-10, so I need to mount the camera directly to the printer. Since the CR-10 is made of T-slot extrusion, I decided to make a part that fits into the slot snugly and mounts the camera. The CAD of this part is pretty simple. I found a dimensional drawing of the 2020 style extrusion used by the printer (so named for it&amp;rsquo;s 20mm x 20mm dimension), and replicated the features of the slot as closely as possible, then printed a test piece. As expected, it didn&amp;rsquo;t fit in the slot, so I reduced the dimensions down slightly until it was a very snug fit. The top of the bracket has a hole which is a bit larger than the tap size for a #8-32 UNF fastener, and I tighten the fastener through the camera bracket without using a nut (purely threading into the plastic). This works well enough for the little camera on the little bracket.&lt;/p&gt;
&lt;h2 id=&#34;the-final-result&#34;&gt;The Final Result&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;Camera Mounted&#34; src=&#34;https://www.apalrd.net/posts/2021/cr10_camera/cam_mount.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Camera View&#34; src=&#34;https://www.apalrd.net/posts/2021/cr10_camera/cam_view.jpg&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this small project. As usual, all design files are licensed Creative Commons CC-BY-SA unless otherwise noted.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/cr10_camera/2020CamBracket.amf&#34;&gt;Printer Mount Bracket (AMF Format)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/cr10_camera/2020CamBracket.FCStd&#34;&gt;Printer Mount Bracket (FreeCAD Original)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://s.click.aliexpress.com/e/_9G5UVT&#34;&gt;JIENUO 5MP Mini Panoramic Camera POE (affiliate link)&lt;/a&gt;
Some links to products may be affiliate links, which may earn a commission for me.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Getting my CR-10 MAX Printing Again</title>
      <link>https://www.apalrd.net/posts/2021/cr10_startup/</link>
      <pubDate>Tue, 07 Dec 2021 19:11:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/cr10_startup/</guid>
      <description>I&amp;rsquo;ve had a Creality CR-10 MAX for about a year and a half at this point. I bought it on sale in early 2020 when I had big project ideas that wouldn&amp;rsquo;t fit on my workhorse Prusa i3 MK3S, so it&amp;rsquo;s fair to say I bought it for the large size for the price point and not the build quality or feature set. However, I&amp;rsquo;ve never really liked it, so now that the Prusa is working really well with Octoprint, the box, the cameras, and all of the other projects I&amp;rsquo;ve documented here, it&amp;rsquo;s time to move on to the CR-10 and get that one working well too.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve had a Creality CR-10 MAX for about a year and a half at this point. I bought it on sale in early 2020 when I had big project ideas that wouldn&amp;rsquo;t fit on my workhorse Prusa i3 MK3S, so it&amp;rsquo;s fair to say I bought it for the large size for the price point and not the build quality or feature set. However, I&amp;rsquo;ve never really liked it, so now that the Prusa is working really well with Octoprint, the box, the cameras, and all of the other projects I&amp;rsquo;ve documented here, it&amp;rsquo;s time to move on to the CR-10 and get that one working well too.&lt;/p&gt;
&lt;p&gt;While I&amp;rsquo;ve had the CR-10 for awhile, I&amp;rsquo;ve only used it for prints where I was running things in bulk and needed the larger bed to make duplicates at the same time. The stock bed on the CR-10 is a rough powedercoated aluminum, which is extremely sticky for prints, leading to usually good first layer adhesion but a really hard time getting prints off. I really miss the flexible PEI bed of the Prusa. The touchscreen is a nice feature compared to the scroll wheel and character LCD of the Prusa and lower-end Creality machines, but it&amp;rsquo;s not very intuitive and doesn&amp;rsquo;t have access to nearly as many settings as the Prusa menu. The translation can also be rough sometimes. Finally, the machine is also limited to about the same flow rates as the Prusa, so there is no speed advantage to the printer, hence I will always prefer the Prusa for prints which don&amp;rsquo;t need the larger bed. Thanks to all of these things, I really only use the CR-10 once every few months.&lt;/p&gt;
&lt;h2 id=&#34;naming-the-printer&#34;&gt;Naming the printer&lt;/h2&gt;
&lt;p&gt;The current Prusa printer is named &amp;lsquo;Columbia&amp;rsquo;, after the first Space Shuttle to fly to space (OV-102). This follows with the space-themed naming of many of my other servers and devices. I normally use manned vehicles for &amp;lsquo;manned&amp;rsquo; computers (desktops and laptops), and while the Space Shuttle is a manned vehicle and a 3D printer really isn&amp;rsquo;t, the Space Shuttle is more notable for being the first space-based construction equipment, building the ISS, servicing the Hubble Space Telescope, etc.. and as such, it&amp;rsquo;s name is fitting for a 3D printer.&lt;/p&gt;
&lt;p&gt;Following Columbia, the second Shuttle to fly to space was Challenger. Hence, the CR-10 is named Challenger.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m aware that both of these shuttles were destroyed in accidents, but they were the first two, so this is what I&amp;rsquo;m sticking with.&lt;/p&gt;
&lt;h2 id=&#34;new-pei-magnetic-bed&#34;&gt;New PEI Magnetic Bed&lt;/h2&gt;
&lt;p&gt;To fix my first gripe, I bought a flexible magnetic PEI bed from Fulament. I bought the &lt;a href=&#34;https://fulament.com/collections/fula-flex-2-0/products/fula-flex-2-0&#34;&gt;Fula-Flex 2.0&lt;/a&gt; in 470x470mm size, as recommended for the CR-10 MAX (it&amp;rsquo;s a big boi). I had to trim the magnetic sheet slightly around metal clips which hold the aluminum bed to the bed structure, but assembly was very easy. Once I had the magnetic sheet on, the PEI sheet snapped in place easily (it&amp;rsquo;s way way more magnetic than the Prusa bed&amp;hellip; it&amp;rsquo;s difficult to pull it off). Overall, I&amp;rsquo;m happy with the bed. But I still really struggled to get the printer leveled.&lt;/p&gt;
&lt;p&gt;The CR-10 MAX includes a BLtouch Z-height sensor standard, while most Creality printers rely on hopes and dreams (or manual Z-leveling) to get a decent first layer height. The BLtouch is fairly similar in concept to Prusa&amp;rsquo;s PINDA probe, except it physically touches the bed with a little needle that pops out when probing. You still need to dial in a Z offset for the machine to account for the height difference between the probe and nozzle, but this process was very painful with Creality&amp;rsquo;s instructions. I&amp;rsquo;ve always settled for adjusting the bed knobs to get the bed leveled side to side, something that shouldn&amp;rsquo;t be necessary with multi-point calibration.&lt;/p&gt;
&lt;h2 id=&#34;new-firmware&#34;&gt;New Firmware&lt;/h2&gt;
&lt;p&gt;The next step in my journey is to find a better firmware build for the CR-10 MAX. A vast majority of consumer 3D printers use &lt;a href=&#34;https://marlinfw.org/&#34;&gt;Marlin firmware&lt;/a&gt;, which is open-source and requires distribution of the source code changes, which Creality has done. In theory, I could take this, reconfigure it as I wish, compile it, and program the mainboard. However, the CR-10 MAX is a bit special in that it also has a graphic LCD which is separate from the mainboard. Creality has made the graphic files for this available too, so you can modify the screen graphics if you make corresponding changes to the firmware.&lt;/p&gt;
&lt;p&gt;I looked around for the best CR-10 alternative firmware and ended up deciding on &lt;a href=&#34;https://tiny-machines-3d.myshopify.com/pages/resourcepagecr10max&#34;&gt;Tiny Machines 3D&lt;/a&gt;&amp;rsquo;s firmware. Unfortunately their site is a bit of a mess with guides hosted on Google Docs (ouch), but I was able to flash both their screen files (DWIN_SET) and mainboard hex file and found that the printer was slightly more pleasant to use. The Tiny Machines firmware has much better instructions for bed leveling, what to add to the start G-code to actually use bed leveling data, and does a larger grid for bed leveling (5x5 instead of 4x4). After working through the full bed leveling guide from them (something the CR-10 didn&amp;rsquo;t really come with), I found that the printer worked much better than before. I think the key is that my startup G-code was missing the M420 instruction, which tells Marlin to actually use stored bed leveling data (after G28 machine homing, bed leveling is not used until G29 commands bed leveling or M420 commands use of stored bed leveling data). Since the bed is never perfectly level, and especially the giant bed of the CR-10 MAX, doing the 5x5 leveling calibration and then actually using the data is important. The instructions were also very clear in how to do the &amp;lsquo;AUX leveling&amp;rsquo;, something that was not super clear in the Creality instructions but is actually very important to getting a good nozzle offset for the BLtouch probe.&lt;/p&gt;
&lt;p&gt;The new firmware also makes a lot less noise, resorting to basic hissing instead of all of the low quality sounds the Creality firmware would play. Neither sound is particularly pleasant, but the hisses are shorter.&lt;/p&gt;
&lt;h2 id=&#34;more-octoprint&#34;&gt;More Octoprint&lt;/h2&gt;
&lt;p&gt;Of course, I need another Raspberry Pi for Octoprint for this printer. Since the Raspberry Pi 4 has been backordered for months (I have an order in&amp;hellip;), I decided to start with a Pi 2 that I already owned and will see how it goes. I know the Pi Zero is strongly not recommended for OctoPrint, and the Pi 2 has a step up in processor (4 cores vs 1 core), although it&amp;rsquo;s not as powerful as the Pi 3 and nowhere close to the Pi 4. I got a basic install setup, mounted everything as an autofs network share (this time using symbolic links in the ~/.octoprint folder instead of remapping the folders within Octoprint), configured the printer volume and such, and had it working pretty quickly.&lt;/p&gt;
&lt;p&gt;There are some quirks. The CR-10 doesn&amp;rsquo;t have isolation on the USB port (at all, apparently), so the LCD will turn on and try to boot up just by plugging in USB to the Pi with the main power to the printer off. So, once I start turning the machine one and off automatically, I&amp;rsquo;ll have to do something about that.&lt;/p&gt;
&lt;h2 id=&#34;future-improvements&#34;&gt;Future Improvements&lt;/h2&gt;
&lt;p&gt;Now that the printer is working as it should, I have a few enhancements planned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A case for the Pi&lt;/li&gt;
&lt;li&gt;Sonoff S31 power control and monitoring&lt;/li&gt;
&lt;li&gt;Updating all of my Home Assistant notifications to correctly work for both printers&lt;/li&gt;
&lt;li&gt;New camera mount for the wide-angle camera&lt;/li&gt;
&lt;li&gt;New NozzleCam for the CR-10, which will need a much more clever mount design than the Prusa did&lt;/li&gt;
&lt;li&gt;LED lighting down the diagnoal bracing of the printer, since I&amp;rsquo;m not building an enclosure for this one&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Introducing StorageTags</title>
      <link>https://www.apalrd.net/posts/2021/storagetags/</link>
      <pubDate>Fri, 03 Dec 2021 08:07:32 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/storagetags/</guid>
      <description>As you might recall from my last blog post, I&amp;rsquo;ve been playing with workshop organization using fiducial markers to locate storage boxes. I&amp;rsquo;ve started to move past the proof of concept code phase into the slightly functional open-source project phase, and I created a repository and developed some working code. The project is just barely functional at this phase, but it has the ability to connect to cameras over RTSP, skip images to reduce the detection framerate, decode them using one of the AprilTag types, and publish the resulting detection data to MQTT.</description>
      <content>&lt;p&gt;As you might recall from my &lt;a href=&#34;https://www.apalrd.net/posts/2021/april_tags/&#34;&gt;last blog post&lt;/a&gt;, I&amp;rsquo;ve been playing with workshop organization using fiducial markers to locate storage boxes. I&amp;rsquo;ve started to move past the proof of concept code phase into the slightly functional open-source project phase, and I created &lt;a href=&#34;https://github.com/apalrd/StorageTags&#34;&gt;a repository&lt;/a&gt; and developed some working code. The project is just barely functional at this phase, but it has the ability to connect to cameras over RTSP, skip images to reduce the detection framerate, decode them using one of the AprilTag types, and publish the resulting detection data to MQTT. Conceptually, this is all that&amp;rsquo;s required if you just want to get a bunch of tag ID and coordinate data from camera(s) into MQTT to deal with yourself.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not a great frontend developer (I have basically no experience beyond HTML), so some assistance in that portion of the project would be great. I&amp;rsquo;m slowly churning through the backend (REST APIs, database code, &amp;hellip;) but the UI is nonexistant. My goal is to eventually be able to view a list of each box in the system, sort by name / category / shelf, and find its location (or lack of known location).&lt;/p&gt;
&lt;p&gt;Until then, feel free to follow my progress on both the &lt;a href=&#34;https://www.apalrd.net/projects/2021/storage_tracker/&#34;&gt;Project Page&lt;/a&gt; as well as the &lt;a href=&#34;https://github.com/apalrd/StorageTags&#34;&gt;Repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also, if you&amp;rsquo;re interested in contributing but aren&amp;rsquo;t a programmer, I&amp;rsquo;m open to suggestions to new names, a graphical theme, and logo for the project as well.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Fiducial Markers for Physical Storage Tracking</title>
      <link>https://www.apalrd.net/projects/2021/storage_tracker/</link>
      <pubDate>Thu, 25 Nov 2021 08:06:32 -0400</pubDate>
      
      <guid>https://www.apalrd.net/projects/2021/storage_tracker/</guid>
      <description>Previously, I saw (and can no longer find the source) a vlog about a maker who stored all of his projects and stock of parts in bins over his long work bench. All of the bins were labeled with some sort of code, and a security camera in his office would periodically scan for codes in the image and keep track of the location of each bin. With this system, he could put any bin in any empty spot on the shelf and easily find it later, or find that it was not on the shelf, from the comfort of his desk computer.</description>
      <content>&lt;p&gt;Previously, I saw (and can no longer find the source) a vlog about a maker who stored all of his projects and stock of parts in bins over his long work bench. All of the bins were labeled with some sort of code, and a security camera in his office would periodically scan for codes in the image and keep track of the location of each bin. With this system, he could put any bin in any empty spot on the shelf and easily find it later, or find that it was not on the shelf, from the comfort of his desk computer. I sought to recreate this, for my own maker space.&lt;/p&gt;
&lt;p&gt;I tried a few different approaches involving QR codes and &lt;a href=&#34;https://en.wikipedia.org/wiki/Fiducial_marker&#34;&gt;fiducial marking&lt;/a&gt;, and at this point I&amp;rsquo;ve settled on &lt;a href=&#34;https://april.eecs.umich.edu/software/apriltag&#34;&gt;AprilTags&lt;/a&gt; based on testing I&amp;rsquo;ve performed (See &lt;a href=&#34;https://www.apalrd.net/posts/2021/april_tags/&#34;&gt;this blog post&lt;/a&gt; for the testing). This project page will catalogue all of the work I&amp;rsquo;ve done to make this a reality.&lt;/p&gt;
&lt;h2 id=&#34;initial-missteps-with-qr-and-2d-barcodes&#34;&gt;Initial Missteps with QR and 2D Barcodes&lt;/h2&gt;
&lt;p&gt;My naive approach was to try and encode the name of the box in a QR code, then have the camera read the code and publish the location of the box to MQTT. From there, I could centrlally process all of the MQTT topics from all of the cameras (gotta think about scalability), and make a simple inventory of each shelf and reverse inventory of each box, listing the shelf and position. If I could encode the name of the box (or something short enough for me to encode and long enough to recognize), I wouldn&amp;rsquo;t need any sort of database to correlate box IDs to metadata.&lt;/p&gt;
&lt;p&gt;I initially started by researching the greater space of &lt;a href=&#34;https://en.wikipedia.org/wiki/Barcode#Matrix_(2D)_barcodes&#34;&gt;2D matrix barcodes&lt;/a&gt;. The most commonly known is the QR code (&amp;lsquo;Quick Response&amp;rsquo;), which is widely used to encode all kinds of information to be read primarily by mobile phones. Other codes I investigated include the microQR, Aztec code, and Data Matrix codes. I used &lt;a href=&#34;https://zingl.github.io/index.html&#34;&gt;a generator&lt;/a&gt; to generate codes in a variety of types for a 10 character string, and printed them out in two sizes - 0.9&amp;quot; square and 2.5&amp;quot; square. 0.9&amp;quot; square happens to be the largest size I can print on my label printer, and 2.5&amp;quot; seemed about right to use premade address label stickers which are easy to print.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;2d barcodes&#34; src=&#34;https://www.apalrd.net/projects/2021/storage_tracker/qr_mid.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;I taped this paper on the wall above my desk, and tried a few different cameras before analyzing the images using OpenCV. This particular image was taken by the same model of camera as my &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/&#34;&gt;3D Printer Wide Angle Camera&lt;/a&gt;, which was a candidate to become the makerspace inventory camera.&lt;/p&gt;
&lt;p&gt;This approach did not go well. With all images the same dimensions, the number of pixels in the image has a strong impact on the readability from the same distance. The MicroQR is only 13x13, while the Aztec is 15x15 and the regular QR is 21x21. This seems small as far as QR codes (and a 10 character string is really very little data), so it just gets worse from here. I was never able to decode any of the 0.9&amp;quot; codes with any camera at any reasonable distance, so I gave up on printing a barcode as part of the 24mm label maker label.&lt;/p&gt;
&lt;p&gt;With the larger images, the MicroQR seemed promising visually, but I couldn&amp;rsquo;t find any open source library to decode it, so we will never know how well it would have performed. I found websites able to decode the Aztec code, but again no open source libraries were able to decode it. The websites seemed to be able to adequately decode the &amp;lsquo;mid&amp;rsquo; depth image (shown above), which is actually only about 3&amp;rsquo; since the camera has such a wide angle, but without being able to integrate it into my own code the Aztecs approach was another dead end.&lt;/p&gt;
&lt;p&gt;That left the QR code that we started with. There are plenty of QR decoders available with OpenCV bindings (including OpenCV&amp;rsquo;s own built-in decoder, &lt;a href=&#34;http://zbar.sourceforge.net/download.html&#34;&gt;Zbar&lt;/a&gt;, and Wechat&amp;rsquo;s CNN based decoder). Of these, Zbar was the most difficult to install (partially because the project has been abandoned for around a decade and never compiled on macOS) but very notably outperformed the other two, and was also the only one to successfully return an array of codes when multiple codes were in view (the rest just picked the &amp;lsquo;best&amp;rsquo; one). Since I really need all of the codes in view, that was very important.&lt;/p&gt;
&lt;p&gt;Despite all of this success with Zbar, I was very unimpressed with how close the camera had to be to get working detection. So, I need a new system with lower resolution tags that the camera can resolve from further away.&lt;/p&gt;
&lt;h2 id=&#34;fiducial-markers&#34;&gt;Fiducial Markers&lt;/h2&gt;
&lt;p&gt;Wikipedia has a good introduction on &lt;a href=&#34;https://en.wikipedia.org/wiki/Fiducial_marker&#34;&gt;fiducial markers&lt;/a&gt; for those unfamiliar. Essentially, these are specifically designed patterns which encode a very small amount of information in a way that is designed for machine vision to unambiguously identify the marker. Normally they are used to identify the position and orientation of the marker to locate the image or the marker in space (given a known position of either the marker or the camera), and any coding within the market is just to identify the marker out of a small set in case there are multiple fiducuials in view at once. The advantage of this is the data encoded is extremely low, and thus the images are extremely low resolution, and when properly scaled up they are easily identified by cameras at much further distances. Wikipedia has a comparison between a few fiducial marker packages, and based on the recent development and open-source nature I selected &lt;a href=&#34;https://april.eecs.umich.edu/software/apriltag&#34;&gt;AprilTags&lt;/a&gt; as my next path of approach. &lt;a href=&#34;https://www.apalrd.net/posts/2021/april_tags/&#34;&gt;I wrote a blog post on my initial experimentation with this&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;introducing-storagetags&#34;&gt;Introducing StorageTags&lt;/h2&gt;
&lt;p&gt;I decided to create a proper software solution for this. I thought through the architecture and settled on some design goals:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Software should run on a single application server (instead of on the camera / Raspberry Pi)&lt;/li&gt;
&lt;li&gt;Cameras should use standard video protocols such as RTSP or HTTP JPEG requests, and converting webcams, PiCams, or capture cards to RTSP/HTTP is not within the scope of this project&lt;/li&gt;
&lt;li&gt;Application server should retrieve and process images from all cameras&lt;/li&gt;
&lt;li&gt;Application server should maintain state of entire system&lt;/li&gt;
&lt;li&gt;Scalability is not believed to exceed the capacity of a single server (as framerates are low and video processing scales well across threads), so separating the processing from state management is not a requirement at this time&lt;/li&gt;
&lt;li&gt;Software should have a purely web-based UI (mobile friendly preferred) for users to view the status, box locations, manage boxes, and add/reassign boxes&lt;/li&gt;
&lt;li&gt;Software should have REST and MQTT API to retrieve/publish state for use by other applications. Beyond associating tag IDs with boxes, we will not deal with the contents or inventory within the box&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I chose to name the project &amp;lsquo;StorageTags&amp;rsquo;, although I&amp;rsquo;m not sure if it&amp;rsquo;s the most unique name, and I reserve the right to change it in the future.&lt;/p&gt;
&lt;p&gt;I explain a bit more about the creation of the project on &lt;a href=&#34;https://www.apalrd.net/posts/2021/storagetags/&#34;&gt;this blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll continue to update this page as I continue to develop the software. I&amp;rsquo;ve started to move out of the experimentation phase, but the software is far from finished&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Playing with Fiducial Markers and AprilTags</title>
      <link>https://www.apalrd.net/posts/2021/april_tags/</link>
      <pubDate>Thu, 25 Nov 2021 08:06:32 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/april_tags/</guid>
      <description>Recently, I have been organizing all of the parts and pieces of my partially finished projects so I can go back to projects more easily. This started as a simple goal - keep all of my work in boxes, keep the boxes labeled, and keep the boxes in a place where they are easy to get to. I have mountains of leftover parts I&amp;rsquo;ve accumulated over the years, and I really need a better solution.</description>
      <content>&lt;p&gt;Recently, I have been organizing all of the parts and pieces of my partially finished projects so I can go back to projects more easily. This started as a simple goal - keep all of my work in boxes, keep the boxes labeled, and keep the boxes in a place where they are easy to get to. I have mountains of leftover parts I&amp;rsquo;ve accumulated over the years, and I really need a better solution.&lt;/p&gt;
&lt;p&gt;The first solution was simple - buy a bunch of smaller boxes. I primarily had 18 gallon storage totes and shelving designed to hold them, but they are way too big for any project and end up filled with everything. I decided on smaller 7 quart (sorry metric friends) bins with latching lids, as the perfect size for most of the electronics projects I normally work on.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;The Bins&#34; src=&#34;https://www.apalrd.net/projects/2021/storage_tracker/bins.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;Of course, I could just use my label maker to print labels for each bin, and manually search for them on a shelf. But, I could also take a much cooler approach and design something to track all of the bins for me. Is it more useful than manually reading all of the labels on the shelf? Maybe not, but sometimes the fun of the project is in building it more than using it.&lt;/p&gt;
&lt;p&gt;Enter my new project - &lt;a href=&#34;https://www.apalrd.net/projects/2021/storage_tracker/&#34;&gt;Storage Tracker&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As a result of this, my wall is now plastered with grids of fiducial markers, reminiscent of the early Virtual Reality demos at VALVe where the entire room had giant block codes scattered all over.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Tags from Dahua camera&#34; src=&#34;https://www.apalrd.net/projects/2021/storage_tracker/tags1_output.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Test image from Dahua 4MP (2560x1440) security camera&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Tags from Wide Angle camera&#34; src=&#34;https://www.apalrd.net/projects/2021/storage_tracker/tags7_output.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Test image from Wide Angle 5MP (2560x1920) security camera at a low angle&lt;/div&gt;
&lt;h2 id=&#34;initial-findings&#34;&gt;Initial Findings&lt;/h2&gt;
&lt;p&gt;I have 4 types of AprilTags here - I printed a sheet of 30x tags for each type (tag16h5, tag25h9, tag36h11, tagStandard52h13). These are roughly 1.5&amp;quot; square not including the keep out area, so these are smaller than the QR codes I tested earlier. I started with only the first 3 types (which are 4x4, 5x5, and 6x6 pixels active area plus a 1px solid border), which support up to 30, 35, and 998 unique codes respectively. I&amp;rsquo;d ideally like to use the smallest number of pixels possible for the number of boxes I have. Since I&amp;rsquo;m likely to expand past 30 and 35 boxes, the tag36h11 seems like the minimum for me, but maybe someday one of you will use my (eventual) software to manage a much larger storage system and the tagStandard52h13 with its 57,714 total tags will required for you. Another approach is to use two different tags (i.e. tag16h5 + tag25h9, which would be 30 * 35 or 1050 possibilities), since two tags side by side might fit better on a box than a single larger tag. Also, especially with the smallest tag16h5, the detector often detects blurred versions of larger tags (hence finding ~35 tags when there are only 30 in the image). Ideally you&amp;rsquo;d stick to only one type of tag in your entire inventory to simplify this. All of this must be considered when choosing the tag system to use for your storage tracker.&lt;/p&gt;
&lt;p&gt;I accidentally printed the tagStandard52h13 incorrectly, so the printer cropped off the right most row of pixels, so 6 of the tags shouldn&amp;rsquo;t read correctly. It&amp;rsquo;s stil much harder for that tag type to be detected than the other 3 tag types at the distance I&amp;rsquo;d like to place my camera.&lt;/p&gt;
&lt;h2 id=&#34;the-test-code&#34;&gt;The Test Code&lt;/h2&gt;
&lt;p&gt;At this point, I&amp;rsquo;m taking still images from the cameras and running them through a python script to process them and export a new modified image. I&amp;rsquo;m running this on Ubuntu, so no guarantees about Windows or macOS. You need to install AprilTags and compile it with all of the python options working (it will let you know if configure can&amp;rsquo;t find python modules it needs, and thus won&amp;rsquo;t build the python bindings). You also need the pip module opencv-contrib-python to get the OpenCV python bindings.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-Python&#34; data-lang=&#34;Python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; cv2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; numpy &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; apriltag &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; apriltag
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Draw function&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;display&lt;/span&gt;(im, detections, color):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; detect &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; detections:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Extract points from detection data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        points &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; detect[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;lb-rb-rt-lt&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; len(points)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Draw the four lines making up the points&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; j &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,n):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            p1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; tuple([int(cell) &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; cell &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; points[j]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            p2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; tuple([int(cell) &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; cell &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; points[(j&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;n]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;line(im, p1, p2, color, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Read in the file as both color (for display) and grayscale (for analysis)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fname &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tags.jpg&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;imagecolor &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;imread(fname)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;image &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;imread(fname,cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;IMREAD_GRAYSCALE)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Create a detector for each tag type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;detector1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; apriltag(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tag16h5&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;detector2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; apriltag(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tag25h9&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;detector3 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; apriltag(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tag36h11&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;detector4 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; apriltag(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tagStandard52h13&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Run each detector on the grayscale image - comment out the ones you don&amp;#39;t expect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;detections1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; detector1&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;detect(image)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;detections2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; detector2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;detect(image)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;detections3 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; detector3&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;detect(image)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;detections4 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; detector4&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;detect(image)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Print the total number of detections - only expect 24 of 52h13 since that one got messed up by the printer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Total &amp;#34;&lt;/span&gt;,len(detections1),&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; detections tag16h5 (expect 30)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Total &amp;#34;&lt;/span&gt;,len(detections2),&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; detections tag25h9 (expect 30)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Total &amp;#34;&lt;/span&gt;,len(detections3),&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; detections tag36h11 (expect 30)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Total &amp;#34;&lt;/span&gt;,len(detections4),&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; detections tagStandard52h13 (expect 30, or 24)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Add overlays for each of the detection lists in a different color&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;display(imagecolor,detections1,(&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;display(imagecolor,detections2,(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;display(imagecolor,detections3,(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;display(imagecolor,detections4,(&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;128&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Write the output file back &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;imwrite(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;output.jpg&amp;#34;&lt;/span&gt;,imagecolor)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My goal going foward is to make blog post updates like this instead of massive project pages, since I have a lot of projects that I work on a lot of and keeping this documentation thorough and clearly written helps me keep track of everything I tried.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Setting Up my Creality CR-10 MAX</title>
      <link>https://www.apalrd.net/projects/2021/creality_setup/</link>
      <pubDate>Tue, 23 Nov 2021 08:06:32 -0400</pubDate>
      
      <guid>https://www.apalrd.net/projects/2021/creality_setup/</guid>
      <description>In this project, I&amp;rsquo;m going to setup my Creality CR-10 MAX in the same way that I&amp;rsquo;ve setup my Prusa i3 MK3S. I&amp;rsquo;ll continue to update this page as I make progress, instead of splitting the project into multiple parts like I did for the Prusa. My goals for the project are as follows:
OctoPi install, printer profile in OctoPrint, remote mount filesystem, and MQTT - Completed Here PrusaSlicer profile for the CR-10 MAX - Completed, Not Published Power control and monitoring - Not Started HomeAssistant integration, including better notifications including which printer is done (currently my notifications assume &amp;lsquo;columbia&amp;rsquo; is done) - In Progress LED status indicators - Not Started Camera mount for the wide angle camera - Completed Here Camera mount for the nozzle camera - Not Started Dealing with the lack of USB power/isolation of the Creality printers (The printer controller and LCD will stay on powered by the USB port) - Not Started Most notably, I will not be building a box for this printer at this point in time.</description>
      <content>&lt;p&gt;In this project, I&amp;rsquo;m going to setup my Creality CR-10 MAX in the same way that I&amp;rsquo;ve setup my Prusa i3 MK3S. I&amp;rsquo;ll continue to update this page as I make progress, instead of splitting the project into multiple parts like I did for the Prusa. My goals for the project are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OctoPi install, printer profile in OctoPrint, remote mount filesystem, and MQTT - &lt;a href=&#34;http://localhost:1313/posts/2021/cr10_startup/&#34;&gt;Completed Here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PrusaSlicer profile for the CR-10 MAX - Completed, Not Published&lt;/li&gt;
&lt;li&gt;Power control and monitoring - Not Started&lt;/li&gt;
&lt;li&gt;HomeAssistant integration, including better notifications including which printer is done (currently my notifications assume &amp;lsquo;columbia&amp;rsquo; is done) - In Progress&lt;/li&gt;
&lt;li&gt;LED status indicators - Not Started&lt;/li&gt;
&lt;li&gt;Camera mount for the wide angle camera - &lt;a href=&#34;http://localhost:1313/posts/2021/cr10_camera/&#34;&gt;Completed Here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Camera mount for the nozzle camera - Not Started&lt;/li&gt;
&lt;li&gt;Dealing with the lack of USB power/isolation of the Creality printers (The printer controller and LCD will stay on powered by the USB port) - Not Started&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most notably, I will not be building a box for this printer at this point in time.&lt;/p&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project. All of my design files are licensed Creative Commons CC-BY-SA.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.creality.com/goods-detail/cr-10-max-3d-printer&#34;&gt;Creality CR-10 MAX Printer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Raspberry Pi Model 3 B - I like &lt;a href=&#34;https://www.adafruit.com/product/3055&#34;&gt;Adafruit&lt;/a&gt;, but the Pi&amp;rsquo;s are often out of stock, so shop around&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fulament.com/collections/fula-flex-2-0/products/fula-flex-2-0&#34;&gt;Fula-Flex 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://tiny-machines-3d.myshopify.com/pages/resourcepagecr10max&#34;&gt;Tiny Machines 3D&amp;rsquo;s Marlin Firmware for CR-10 MAX&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Bitscope Server as a Raspberry Pi Systemd Service</title>
      <link>https://www.apalrd.net/posts/2021/bitscope_server/</link>
      <pubDate>Thu, 18 Nov 2021 10:31:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/bitscope_server/</guid>
      <description>Bitscope makes some low-cost USB logic analyers and low bandwidth oscilloscopes. Since I am a computer engineer and primarily work in the digital domain, this is adequate for a lot of my projects, and I&amp;rsquo;ve had a Bitscope Mini for a few years now. I think there are better options available on the market now that weren&amp;rsquo;t back when I bought it, but I&amp;rsquo;m sticking with the tools I already own.</description>
      <content>&lt;p&gt;Bitscope makes some low-cost USB logic analyers and low bandwidth oscilloscopes. Since I am a computer engineer and primarily work in the digital domain, this is adequate for a lot of my projects, and I&amp;rsquo;ve had a Bitscope Mini for a few years now. I think there are better options available on the market now that weren&amp;rsquo;t back when I bought it, but I&amp;rsquo;m sticking with the tools I already own. To reduce workspace cable clutter with my laptop on the bench, I decided to use a Raspberry Pi to run Bitscope Server. They have a server version of the sofwtare with builds for armv7 linux, but it doesn&amp;rsquo;t set itself up as a linux systemd service and doesn&amp;rsquo;t run on boot, and is honestly kinda terrible. Today, I&amp;rsquo;m going to go through the whole setup process to get it working on a Pi 2B.&lt;/p&gt;
&lt;h2 id=&#34;prepare-the-pi&#34;&gt;Prepare the Pi&lt;/h2&gt;
&lt;p&gt;Start by flashing an SD card with the latest &lt;a href=&#34;https://www.raspberrypi.com/software/operating-systems/&#34;&gt;Raspberry Pi OS&lt;/a&gt;, Lite version (no desktop) is fine. I use &lt;a href=&#34;https://www.balena.io/etcher/&#34;&gt;Etcher&lt;/a&gt; for this. After Etcher is done, remove and re-insert the card and a partition called BOOT should show up, as well as a partition that your computer may not be able to read (DON&amp;rsquo;T let Windows format it, just leave it alone). Create a new file in BOOT called &amp;lsquo;ssh&amp;rsquo; with no extension. It doesn&amp;rsquo;t need any contents, it just has to be there to tell the OS it should enable the SSH server for us (so we don&amp;rsquo;t need to connect a display and keyboard to get started).&lt;/p&gt;
&lt;p&gt;Next we do the usual to get a Pi ready. Find the IP address (I look at my router&amp;rsquo;s DHCP leases, but it might also show up as raspberrypi.local) and SSH into it. Default username is pi, password is raspberry. We have a few things to do as general housekeeping:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Change the default password&lt;/li&gt;
&lt;li&gt;Change the time zone&lt;/li&gt;
&lt;li&gt;Change the hostname&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All of these are cone with raspi-config&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo raspi-config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Password and Hostname are both under the first menu, System Options. Set Password to anything you&amp;rsquo;ll remember. Then go back to the System Options menu to change the hostname. You need to change it from &amp;lsquo;raspberrypi&amp;rsquo; so you don&amp;rsquo;t have issues in the future with a bunch of raspberry pi&amp;rsquo;s all trying to call themselves raspberrypi.local, preventing you from finding the right one. It&amp;rsquo;s also good practice to avoid hostname collisions on a network, although it isn&amp;rsquo;t strictly required. I named mine &amp;lsquo;bitscope&amp;rsquo;. If you want to enable WiFi on your Pi (I&amp;rsquo;m using wired Ethernet), you can also set it under System Options&lt;/p&gt;
&lt;p&gt;The final change is the time zone. Raspberry Pi OS defaults to UTC time. This isn&amp;rsquo;t necessarily a problem unless you have an app which depends on the local time, but it&amp;rsquo;s good practice to change it anyway in case you install something that does care about local time. This option is under Localization. First, choose your geographic area, then any city on the list in the same time zone as you. Once you are done, click Finish, and let it reboot for you.&lt;/p&gt;
&lt;h2 id=&#34;install-bitscope-server&#34;&gt;Install Bitscope Server&lt;/h2&gt;
&lt;p&gt;Bitscope provides a small help page on &lt;a href=&#34;https://www.bitscope.com/blog/DL/?p=DL15A&#34;&gt;Bitscope Server&lt;/a&gt;, but it isn&amp;rsquo;t much. You have to go to the downloads page to get the right .deb file from the &lt;a href=&#34;http://my.bitscope.com/download/?p=download&#34;&gt;Downloads Page&lt;/a&gt;. It&amp;rsquo;s odd that they have no binaries for Generic Linux, but they have i386 and amd64 for Raspbian Debian.. but we need Raspbian Debian and ARMv7. No ARMv8, sorry. Before you go any further, SSH into the Pi again to be ready to download the image.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;re there, check the box for Bitscope Server and click Download. It&amp;rsquo;ll take you to a page with the download link to the deb. Right click on the link, and copy it. Now, go back to the SSH session and type &amp;lsquo;wget &amp;rsquo; and then paste the link you copied. In my case, I ran this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wget http://bitscope.com/download/files/bitscope-server_1.0.FK26A_armhf.deb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need to manually install the deb using dpkg. Adjust this command if your filename is different:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo dpkg --install bitscope-server_1.0.FK26A_armhf.deb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should install. If it gives you errors, you either got the wrong architecture (make sure it&amp;rsquo;s not i386 or amd64), or you are running a 64-bit OS (ARMv8). The good news is that, even on Pi&amp;rsquo;s which support ARMv8, Raspberry Pi OS is currently (as of 2021) booting in 32-bit mode by default on all Pi&amp;rsquo;s.&lt;/p&gt;
&lt;p&gt;Finally, we can try to run the server. It outputs nothing unless you add -v for verbose output.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bitscope-server -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we run the help, it&amp;rsquo;s clearly not really designed to run on UNIX based systems at all. It has no systemd service out of the box, it has the option to daemonize (which just makes it disappear from the terminal, we still need to launch and control it), and the install/uninstall options are Windows only (so why even include them in the help on UNIX?).&lt;/p&gt;
&lt;h2 id=&#34;writing-a-systemd-service-for-bitscope-server&#34;&gt;Writing a Systemd service for Bitscope Server&lt;/h2&gt;
&lt;p&gt;Systemd shouldn&amp;rsquo;t be intimidating, but I see a lot of hacks around the internet for getting things to start on boot. By writing a service, systemd will take care of all of that for us. Referring to my &lt;a href=&#34;http://localhost:1313/posts/2021/systemd/&#34;&gt;cheat-sheet on systemd service files&lt;/a&gt;, I first find where the binary is&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;which bitscope-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it tells us&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/bin/bitscope-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So now we can create the service file and edit it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo touch /etc/systemd/system/bitscope.service
sudo chmod 664 /etc/systemd/system/bitscope.service
sudo nano /etc/systemd/system/bitscope.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The contents of the file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=Bitscope Server
After=network-online.target

[Service]
ExecStart=/usr/bin/bitscope-server
StandardOutput=null
Restart=always

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save and exit, then reload the daemons, start the service, and enable it to auto-start&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl start bitscope
sudo systemctl enable bitscope
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can view the status&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl status bitscope
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This bitscope-server command is really poorly behaved for a server process. Without -v, it outputs nothing at all describing what it&amp;rsquo;s doing, and with or without -v, it will continuously read stdin checking for ENTER to quit, and then it asks for a y or n to quit. When run as a systemd service, stdin is null, and it still reads from it anyway and interprets this failure as an ENTER, so it asks over and over and over to type Y or N to quit. The best solution to this is to set the standard output also null, so it doesn&amp;rsquo;t fill any log files with garbage. You can still check the status and it will report any errors that systemd sees, as well as the status of the process and if it quit on its own.&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;The Bitscope software is a mess. The list of platforms they offer downloads for really terrifies me as to their software development process. They have Windows x86 and x64 (makes sense), macOS x86 only (wtf?), Raspberry Pi Raspbian x86, x64, and ARMv7, and generic Linux x64 (Not sure who&amp;rsquo;s running Raspbian on x86 or x64). Their current release of MacOS software is still 32-bit only (which Apple deprecated in 2012 and removed support for entirely in 2018), because they wrote their entire MacOS system using the Carbon API, which dates back to the early days of OS X as a compatibility layer for Mac OS 9 apps and was never intended to be used for native OS X apps. It was also deprecated in 2007 and support was removed entirely in 2018, so no modern macs can run their software.&lt;/p&gt;
&lt;p&gt;In addition to all of the weird platform problems, the server software is really designed to run as a terminal program and as you can see by the continuous reading for &amp;lsquo;press ENTER to quit&amp;rsquo;, its very poorly behaved on Linux. Maybe it does better in a Windows environment, but I don&amp;rsquo;t expect anyone is going to want to deal with the overhead of Windows for a little scope server.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Upgrading my Zigbee network with the zig-a-zig-ah! (zzh!)</title>
      <link>https://www.apalrd.net/posts/2021/zigbee_upgrade/</link>
      <pubDate>Fri, 12 Nov 2021 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/zigbee_upgrade/</guid>
      <description>I currently have a TI CC2531 based Controller for Zigbee2MQTT, and the performance is poor. Based on how much my Zigbee network is expanding with the really low cost of Zigbee hardware (despite my preference for Z-wave for reliability when it counts), I&amp;rsquo;m upgrading my Controller to the zzh! from electrolama. The new controller is based on the CC2652 and has a decent external antenna, and should hopefully improve my awful Zigbee reception and reliance on IKEA repeaters to get any signal at all.</description>
      <content>&lt;p&gt;I currently have a TI CC2531 based Controller for Zigbee2MQTT, and the performance is poor. Based on how much my Zigbee network is expanding with the really low cost of Zigbee hardware (despite my preference for Z-wave for reliability when it counts), I&amp;rsquo;m upgrading my Controller to the &lt;a href=&#34;https://www.tindie.com/products/electrolama/zzh-cc2652r-multiprotocol-rf-stick/&#34;&gt;zzh! from electrolama&lt;/a&gt;. The new controller is based on the CC2652 and has a decent external antenna, and should hopefully improve my awful Zigbee reception and reliance on IKEA repeaters to get any signal at all.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Network map Before&#34; src=&#34;https://www.apalrd.net/posts/2021/zigbee_upgrade/before.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;As you can see in the &amp;lsquo;Before&amp;rsquo; network diagram, most of my devices don&amp;rsquo;t want to connect directly to the controller, and those that do get very low link quality index. The laundry_temp_humid_sensor is physically located in the same room only a few feet away from the CC2531 and only gets an lqi of 68, while the andrew_bed_motion is only one wall over (~10 feet and 1 wall in between) and gets an lqi of 5. That&amp;rsquo;s really terrible. The first repeater (bed_andrew_repeater) is actually plugged in to the same power strip as the CC2531&amp;rsquo;s raspberry pi and is about 3 feet away, so the poor antenna on the CC2531 is obvious when we see how many devices want that repeater instead of the controller.&lt;/p&gt;
&lt;p&gt;Back when I bought my &lt;a href=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/&#34;&gt;IKEA Blinds&lt;/a&gt;, I also bought the CC2531 pre-flashed with controller firmware to use in my Zigbee network, but due to life getting in the way I didn&amp;rsquo;t end up setting up that network until a few months ago. Back then, the CC2531 was the recommended dongle from Zigbee2MQTT. In the time since, the CC2531 became less recommended compared to the CC2652, and now it&amp;rsquo;s listed as NOT recommended (but still supported). The zzh! helps support the Zigbee2MQTT developer somewhat, and I felt comfortable selecting that dongle for my network. I was fully aware that I could possibly have to re-pair everything, although migrating from the CC2531 to CC2652 sometimes does not require re-pairing if all goes well.&lt;/p&gt;
&lt;p&gt;The first step in the transition is to flash my new CC2652-based zzh! with the correct firmware. The firmware primarily used with Zigbee2MQTT and open-hardware dongles is the open-source &lt;a href=&#34;https://github.com/Koenkk/Z-Stack-firmware&#34;&gt;Z-Stack-firmware&lt;/a&gt;. I then followed &lt;a href=&#34;https://electrolama.com/radio-docs/flash-cc-bsl/&#34;&gt;Electrolama&amp;rsquo;s Guide&lt;/a&gt; to flash the dongle. Not wanting to deal with a Windows-only flashing utility from TI, I chose this option (with the open-source Python utility) despite the Windows version having a GUI.&lt;/p&gt;
&lt;p&gt;Next step is to backup the configuration. I ran the &lt;a href=&#34;https://www.apalrd.net/posts/2021/zigbee_bakcup/&#34;&gt;backup script&lt;/a&gt; manually, then renamed the file it generated so that particular backup will persist forever in case I need to roll back. After that, I shut down the Pi, replaced the USB dongle, and booted it back up.&lt;/p&gt;
&lt;p&gt;When I rebooted, I had to make a few configuration changes to zigbee2mqtt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The new dongle was at /dev/ttyUSB0 instead of /dev/ttyACM0&lt;/li&gt;
&lt;li&gt;The new dongle requires &amp;lsquo;rtscts: false&amp;rsquo; in the advanced section of the yaml&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After making those changes (with the service stopped, since it will overwirite configuration.yaml on its own), I started the service and it seemed to work fine. Devices in my network re-appeared as available in Home Assistant. I then ran a network map and got&amp;hellip; odd results. No device links, just a cloud of devices. I went through the house and found out that most of my devices appeared to be working (motion lights followed me, etc.) but they still don&amp;rsquo;t show up in the link map.&lt;/p&gt;
&lt;p&gt;I did a new backup and gave it a day to get over itself. Zigbee lacks a way to force neighbor updates like Z-wave&amp;rsquo;s &amp;lsquo;Heal&amp;rsquo; function, since you basically just have to hope the devices discover new neighbors and links when they wake up and try to communicate. I had a few stubborn devices - two Aqara door switches on my south and center garage doors (but not the north!), and the basement temperature + humidity sensor. I eventually gave up and re-paired them, which was a bit of a hassle.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Network map after settling&#34; src=&#34;https://www.apalrd.net/posts/2021/zigbee_upgrade/after.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;Was the upgrade worth it? The CC2652 supports 50 direct children, while the CC2531 only supported 20. Of course, you can have more than that if your nodes are connected via routers. The devices which are now direct children of the CC2652 seem to have better signal strength than before, and many of them are significantly further from the controller than the children of the CC2531. Overall, I&amp;rsquo;d say you should definitely start with a CC2652 or upgrade as soon as possible, so you don&amp;rsquo;t start running into the limitations of the CC2531 when you have a larger network that&amp;rsquo;s more hassle to reconfigure.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>WLED Lighting for my Desk</title>
      <link>https://www.apalrd.net/posts/2021/bedroom_wleds/</link>
      <pubDate>Mon, 08 Nov 2021 11:06:32 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/bedroom_wleds/</guid>
      <description>Today I finished working on new lighting for my closet office.
Last year I renovated my bedroom, to fit my computer desk better. I don&amp;rsquo;t need a massive closet and traditional American McMansions require a large closet space with plenty of wasted space in every single bedroom, so I decided to take the closet doors off to expand my bedroom and put my desk into the closet. After some network and power wiring work, I had a pretty comfortable expansion of my desk space and cleared the center of my room for VR gaming.</description>
      <content>&lt;p&gt;Today I finished working on new lighting for my closet office.&lt;/p&gt;
&lt;p&gt;Last year I renovated my bedroom, to fit my computer desk better. I don&amp;rsquo;t need a massive closet and traditional American McMansions require a large closet space with plenty of wasted space in every single bedroom, so I decided to take the closet doors off to expand my bedroom and put my desk into the closet. After some network and power wiring work, I had a pretty comfortable expansion of my desk space and cleared the center of my room for VR gaming.&lt;/p&gt;
&lt;h2 id=&#34;the-story&#34;&gt;The Story&lt;/h2&gt;
&lt;p&gt;That was last year. The downside I&amp;rsquo;ve found is that the closet doesn&amp;rsquo;t have a light. Sometimes this isn&amp;rsquo;t a problem, but if I want to use my desk for things other than computer work, I really need better lighting. So, I decided to use individually addressable RGBW LED tape. RGBW tape is similar to RGB tape, but with an extra white channel with a more broad spectrum light, to improve the CRI of the white light. An expert on this topic is Quindor of &lt;a href=&#34;https://quinled.info/&#34;&gt;QuinLED&lt;/a&gt;. So, I followed his site and watched some of his videos to decide exactly what I want.&lt;/p&gt;
&lt;p&gt;Since my closet door opening isn&amp;rsquo;t that big, I only need 1.5m of tape. Since I&amp;rsquo;m running a short tape, I don&amp;rsquo;t need higher voltages, and the voltage drop across a 5V tape this short with the AC power supply a few feet away is reasonable, so I went with a 5V LED for simplicity (and I had some fairly beefy 5V AC adapters already). The LED tape came with a connector, and I soldered that to 5&amp;rsquo; of wire to mount the QuinLED down near the ground. I got the IP30 LEDs since they dissipate heat better with no enclosure or potting, and are easier to work with. I used the built-in tape to secure 1.5m of the strip to the back of the closet door, so it faces the angled ceiling of the closet to bounce light at my desk. I taped the wire to the wall around the back of the closet, and bundled it with wires I was already running up the closet wall (Ethernet and HDMI to my TV). I connected the QuinLED (wired Ethernet model), and a 5V 10A power supply I already had. It&amp;rsquo;s a bit overkill, with the full RGB white + dedicated white at full brightness, the strip is estimated to draw around 4.9A.&lt;/p&gt;
&lt;p&gt;I found the WLED on the network by looking at DHCP leases in my router, connected to it, and set it up for my strip. I&amp;rsquo;m using 1.5m of 60 LED/m strip, which is 90 LEDs. They are RGBW (with a natural white channel), using SK6812 family of LEDs. I ran through all of the colors to make sure the configuration was correct, and was amazed at how easy to use the WLED software is. Home Assistant found the WLED through Discovery, and I added it and configured it to be part of my bedroom. It exposes most of the WLED functionality through the HA integration, which is excellent.&lt;/p&gt;
&lt;h2 id=&#34;results&#34;&gt;Results&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;Installation&#34; src=&#34;https://www.apalrd.net/posts/2021/bedroom_wleds/led_mount.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;Click on this image for an animation:
&lt;a href=&#34;https://www.apalrd.net/posts/2021/bedroom_wleds/output.gif&#34;&gt;&lt;img alt=&#34;Static image of LEDs&#34; src=&#34;https://www.apalrd.net/posts/2021/bedroom_wleds/led_orange.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;project-files-and-parts-list&#34;&gt;Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;I didn&amp;rsquo;t create any of the software for this project. Here are links to the hardware and software developers who made this possible.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LED Tape - I bought SK6812, RGBNW (Natural White), 5m, 60 LED/m, IP30 - &lt;a href=&#34;https://s.click.aliexpress.com/e/_9QfrXJ&#34;&gt;AliExpress Affiliate Link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;QuinLED DigUno - I bought it from DrZZs with the Ethernet add-on board - &lt;a href=&#34;https://quinled.info/pre-assembled-quinled-dig-uno/&#34;&gt;Quindor&amp;rsquo;s Site&lt;/a&gt; or &lt;a href=&#34;https://drzzs.com/shop/dig-uno-diy-rgb-led-controller-w-wled-preassembled/&#34;&gt;DrZZs Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;WLED Firmware - pre-installed if you buy the QuinLED above - &lt;a href=&#34;https://github.com/Aircoookie/WLED&#34;&gt;Github&lt;/a&gt;
Some links to products may be affiliate links, which may earn a commission for me.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Laundry Finished Notification</title>
      <link>https://www.apalrd.net/posts/2021/laundry_notifier/</link>
      <pubDate>Tue, 02 Nov 2021 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/laundry_notifier/</guid>
      <description>Often, when I&amp;rsquo;m focused on a task or project, I absolutely can&amp;rsquo;t think about anything else. This means that other tasks often get left unattended, possibly for hours. To reduce this, I&amp;rsquo;ve implemented a system in Home Assistant to notify me when either the washer or dryer are finished running. It&amp;rsquo;s a pretty simple automation, but it&amp;rsquo;s this kind of useful life-improvements that really make home automation worthwhile.
The Hardware I have a gas dryer (not ideal, but I&amp;rsquo;ll get a heat pump in the next house) and normal electric washer.</description>
      <content>&lt;p&gt;Often, when I&amp;rsquo;m focused on a task or project, I absolutely can&amp;rsquo;t think about anything else. This means that other tasks often get left unattended, possibly for hours. To reduce this, I&amp;rsquo;ve implemented a system in Home Assistant to notify me when either the washer or dryer are finished running. It&amp;rsquo;s a pretty simple automation, but it&amp;rsquo;s this kind of useful life-improvements that really make home automation worthwhile.&lt;/p&gt;
&lt;h2 id=&#34;the-hardware&#34;&gt;The Hardware&lt;/h2&gt;
&lt;p&gt;I have a gas dryer (not ideal, but I&amp;rsquo;ll get a heat pump in the next house) and normal electric washer. Both of them share a single power outlet on a 20A circuit, all fairly standard in the US. I do have power monitoring at the breaker panel via the &lt;a href=&#34;https://www.apalrd.net/projects/2020/power_meter/&#34;&gt;Energy Monitor Project&lt;/a&gt;, but that includes power consumed by the washer, dryer, as well as some networking equipment which resides in the laundry room (including the Zigbee master, Z-Wave master, and 433Mhz receiver, a network switch, an audio amplifier for the deck speakers, and two Raspberry Pi&amp;rsquo;s). The washer and dryer use quite a bit of power, but I still need better resolution than this.&lt;/p&gt;
&lt;p&gt;Thankfully, they both use less than 10A and plug into standard US 120V wall plugs, so I can just get two Sonoff S31&amp;rsquo;s and call it a day (I had one leftover from &lt;a href=&#34;https://www.apalrd.net/posts/2021/tasmota_day/&#34;&gt;Tasmota Day&lt;/a&gt; and had to get a second). I then added them to Home Assistant, including all of the power monitoring channels, configured them to turn on automatically (PowerOnState 1), and send telemetry more often (TelePeriod 20). Once that was all done, I ran a cycle on each to establish how much power each consumed.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Power Graph&#34; src=&#34;https://www.apalrd.net/posts/2021/laundry_notifier/laundry_power.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, the washer has a portion of the cycle wher it uses very little power, as it fills initially and again during the rinse cycle. I need to set the threshold very carefully to detect when it&amp;rsquo;s actually off (and just drawing standby power) versus when only the water valve is on. It seems like the water valve is on at 8W and the control power alone is 2W, so a threshold of 5W and a minimum time of 2-5 minutes is probably adequate. The dryer is much easier, it uses a lot of power for the entire cycle, so the threshold is more agressive at 10W for 1 minute.&lt;/p&gt;
&lt;h2 id=&#34;the-notifier&#34;&gt;The Notifier&lt;/h2&gt;
&lt;p&gt;Notifications in Home Assistant are really easy. You call a service on the notifier entity, which in this case is an iphone.&lt;/p&gt;
&lt;p&gt;If you just want to copy it, here&amp;rsquo;s the yaml for the whole automation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Laundry Finished Notification&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;description&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Notify when laundry is finished&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;trigger&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;numeric_state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;sensor.laundry_dryer_power_w&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Dryer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;below&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;10&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;for&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;hours&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;minutes&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;seconds&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;milliseconds&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;numeric_state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;sensor.laundry_washer_power_w&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Washer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;below&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;5&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;for&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;hours&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;minutes&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;seconds&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;milliseconds&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;condition&lt;/span&gt;: []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;action&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;notify.notify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;data&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;title&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Laundry Complete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;message&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{{ trigger.id }} Has Finished&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;single&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can add as many triggers as you want, it just passes &amp;lsquo;{Trigger ID} Has Finished&amp;rsquo; as the notification value. So, set the Trigger ID to the text you want it to say when it notifies you. You can also specify a single device instead of notify.notify if you want to alert just one phone.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>3D Printer Nozzle Camera</title>
      <link>https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/</link>
      <pubDate>Mon, 25 Oct 2021 20:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/</guid>
      <description>After buying some cheap USB boroscope cameras to use as an actual boroscope for home renovation projects, I decided to buy one with a flexible cable to mount near the nozzle of my Prusa i3 MK3s to get a time-lapse of the nozzle during the printing process. Watching the first layer closely during a print can show failures early, since most failures are due to bed adhesion or other first-layer problems.</description>
      <content>&lt;p&gt;After buying some cheap USB boroscope cameras to use as an actual boroscope for home renovation projects, I decided to buy one with a flexible cable to mount near the nozzle of my Prusa i3 MK3s to get a time-lapse of the nozzle during the printing process. Watching the first layer closely during a print can show failures early, since most failures are due to bed adhesion or other first-layer problems. Keeping the camera out of the print volume while still getting a good view of the nozzle and print was challenging, but I ended up with a cool solution that I&amp;rsquo;m really proud of, and the view is fantastic.&lt;/p&gt;
&lt;h2 id=&#34;camera-mounting&#34;&gt;Camera Mounting&lt;/h2&gt;
&lt;p&gt;I started by holding the camera up to the printer and measuring where I wanted to mount it. The Prusa i3 MK3S has a bracket which goes off the back of the extruder assembly which anchors the flexible cables to the extruder. The cables from the extruder motor, PINDA probe, filament sensor, and fans run over the top of the anchor, and the cables from the hotend heater and thermistor run over the bottom of the anchor. I decided to make a wedge to sit against the bottom of the anchor, allowing me to use the well designed zip tie holes to securely mount the camera. The hotend wires can move along the side of the anchor, leaving space for the camera. I held up the camera in place with the camera view open on my laptop and decided the slope I want (1/4&amp;quot; over the length of the camera), then measured the dimensions of the camera with calipers to make a mount with a half circle for the camera to sit in.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Camera Mount in PrusaSlicer&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/bracket_sliced.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Bracket model in PrusaSlicer&lt;/div&gt;
&lt;p&gt;After running the tiny part on the printer, I decided to tape the camera to the bracket, since the camera has a smooth metal finish and zip ties would not securely hold it against rotation. To align the camera, I set the bracket on the table (upside-down), placed a square object in front of it, and rotated the camera around by its cable until the square object was aligned to the image upside-down (since the bracket will be flipped when mounted on the printer). I then wrapped the camera and bracket in masking tape, careful to maintain alignment.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Camera Mount 1&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/nozzlecam_mount1.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Camera and Bracket zip-tied to Prusa&#39;s cable anchor&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Camera Mount 2&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/nozzlecam_mount2.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Hotend cables out of the way&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Camera Mount 3&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/nozzlecam_mount3.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;View port of camera (you have to read further for the camera&#39;s view)&lt;/div&gt;
&lt;h2 id=&#34;using-octolapse-to-record-two-cameras&#34;&gt;Using OctoLapse to record two cameras&lt;/h2&gt;
&lt;p&gt;Since I now have two cameras, I&amp;rsquo;d like to use Octolapse to record both of them. I installed OctoLapse through the OctoPrint plugin manager. I&amp;rsquo;m starting from the config I&amp;rsquo;ve been building up in the &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/&#34;&gt;OctoPi Project&lt;/a&gt; and &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_power/&#34;&gt;3D Printer Power Project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once it was installed, I setup two new cameras for the Ethernet camera and the built-in OctoPi camera, which is now the nozzle camera. I renamed the default camera to NozzleCam, and created an entirely new camera for the Ethernet Cam. I didn&amp;rsquo;t bother setting the stream address, it&amp;rsquo;s only used in the web UI and I usually use Home Assistant to watch the camera anyways.&lt;/p&gt;
&lt;p&gt;OctoLapse doesn&amp;rsquo;t use the default timelapse temp folder to store its temporary files, which leads to temporary files being stored on the SD card of the Pi. This is not ideal, so we need to add another autofs mount for the folder /home/pi/.octoprint/data/octolapse so it can keep its stuff on the network. The temp data doesn&amp;rsquo;t really need to be on the network, but the NAS can handle write wear much better than the SD card of the Pi. OctoLapse was very angry mounting the entire octolapse folder on the network, since it seems to try to chmod files after creating them (even though this is unnecessary, it doesn&amp;rsquo;t have permissions to chmod a folder it doesn&amp;rsquo;t own), so I ended up mounting the /mnt/printer (the existing printer mount) with noperm (so Octolapse can chmod files it doesn&amp;rsquo;t own and the permissions will be ignored) and created a symbolic link from the octolapse temp folder to a folder in /mnt/printer. I also forwarded the timelapse folder with a similar method. Overall, Octoprint is not happy with the autofs mounts, and keeps trying to revert to default folder paths, so maybe it&amp;rsquo;s a better approach to symlink them anyway instead of using the settings file to change them to the paths I want.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ln -s /mnt/printer/octolapse/tmp ~/.octoprint/data/octolapse/tmp
ln -s /mnt/printer/timelapse ~/.octoprint/timelapse
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;other-quirks&#34;&gt;Other Quirks&lt;/h2&gt;
&lt;p&gt;The camera has built-in lighting, and there&amp;rsquo;s a small box midline in the cable with a knob to adjust the LED intensity. However, there&amp;rsquo;s no way to turn it off, or control it from the Pi. My solution to this is to disable USB power when the printer is turned off, which opens a whole can of worms. &lt;a href=&#34;https://www.apalrd.net/posts/2021/3d_printer_uhubctl/&#34;&gt;I wrote a short blog post about my solution here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Essentially, uhubctl works great to turn on/off the power to the LEDs, but it also turns off power to the camera itself, so the webcamd streamer needs to be restarted when the camera returns. It also cuts power to the printer, which isn&amp;rsquo;t powered over USB, but powers its USB isolation from the USB side, so the printer serial port drops out as well. When I re-enable power, it takes a few seconds for the USB UART for the printer to return as well, so I extended the connection delay (from when the power is turned on the printer and USB to when the printer connection is attempted) to 15 seconds, and this seems to work adequately.&lt;/p&gt;
&lt;h2 id=&#34;result&#34;&gt;Result&lt;/h2&gt;
&lt;p&gt;Click on the thumbnail to view the full video on Youtube
&lt;a href=&#34;https://youtu.be/om2REdvjcFg&#34;&gt;&lt;img alt=&#34;Youtube Link&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/thumb.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project. All of my design files are licensed Creative Commons CC-BY-SA. As this project uses files created by other authors as examples, please read their licenses as well.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://s.click.aliexpress.com/e/_AF9BmD&#34;&gt;Camera I Used&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/NozzleCamBracket.amf&#34;&gt;Wedge Mount Design Files (AMF Format)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/NozzleCamBracket.FCStd&#34;&gt;Wedge Mount Design Files (FreeCAD Originals)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.3dbenchy.com/&#34;&gt;3DBenchy Test Print&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/DrLex0/print3D-FlexiRex&#34;&gt;Flexy Rex Test Print&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.thingiverse.com/thing:937740&#34;&gt;Low Poly Fox Test Print&lt;/a&gt;
Some links to products may be affiliate links, which may earn a commission for me.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>My First YouTube Video! And NozzleCam Project</title>
      <link>https://www.apalrd.net/posts/2021/3d_printer_video/</link>
      <pubDate>Mon, 25 Oct 2021 20:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/3d_printer_video/</guid>
      <description>Today I just published a project I&amp;rsquo;ve been working on for awhile - my 3D printer nozzle camera - and it&amp;rsquo;s the first project I&amp;rsquo;ve made a corresponding video for! I built this nozzle camera mount to carefully watch the first layer of 3D prints, since most failures happen early on due to poor first layer adhesion or related issues. Keeping the camera out of the print volume while still getting a good view of the nozzle and print was challenging, but I ended up with a cool solution that I&amp;rsquo;m really proud of, and the view is fantastic.</description>
      <content>&lt;p&gt;Today I just published a project I&amp;rsquo;ve been working on for awhile - &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/&#34;&gt;my 3D printer nozzle camera&lt;/a&gt; - and it&amp;rsquo;s the first project I&amp;rsquo;ve made a corresponding video for! I built this nozzle camera mount to carefully watch the first layer of 3D prints, since most failures happen early on due to poor first layer adhesion or related issues. Keeping the camera out of the print volume while still getting a good view of the nozzle and print was challenging, but I ended up with a cool solution that I&amp;rsquo;m really proud of, and the view is fantastic. I&amp;rsquo;m super excited about the video release, and want to share it here on the blog as well! I hope you enjoy the video. Here it is. Click on the thumbnail to view it on YouTube.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/om2REdvjcFg&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_nozzlecam/thumb.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>How Much Power does a 3D Printer Consume?</title>
      <link>https://www.apalrd.net/projects/2021/3d_printer_power/</link>
      <pubDate>Sun, 24 Oct 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2021/3d_printer_power/</guid>
      <description>I have a Prusa i3 MK3S 3D printer, and I use it for many projects I post here. I want to know roughly how much power it consumes while printing, to get a feel for both the peak power consumption of the printer (to, say, size an off-grid power system) and energy consumed for an average print. I know the cost of filament is pretty low for most projects, but I don&amp;rsquo;t know the cost of energy (or wear on the printer).</description>
      <content>&lt;p&gt;I have a Prusa i3 MK3S 3D printer, and I use it for many projects I post here. I want to know roughly how much power it consumes while printing, to get a feel for both the peak power consumption of the printer (to, say, size an off-grid power system) and energy consumed for an average print. I know the cost of filament is pretty low for most projects, but I don&amp;rsquo;t know the cost of energy (or wear on the printer). This project seeks to remedy that, using a &lt;a href=&#34;https://itead.cc/product/sonoff-s31/&#34;&gt;Sonoff S31&lt;/a&gt; power monitoring smart plug flashed with &lt;a href=&#34;https://tasmota.github.io/docs/&#34;&gt;Tasmota&lt;/a&gt; firmware. I also set up this smart plug to be controlled by OctoPrint as an added bonus.&lt;/p&gt;
&lt;h2 id=&#34;flashing-and-configuring-tasmota&#34;&gt;Flashing and Configuring Tasmota&lt;/h2&gt;
&lt;p&gt;I flashed my Sonoff S31 on my &lt;a href=&#34;https://www.apalrd.net/posts/2021/tasmota_day/&#34;&gt;Tasmota Day&lt;/a&gt;. By the end of the &amp;lsquo;day&amp;rsquo;, I had a number of S31&amp;rsquo;s which had Tasmota flashed, and which were configured with the correct WiFi network and module type, but no other configuration.&lt;/p&gt;
&lt;p&gt;The first step is to configure the MQTT broker. I am using the same broker as Home Assistant, although in this case commands will come from Octoprint instead of HA. Start by finding the IP address (I look on my router&amp;rsquo;s DHCP leases for new Tasmota devices), and connect to it over HTTP. It should show up with a big &amp;lsquo;ON&amp;rsquo; or &amp;lsquo;OFF&amp;rsquo; as well as a bunch of power measurement numbers, a toggle button, and configuration buttons. Click &amp;lsquo;Configuration&amp;rsquo;, then &amp;lsquo;Configure MQTT&amp;rsquo;, and enter the broker information. I don&amp;rsquo;t like how Tasmota pollutes the root namespace in MQTT with tele, cmnd, etc. so I change the default topic structure to be &amp;lsquo;raw/%topic%/%prefix%/, which ends up with a topic like raw/tasmota_123ABC/stat/POWER. I set this structure for my Tasmota devices when I was newer to MQTT, but now I would have chosen &amp;rsquo;tasmota/%topic%/%prefix%/&amp;rsquo;, so tasmota devices get their own folder in the namepace, followed by each individual device. This is more of a personal opinion on how to structure MQTT topics. Save configuration here.&lt;/p&gt;
&lt;p&gt;Another configuration which is optional is to change the name. It doesn&amp;rsquo;t need a name, but if you set it, it will show the name on the main screen and in the HTML title. To set this, go to Configuration -&amp;gt; Configure Other and set Device Name to whatever is meaningful to you. If you have a bunch of Tasmota devices, having the name listed on the top of the page can really help you ensure that you&amp;rsquo;re connected to the correct one.&lt;/p&gt;
&lt;p&gt;Next, we need to change the telemetry period. By default, Tasmota on the S31 will send power readings every 300 seconds. I&amp;rsquo;d like more data, and the backend can deal with all that data, so I bumped it up to 30 seconds. From the main screen, click Console. Now, we need to change the value &amp;lsquo;TelePeriod&amp;rsquo; to the number of seconds we would like&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TelePeriod 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should return a JSON string of the new value, like &amp;lsquo;{&amp;ldquo;TelePeriod&amp;rdquo;:30}&amp;rsquo;. If it still says 300, you didn&amp;rsquo;t type it right. No equals, no comma, just the command and value.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-octoprint-plugins&#34;&gt;Setting Up OctoPrint Plugins&lt;/h2&gt;
&lt;p&gt;We have a bit of a dance in OctoPrint with plugins and subplugins. In the end, we need all of these plugins installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MQTT&lt;/li&gt;
&lt;li&gt;HomeAssistant Discovery&lt;/li&gt;
&lt;li&gt;PSU Control&lt;/li&gt;
&lt;li&gt;PSU Control - MQTT&lt;/li&gt;
&lt;li&gt;MQTT for PSU Control&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of these will already be installed if you started from my &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/&#34;&gt;OctoPi Project&lt;/a&gt;. If you followed that guide, skip down to PSU Control, the first two plugins are configured identically.&lt;/p&gt;
&lt;h3 id=&#34;mqtt-plugin&#34;&gt;MQTT Plugin&lt;/h3&gt;
&lt;p&gt;Enable and configure this plugin first, by itself. This way, we can configure all of the topic prefixes before HomeAssistant Discovery messes with them. Setup your broker, topics (I used octoprint/&amp;lt;printer name&amp;gt;/ so I can add more printers later), and leave the rest of the settings as defaults.&lt;/p&gt;
&lt;h3 id=&#34;homeassistant-discovery-plugin&#34;&gt;HomeAssistant Discovery Plugin&lt;/h3&gt;
&lt;p&gt;Enable and configure this plugin second. There is nothing to configure here, other than Device Name. I suggest setting it to the name of your printer, if you have more than one printer, so they won&amp;rsquo;t conflict. It should automatically generate a Node ID.&lt;/p&gt;
&lt;p&gt;Now, you should see a new Device in Home Assistant. Feel free to do any configuration you&amp;rsquo;d like there. It&amp;rsquo;s not super important for the purposes of this project, and it&amp;rsquo;s the same as my &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/&#34;&gt;OctoPi Project&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;psu-control-psu-control-mqtt-and-mqtt-for-psu-control&#34;&gt;PSU Control, PSU Control MQTT, and MQTT for PSU Control&lt;/h3&gt;
&lt;p&gt;The naming of all of these is a bit odd. PSU Control is a plugin which allows OctoPrint to control the power supply of your printer. It relies on sub-plugins to provide different interfaces to PSU control switches, and provides a UI and common startup/shutdown settings for all of them. In our case, the sub-plugin we are using is PSU Control - MQTT which sends the PSU on/off messages and returns status via MQTT. The third plugin, MQTT for PSU Control, is not a sub-plugin which provides a PSU interface, but instead provides access to the PSU Control switch via Home Assistant over MQTT.&lt;/p&gt;
&lt;h3 id=&#34;psu-control&#34;&gt;PSU Control&lt;/h3&gt;
&lt;p&gt;For PSU Control, set the Switching Method to Plugin, and select PSU Control - MQTT as the plugin. For Sensing Method, again select Plugin, and again select PSU Control - MQTT. I set the polling interval to 1 second. For Power On Options, I added a 15 second Post On Delay to allow the printer to boot up, and enabled Connect when powered on. Finally, I set Power Off Options to turn off after idle for 30 minutes, and to disconnect from the printer.&lt;/p&gt;
&lt;h3 id=&#34;psu-control---mqtt&#34;&gt;PSU Control - MQTT&lt;/h3&gt;
&lt;p&gt;For PSU Control - MQTT, we need to set the topics of our Tasmota smart switch. Since I changed the default topics, my command topic is &amp;lsquo;raw/tasmota_049BED/cmnd/POWER&amp;rsquo; and my status topic is &amp;lsquo;raw/tasmota_049BED/stat/POWER&amp;rsquo;, with ON and OFF being the payloads for both topics. Tasmota publishes state reliably, so no need to poll for state and we can disable the &amp;lsquo;actively query for switch state&amp;rsquo; option.&lt;/p&gt;
&lt;h3 id=&#34;mqtt-for-psu-control&#34;&gt;MQTT for PSU Control&lt;/h3&gt;
&lt;p&gt;For MQTT for PSU Control, first go into the HomeAssistant Discovery plugin and copy the Node ID. Then, go into the configuration page for MQTT for PSU Control and paste this Node ID under the HomeAssistant automatic MQTT discovery heading. This will add the PSU Control switch to the existing Device created by the HomeAssistant Discovery plugin. Check &amp;lsquo;activate HomeAssistant support&amp;rsquo; and &amp;lsquo;add switch entity to existing device&amp;rsquo;, and change the Switch Name if you wish. Device Name will be inherited from HomeAssistant Discovery, since they share the same node ID and we are adding the switch to an existing device.&lt;/p&gt;
&lt;h2 id=&#34;adding-power-monitoring-to-home-assistant&#34;&gt;Adding Power Monitoring to Home Assistant&lt;/h2&gt;
&lt;p&gt;Since I&amp;rsquo;m controlling the power relay through OctoPrint, I don&amp;rsquo;t want to add it directly as a switch in Home Assistant. The PSU control integrates with Home Assistant already, so the switch is already exposed indirectly through the OctoPrint device. I just want to capture the sensor data, since OctoPrint&amp;rsquo;s plugins don&amp;rsquo;t do that.&lt;/p&gt;
&lt;p&gt;All of the sensors are numeric and exposed by Tasmota in a single JSON-encoded message, so all of them become sensor entities in Home Assistant. Therefore, we edit sensor.yaml and add each signal as a sensor. Also note that I use a different topic path than the Tasmota default, so you may need to adjust the paths (use &lt;a href=&#34;https://mqtt-explorer.com/&#34;&gt;MQTT Explorer&lt;/a&gt; if you need to find the paths).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#3D Printer Power consumption data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Columbia Power [W]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;columbia_power_w&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_049BED/tele/SENSOR&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;value_template&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{value_json[&amp;#39;ENERGY&amp;#39;][&amp;#39;Power&amp;#39;]}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;W&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;device_class&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;power&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;availability&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_049BED/tele/LWT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;payload_not_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Offline&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;payload_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Online&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Columbia Voltage&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;columbia_power_v&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_049BED/tele/SENSOR&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;value_template&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{value_json[&amp;#39;ENERGY&amp;#39;][&amp;#39;Voltage&amp;#39;]}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;V&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;device_class&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;voltage&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;availability&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_049BED/tele/LWT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;payload_not_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Offline&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;payload_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Online&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Columbia Current&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;columbia_power_i&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_049BED/tele/SENSOR&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;value_template&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{value_json[&amp;#39;ENERGY&amp;#39;][&amp;#39;Current&amp;#39;]}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;device_class&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;current&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;availability&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_049BED/tele/LWT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;payload_not_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Offline&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;payload_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Online&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Columbia Energy [kWh]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;columbia_power_kwh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_049BED/tele/SENSOR&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;value_template&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{value_json[&amp;#39;ENERGY&amp;#39;][&amp;#39;Total&amp;#39;]}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kWh&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;device_class&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;energy&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;state_class&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;total_increasing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;availability&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_049BED/tele/LWT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;payload_not_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Offline&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;payload_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Online&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Columbia Power Factor&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;columbia_power_fac&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_049BED/tele/SENSOR&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;value_template&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{value_json[&amp;#39;ENERGY&amp;#39;][&amp;#39;Factor&amp;#39;]}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;device_class&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;power_factor&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;availability&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/tasmota_049BED/tele/LWT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;payload_not_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Offline&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;payload_available&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Online&amp;#34;&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;the-print&#34;&gt;The Print&lt;/h2&gt;
&lt;p&gt;I printed a 3DBenchy for the purposes of this power test. The printer peaked at 245W during the warmup phase, averaged 92W during the print phase, and consumed just under 0.1 kWh during the roughly 1 hour print job. Home Assistant doesn&amp;rsquo;t show very many decimals and the numbers are pretty small, so the precision on that 0.1 kWh is probably +-10%. The idle consumption is also not negligible, at 10W. Leaving it on all the time would be roughly 7.2 kWh/month, which would cost around $1 (at my energy prices in 2021), purely for idling. The print doesn&amp;rsquo;t cost much in terms of energy, coming in at an energy cost of 1.3 cents (again at my energy prices in 2021). Overall, the energy expense of a single hobby 3D printer is not high enough to worry about.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Lovelace Power Graphs&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_power/powerlog.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Lovelace Graph of 3DBenchy Print Data&lt;/div&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the parts required to replicate this project. There are no design files for this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://itead.cc/product/sonoff-s31/&#34;&gt;Sonoff S31 Power Monitoring Smart Plug (NOT lite version)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.adafruit.com/product/4331&#34;&gt;USB to UART adapter (3V Power and Data) from Adafruit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://plugins.octoprint.org/plugins/mqtt/&#34;&gt;OctoPrint MQTT Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://plugins.octoprint.org/plugins/homeassistant/&#34;&gt;OctoPrint HomeAssistant Discovery Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://plugins.octoprint.org/plugins/psucontrol/&#34;&gt;OctoPrint PSU Control Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://plugins.octoprint.org/plugins/psucontrol_mqtt/&#34;&gt;OctoPrint PSU Control - MQTT Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://plugins.octoprint.org/plugins/mqtt_for_psucontrol/&#34;&gt;OctoPrint MQTT for PSU Control Plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Flexy Rex Kid-Friendly 3D Printing</title>
      <link>https://www.apalrd.net/posts/2021/flexy_rex/</link>
      <pubDate>Fri, 22 Oct 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/flexy_rex/</guid>
      <description>Flexy Rex is a 3D print that&amp;rsquo;s been circling the internet for awhile. See below for the links to all of the variants that have been created over the years.
Anyway, I printed this is one of the test prints with my upcoming Nozzle Cam project. My cousin was visiting from out of state along with her young son, so I let him print a Flexy Rex, watch the printer (and the camera feed), and take it off the bed when it was done.</description>
      <content>&lt;p&gt;Flexy Rex is a 3D print that&amp;rsquo;s been circling the internet for awhile. See below for the links to all of the variants that have been created over the years.&lt;/p&gt;
&lt;p&gt;Anyway, I printed this is one of the test prints with my upcoming Nozzle Cam project. My cousin was visiting from out of state along with her young son, so I let him print a Flexy Rex, watch the printer (and the camera feed), and take it off the bed when it was done. Enjoy this soothing timelapse until I finish documenting the whole project. Since the video is on YouTube, I&amp;rsquo;ve linked it instead of embedding in case you&amp;rsquo;re concerned with the privacy implications of using Google&amp;rsquo;s services.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/mI16EQAm68A&#34;&gt;&lt;img alt=&#34;Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2021/flexy_rex/flexyrex_thumb.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;project-files&#34;&gt;Project Files&lt;/h2&gt;
&lt;p&gt;I did not create these files. The following links are to all of the known original authors, from newest to oldest. All files are licensed CC-BY-SA.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/DrLex0/print3D-FlexiRex&#34;&gt;DrLexO even more kid proof version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.thingiverse.com/thing:2189652&#34;&gt;Airfish improved eyes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.thingiverse.com/thing:1759297&#34;&gt;Kirbs more kid proof version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.thingiverse.com/thing:929413&#34;&gt;zheng3 original&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Tasmota Flashing Day</title>
      <link>https://www.apalrd.net/posts/2021/tasmota_day/</link>
      <pubDate>Tue, 19 Oct 2021 12:23:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/tasmota_day/</guid>
      <description>Today I spent the day flashing Tasmota on a variety of Sonoff devices, for use in future projects. I took pictures of the process, so you can follow along with all of the fun bits of playing with repurposed electronic hardware.
I have projects in mind for some of these, but some are still &amp;rsquo;extra&amp;rsquo; (nothing is really ever &amp;rsquo;extra&amp;rsquo;, it will always be used eventually). I have two Sonoff S31 (US smart plug with power monitoring), two Sonoff S26 (US version of the low cost S20 smart plug), and two Sonoff 4CHPRO R3 (4 channel relay, the Pro version with isolated relays).</description>
      <content>&lt;p&gt;Today I spent the day flashing Tasmota on a variety of Sonoff devices, for use in future projects. I took pictures of the process, so you can follow along with all of the fun bits of playing with repurposed electronic hardware.&lt;/p&gt;
&lt;p&gt;I have projects in mind for some of these, but some are still &amp;rsquo;extra&amp;rsquo; (nothing is really ever &amp;rsquo;extra&amp;rsquo;, it will always be used eventually). I have two Sonoff S31 (US smart plug with power monitoring), two Sonoff S26 (US version of the low cost S20 smart plug), and two Sonoff 4CHPRO R3 (4 channel relay, the Pro version with isolated relays). I have plans for one of each, but when you&amp;rsquo;re paying for shipping, why not buy two of each?&lt;/p&gt;
&lt;h2 id=&#34;what-you-need&#34;&gt;What You Need&lt;/h2&gt;
&lt;p&gt;All Sonoff modules which support Tasmota use the ESP8266 family of chips (often the ESP8285, which has built-in flash memory). The ESP chips all include a built-in serial bootloader which is activated by connecting GPIO 0 to ground while powering on the chip. Most Sonoff smart plugs use GPIO 0 for the button on the device, so pressing it while powering on is an easy way to get into the bootloader. Most of them also have pads available for 3V3, GND, TX, and RX, and we just need to find them, solder pins or wires to them, and connect a USB to Serial adapter. I am using an &lt;a href=&#34;https://www.adafruit.com/product/4331&#34;&gt;Adafruit 3V USB to Serial cable with USB-C&lt;/a&gt;, along with male to female 0.1&amp;quot; header jumpers to break out the 6 pin header on the cable to individual pins. I&amp;rsquo;ve used the same color leads as the corresponding wire in the Adafruit cable, where Red = 3V3, Brown = Gnd, Orange = TX (Sonoff RX), and Yellow = RX (Sonoff TX).&lt;/p&gt;
&lt;p&gt;The software we will be flashing is &lt;a href=&#34;https://tasmota.github.io/docs/&#34;&gt;Tasmota&lt;/a&gt;, which was originally written as an alternative firmware for Sonoffs specifically but now supports a wide range of ESP based devices. I am flashing a pre-built standard binary, which includes all of the functionality I need for my Sonff&amp;rsquo;s. ESPHome is another popular option, but for stock Sonoff devices, Tasmota has pre-built module configurations. ESPHome would probably be a better choice if you are building your own devices.&lt;/p&gt;
&lt;p&gt;The third piece of the puzzle is &lt;a href=&#34;https://github.com/tasmota/tasmotizer&#34;&gt;Tasmotizer&lt;/a&gt;, a simple tool which will download the Tasmota image, flash it, and let you configure common settings (WiFi, MQTT broker, Module Type) and push them over the serial console so you don&amp;rsquo;t have to go through the process of connecting to the temporary WiFi network to configure Tasmota for the first time.&lt;/p&gt;
&lt;h2 id=&#34;sonoff-s31&#34;&gt;Sonoff S31&lt;/h2&gt;
&lt;p&gt;This was the first plug I&amp;rsquo;ve used from Sonoff. I bought it because of the power monitoring, but the form factor fits a lot better with US plugs than the S26 (since US plugs are usually stacked vertically instead of horizontally like most other countries). For the small price difference, power monitoring is also a really nice feature to have, especially when paired with logic in Home Assistant, or even just as a cheap Wifi appliance power monitor. The S31 has 6 pads with 0.1&amp;quot; spacing already, two of them are used for the second serial link to the power monitoring chip and are not used. The process was straightforward and Tasmota already has a module type for S31 which works out of the box with power monitoring. &lt;a href=&#34;https://tasmota.github.io/docs/devices/Sonoff-S31/&#34;&gt;Tasmota Page on the Sonoff S31&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff S31 1&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_s31_1.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Everything you need except the USB-Serial cable&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff S31 2&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_s31_2.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Pry the side cover off&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff S31 3&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_s31_3.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Remove the linear trim pieces and remove the screws behind them&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff S31 4&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_s31_4.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Pull out the module to reveal the ESP and pads&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff S31 5&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_s31_5.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Solder pin header to pads, two pins are not used and I skipped soldering them&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff S31 6&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_s31_6.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Connect to USB-Serial cable and Tasmotize&lt;/div&gt;
&lt;h2 id=&#34;sonoff-s26&#34;&gt;Sonoff S26&lt;/h2&gt;
&lt;p&gt;This one was the most difficult since the pads aren&amp;rsquo;t in a row (they are arranged in two sets of two), they are closer together than the usual 0.1&amp;quot; pitch, and the power and ground pads are very close to the power PCB. I managed to tear a pad off the first one I tried, and threw it away instead of fixing it (they are cheap). I also managed to tear a pad off trying to remove my pins on the second one, but it&amp;rsquo;s already flashed so it survived. GPIO 0 is again connected to the single button, so hold the button while plugging in the 3V3 pin to get into the bootloader, then flash in Tasmotizer. I set it up as a &amp;lsquo;Sonoff S2x&amp;rsquo; module, since the S20 family are all the same software with variants for different country plugs. &lt;a href=&#34;https://tasmota.github.io/docs/devices/Sonoff-S26-Smart-Socket/&#34;&gt;Tasmota Page on the Sonoff S26&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff S26 1&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_s26_1.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Ready for disassembly&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff S26 2&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_s26_2.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;TX/RX on the left, GND/3V3 on the right, tiny pads, I&#39;m not a soldering expert&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff S26 3&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_s26_3.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Despite ugly soldering it still flashed fine&lt;/div&gt;
&lt;h2 id=&#34;sonoff-4chpro-r3&#34;&gt;Sonoff 4CHPRO R3&lt;/h2&gt;
&lt;p&gt;This was the easiest. After taking the case off, I found that it has plated through-holes specifically for the 3V3, RX, TX, and GND pins, which is what we need for flashing. I used long pin headers so they stood up from the board with room to solder without removing the Sonoff from the case lower housing, and even with the long pins the upper housing still fits, so I don&amp;rsquo;t even need to remove my pins. Unfortunately, since this model uses an additional microcontroller for IO expansion, none of the buttons map to GPIO 0 (which is what launches the bootloader on ESP chips). It&amp;rsquo;s tied to 3V3 through a resistor (R21). So, I need to poke the resistor with a test lead to get it into bootload mode. Once it&amp;rsquo;s powered on with GPIO 0 grounded it enters the bootloader, and Tasmotizer is able to flash it without issues. Set the module type to Sonoff 4CH and it works exactly as expected. &lt;a href=&#34;https://tasmota.github.io/docs/devices/Sonoff-4CH-Pro/&#34;&gt;Tasmota Page on Sonoff 4CH PRO&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff 4CH PRO 1&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_4ch_1.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;They clearly want us to flash it with these through holes&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff 4CH PRO 2&#34; src=&#34;https://www.apalrd.net/posts/2021/tasmota_day/sonoff_4ch_2.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;But we still need a lead to ground R21 to enter bootload&lt;/div&gt;
</content>
    </item>
    
    <item>
      <title>Controlling USB Camera Lights on Raspberry Pi with USB Hub Power Control</title>
      <link>https://www.apalrd.net/posts/2021/3d_printer_uhubctl/</link>
      <pubDate>Mon, 18 Oct 2021 18:06:32 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/3d_printer_uhubctl/</guid>
      <description>I recently got a camera to use with my 3D printer which includes integrated LED illumination. It has a physical switch to control the lights, but I want to turn them on and off, either from OctoPrint, or from Home Assistant, based on the printer status. Wanting the simplest solution possible, I&amp;rsquo;m going to turn off power to the Pi&amp;rsquo;s USB hub when I don&amp;rsquo;t need the camera lighting. This has a side effect of also disabling the camera itself due to lack of power, which I will also need to deal with, but it doesn&amp;rsquo;t disable the USB data lines, so the 3D printer (which has its own power supply) might not be affected, depending on the printer model.</description>
      <content>&lt;p&gt;I recently got a camera to use with my 3D printer which includes integrated LED illumination. It has a physical switch to control the lights, but I want to turn them on and off, either from OctoPrint, or from Home Assistant, based on the printer status. Wanting the simplest solution possible, I&amp;rsquo;m going to turn off power to the Pi&amp;rsquo;s USB hub when I don&amp;rsquo;t need the camera lighting. This has a side effect of also disabling the camera itself due to lack of power, which I will also need to deal with, but it doesn&amp;rsquo;t disable the USB data lines, so the 3D printer (which has its own power supply) might not be affected, depending on the printer model.&lt;/p&gt;
&lt;h2 id=&#34;basics-of-usb-hub-control&#34;&gt;Basics of USB Hub Control&lt;/h2&gt;
&lt;p&gt;The key to this project is the &lt;a href=&#34;https://github.com/mvp/uhubctl&#34;&gt;uhubctl&lt;/a&gt; command, which allows us to control the power state of USB hub ports from the command line. It specifically supports the built-in hub(s) on the Raspberry Pi B+, 2B, 3B, 3B+, and 4B, although the commands vary slightly based on each model. In my case, I am using a Raspberry Pi 3B, but you can change the commands if you have a 3B+ or 4B (B+, 2B, 3B are all the same). For the Pi, all of the ports share a single power output, so we can&amp;rsquo;t control power individually. Other hubs don&amp;rsquo;t have this limitation, so if this is a deal breaker for your setup, you should get another hub on the supported list to control your outputs, OR use any old hub to power the devices which still need power (since uhubctl doesn&amp;rsquo;t actually disable communication on the ports, just turn off the power to them).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m starting with a completely bare OctoPi install in this case, but Raspbian / Raspberry Pi OS should be similar. I first need to install uhubctl, which is packaged with Debian (and thus Raspbian). SSH in and install it with apt.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install uhubctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we need to give uhubctl permission to operate on the hub, or use sudo all the time. To start, we can test that it works at all using sudo.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo uhubctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should return a list of all of the hubs and ports. For my Pi, there is one hub (1-1) and it has 5 ports. Port 1 controls the WiFi and Ethernet, port 2-5 are the user-accessible USB ports. Controlling the power to port 2 controls all of the user ports. We can try toggling it with sudo:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#Turn off hub 1-1 port 2 (all external ports on the Pi)
sudo uhubctl -l 1-1 -p 2 -a 0
#Turn on hub 1-1 port 2 (all external ports on the Pi)
sudo uhubctl -l 1-1 -p 2 -a 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my case, the lights on my camera turned off (well, the whole camera turned off), and then came back on. Since we toggled power to the camera in addition to just the lights, the OctoPi camera streamer isn&amp;rsquo;t very happy with us, so we need to restart it&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#The OctoPi webcam service is named webcamd
sudo systemctl restart webcamd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, if we just wanted hub control, we could give user pi permission to control the hubs via udev rules. uhubctl gives us instructions for doing this. However, since we will always need sudo to restart webcamd, the script / tool we use to do this needs to have sudo permissions anyway.&lt;/p&gt;
&lt;h2 id=&#34;control-using-node-red&#34;&gt;Control using Node-Red&lt;/h2&gt;
&lt;p&gt;If you only want to control the USB hub to come on/off with the printer, you can use the OctoPrint PSU Control plugin to do this. However, I&amp;rsquo;m already using the PSU Control plugin to control my PSU, using a Sonoff S31 over MQTT &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_power/&#34;&gt;(See Project)&lt;/a&gt;, so I can&amp;rsquo;t use that plugin again. I decided to install Node-Red on the Pi, give it full passwordless sudo permissions (dangerous, I know), and have it subscribe to the same MQTT topic used to control the Sonoff, and respond to ON/OFF messages with the corresponding uhubctl commands.&lt;/p&gt;
&lt;p&gt;I have another quirk in my setup, which you are also likely to encounter if your printer has a well-designed controller. Some printers have isolation between the USB port and the printer&amp;rsquo;s internal power supply, and rely on USB power to supply the USB-serial converter and/or USB isolator. In my case, my Prusa i3 MK3S has a USB-UART chip which is powered by the USB power, followed by a digital isolator for the serial lines which is also powered by USB power. So, at a minimum, I need to keep the USB bus power enabled as long as I want to connect to my printer. Since I am having the USB bus power directly follow the AC power to the printer, this should be perfect, since the PSU Control plugin can be configured to wait after it confirms AC power is on before it connects to the printer and it disconnects from the printer before it poweres off.&lt;/p&gt;
&lt;p&gt;I installed node-red using the apt package, but the node-red website does have a script to install it on your own (and install a more recent version). Since I&amp;rsquo;m not particularly concerned about the version, I used the one in the distro repository.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
sudo apt install nodered
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, I needed to allow no-password sudo access. Node-red runs as user pi, who already has sudo permissions, but would need to re-type their own password to use sudo. Since node-red can&amp;rsquo;t do that, I&amp;rsquo;m going to give user pi no-password sudo access, to allow node-red to execute systemctl to restart the webcam server and also control uhubctl without modifying udev rules. We could get around the uhubctl issue, but systectl must always run as root, so we still need to give root access to node-red anyway. To do this, we need to edit the sudoers file, and this must be done using visudo:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo visudo
#If it asks which editor you want, Nano is the easiest to use

#Find the following line
%sudo ALL=(ALL:ALL) ALL
#Replace with this line
%sudo ALL=(ALL:ALL) NOPASSWD: ALL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, setup a node-red flow to listen on the command topic and respond by executing the system commands to turn on/off USB power. &lt;a href=&#34;https://www.apalrd.net/posts/2021/3d_printer_uhubctl/uhubctl_flow.json&#34;&gt;Click Here for my Flow&lt;/a&gt;. You will need to setup the MQTT broker and topic to match your setup, I have examples listed.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>The Bare Minimum Custom Systemd Service</title>
      <link>https://www.apalrd.net/posts/2021/systemd/</link>
      <pubDate>Sun, 17 Oct 2021 10:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/systemd/</guid>
      <description>Occasionally, I find myself wanting to start something custom as a systemd service, so it starts at boot. There&amp;rsquo;s a whole wealth of information on how to properly write systemd services, but I just want the bare minimum to get my command executed on boot and running on its own. Hence, here is the most basic systemd service guide. Feel free to read the systemd docs (systemd.service, systemd.unit, systemd.exec) for more info on what can go in the service file if you want to get fancy.</description>
      <content>&lt;p&gt;Occasionally, I find myself wanting to start something custom as a systemd service, so it starts at boot. There&amp;rsquo;s a whole wealth of information on how to properly write systemd services, but I just want the bare minimum to get my command executed on boot and running on its own. Hence, here is the most basic systemd service guide. Feel free to read the systemd docs (&lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/systemd.service.html&#34;&gt;systemd.service&lt;/a&gt;, &lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/systemd.unit.html&#34;&gt;systemd.unit&lt;/a&gt;, &lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/systemd.exec.html&#34;&gt;systemd.exec&lt;/a&gt;) for more info on what can go in the service file if you want to get fancy.&lt;/p&gt;
&lt;p&gt;Start by determining the full path to your service. If it&amp;rsquo;s on the PATH, you can do this with which. If you wrote it and it doesn&amp;rsquo;t install itself in /usr/local/bin like a good program, it might be in your home folder. If it&amp;rsquo;s a script and needs an interpreter, you need the full path to the interpreter followed by the full path to the script&lt;/p&gt;
&lt;p&gt;Second, create a systemd service file in the right place and edit it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo touch /etc/systemd/system/myservice.service
sudo chmod 664 /etc/systemd/system/myservice.service
sudo nano /etc/systemd/system/myservice.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, write out the shortest possible configuration file including the full path and command line to execute your service&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=A Cool Service, Wow!
After=network-online.target

[Service]
ExecStart=/usr/bin/python3 /home/pi/myservice/main.py -a -b -c -d
Restart=always

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, tell systemd to reload it&amp;rsquo;s daemon files (since we modified them), then start the service (launch it now), then enable the service (set it to launch automatically on boot).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl start myservice
sudo systemctl enable myservice
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also view the latest bit of the log to check for any errors&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl status myservice
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The End! Systemd is quite easy to work with, and using it to launch your scripts at startup is handy.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Networked DVD Ripping with Raspberry Pi and iSCSI</title>
      <link>https://www.apalrd.net/posts/2021/iscsi_dvd/</link>
      <pubDate>Thu, 14 Oct 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/iscsi_dvd/</guid>
      <description>I&amp;rsquo;ve been working up to a better virtualization and storage setup for my homelab for awhile now. One part of this is cataloguing my media and expanding the virtual side of the media library. I have a legacy collection of DVDs and BDs which I&amp;rsquo;d like to import, and that means I need to rip them from disk. The decryption and transcoding process requires a decent CPU. The demand for high performance leads me to want to run this in a virtual machine (where it can get low priority access to a wealth of compute resources), but the need for a physical disk drive also makes me not want to walk down to the basement every time a disk is done to change disks.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve been working up to a better virtualization and storage setup for my homelab for awhile now. One part of this is cataloguing my media and expanding the virtual side of the media library. I have a legacy collection of DVDs and BDs which I&amp;rsquo;d like to import, and that means I need to rip them from disk. The decryption and transcoding process requires a decent CPU. The demand for high performance leads me to want to run this in a virtual machine (where it can get low priority access to a wealth of compute resources), but the need for a physical disk drive also makes me not want to walk down to the basement every time a disk is done to change disks. Thus, I want a networked disk drive for the virtual machine to read from.&lt;/p&gt;
&lt;h2 id=&#34;iscsi-enters-the-chat&#34;&gt;iSCSI Enters The Chat&lt;/h2&gt;
&lt;p&gt;After my previous experiments with iSCSI trying to &lt;a href=&#34;https://www.apalrd.net/projects/2021/pxe_windows/&#34;&gt;network boot Windows diskless&lt;/a&gt;, I&amp;rsquo;ve grown to have a stronger appreciation for the benefits of iSCSI in the right use case. SMB (CIFS) is still the go-to choice for file sharing across networks, with server-enforced file permissions and wide OS support (basically, the only protocol Windows will speak), but sometimes it&amp;rsquo;s the wrong use case. I could setup a SMB share for a USB drive on a Pi, but then I can only read the mounted filesystem remotely, not the entire block volume, I can&amp;rsquo;t read bolume header information, and I can&amp;rsquo;t control the disk drive (i.e. eject it when complete). So, it&amp;rsquo;s not ideal.&lt;/p&gt;
&lt;p&gt;Basically all modern storage devices in modern computers use only a few protocols, even with a wide variety of physical connection mediums. Quite a few of them end up back at the SCSI command set. The USB 3.0 spec has adopted SCSI over USB (&amp;lsquo;USB Attached SCSI&amp;rsquo;) for mass storage devices, replacing the old USB mass storage command set, and allows this to be used over USB 2.0 as well. This means, if I can get a DVD/BD drive that supports UAS, it should show up as a SCSI device in Linux and thus I can route it over iSCSI to other devices on the network.&lt;/p&gt;
&lt;p&gt;But, what is iSCSI? Simply put, iSCSI is a way to tunnel SCSI commands over a network. SCSI being a protocol to perform block transfers to block IO devices, this means that we can tunnel a &lt;em&gt;block device&lt;/em&gt;, instead of a &lt;em&gt;filesystem&lt;/em&gt; as we would with a protocol like SMB. The host side (&amp;lsquo;initiator&amp;rsquo; in iSCSI terms) is responsible for dealing with drive partitioning and formatting, and interpreting the blocks as a filesystem. The server side (&amp;rsquo;target&amp;rsquo; in iSCSI terms) can choose to emulate the block device or pass the commands through to a physical device, or a partition on a physical device. In my case, I&amp;rsquo;m going to pass through the physical USB SCSI device, meaning the initiator will have full control of it (including all of the extra bits like drive eject).&lt;/p&gt;
&lt;p&gt;The downside to using iSCSI over SMB or NFS is, since it&amp;rsquo;s a block device with the filesystem being managed by the initiator, we need to treat each target like a physical drive - we can&amp;rsquo;t have two clients sending commands to the same physical drive (normally). So, only one computer at a time can connect to each iSCSI target, and they have exclusive control of the device. It&amp;rsquo;s like the SCSI device is physically installed in the initiator&amp;rsquo;s machine. That&amp;rsquo;s exactly what I want with the DVD/BD drive, but this is not a protocol you should go to looking for general purpose file sharing.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-target&#34;&gt;Setting Up the Target&lt;/h2&gt;
&lt;p&gt;To get started with iSCSI, we need a target and an initiator. The target is were the block devices are stored. Normally, iSCSI is used on SANs, and an iSCSI target may be something like a giant disk shelf / JBOD or large storage server providing virtual disk drives for VMs. But, here, we just need a simple Raspberry Pi. I used a Raspberry Pi 2, since it&amp;rsquo;s the best I had given the current Pi 3 and 4 shortages and how many older Pi&amp;rsquo;s I have laying around. It doesn&amp;rsquo;t support USB 3.0, but my DVD drive (already owned) does, so it should use the new UAS instead of USB Mass Storage protocol. I had to use an external powered hub, since the drive would cause power issues with the Pi every time it tried to spin up.&lt;/p&gt;
&lt;p&gt;I first validated that the drive was actually showing up correctly. Before plugging in the USB device, I got a full list of what is in /dev already, then I plugged in the device, then I diff&amp;rsquo;d the two.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo ls /dev &amp;gt; before.txt
#Plug in your drive here
sudo ls /dev &amp;gt; after.txt
diff before.txt after.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see an sgX and srX device, and a bunch of other devices (cdrom, cdrw, dvd, dvrw, &amp;hellip;) depending on the specs of your drive. The sgX device is the one we need here, it&amp;rsquo;s the raw SCSI device. If you look closely (ls -l /dev), you will see that all of the &amp;lsquo;bunch of other devices&amp;rsquo; are actually just links to the srX device, which is the disk device.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to setup the target similar to my diskless Windows install, but instead use direct SCSI passthrough to a physical device. First, install the iSCSI target:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install tgt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, create a config file for the target&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/tgt/conf.d/targets.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The contents are a bit more complex than last time&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;target&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;lun.2021-10.net.apalrd:vdvd&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    backing-store /dev/sg0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bs-type sg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    device-type pt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/target&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In short, we named the target &amp;rsquo;lun.2021-10.net.apalrd:vdvd&amp;rsquo;, it&amp;rsquo;s backed by the physical SCSI device /dev/sg0 (which is the &amp;lsquo;raw&amp;rsquo; SCSI device for my drive), the backing store type is &amp;lsquo;sg&amp;rsquo; (&amp;lsquo;raw scsi device&amp;rsquo;, the prefix sgX in dev), and the device type is passthrough.&lt;/p&gt;
&lt;p&gt;Then, we restart and check that it&amp;rsquo;s working&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart tgt
sudo tgtadm --op show --mode target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If there are any errors in the first step, use &amp;lsquo;sudo systemctl status tgt&amp;rsquo; to see what they are. If it returns with no errors, then tgtadm should show one iSCSI target with two LUNs, one the controller and the other backed by the physical disk drive&amp;rsquo;s SCSI device.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-initiator-on-windows&#34;&gt;Setting Up the Initiator on Windows&lt;/h2&gt;
&lt;p&gt;Initially, I wanted to see if this worked at all, so I setup the initator on my Windows workstation and tried to rip a dvd using MakeMKV.&lt;/p&gt;
&lt;p&gt;To use iSCSI in Windows 10, open the start menu and search for &amp;lsquo;iSCSI Initiator&amp;rsquo;. It will ask you if you want it to run as a service, click yes. Then, you can enter the IP address of the target and discover the LUNs it exposes, click one, and connect to it. If you go to Windows Explorer, it should show a new DVD drive, and it should be usable (although possibly very slow).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Windows iSCSI Initiator&#34; src=&#34;https://www.apalrd.net/posts/2021/iscsi_dvd/win_iscsi_initiator.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Windows iSCSI Initiator&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Windows DVD played remotely&#34; src=&#34;https://www.apalrd.net/posts/2021/iscsi_dvd/win_dvd_play.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;DVD Playback over iSCSI&lt;/div&gt;
&lt;p&gt;However, Windows seems to really struggle to use the DVD drive. It&amp;rsquo;s very slow. Handbrake was unable to rip the DVD at all, and MakeMKV was successful but at a rate of under a megabit per second. VLC was able to load the menu and navigate the menu, but couldn&amp;rsquo;t read fast enough to play back the content. I&amp;rsquo;m not sure what the issues is, but something about the setup is just not ideal.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;MakeMKV&#34; src=&#34;https://www.apalrd.net/posts/2021/iscsi_dvd/win_makemkv.png&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;MakeMKV works, but is very slow&lt;/div&gt;
&lt;p&gt;(Note: I did try connecting the same DVD drive to a USB 2.0 port on the Windows workstation, and it did play, although it wasn&amp;rsquo;t super fast either, but it was at least fast enough to play back the DVD without any buffering)&lt;/p&gt;
&lt;p&gt;I then moved on to Linux, hoping for a better experience.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-initiator-on-linux&#34;&gt;Setting Up the Initiator on Linux&lt;/h2&gt;
&lt;p&gt;First, we need a machine to run this, running Linux, and preferably with enough resources to handle decoding/encoding in Handbrake. I chose to install Ubuntu 20.04 LTS Server on a virtual machine which I gave 8 vCPUs to. Since ripping / transcoding is a background task, I recommend allocating a lot of resources at a low priority to this VM, since the automatic ripping machine can queue jobs for transcoding (since reading the disk is much less intense than transcoding it), so you could pop in a complete box set of a season of your favorite show, let it read the disks as fast as possible, and slowly work through the transcoding in the background without bogging down your other VMs if they are busy. If you install your VM from a virtual CD drive, make sure you detatch the drive entirely (not just remove the virtual disk) once you are done, otherwise, ARM will try to make use of that device for ripping (and that&amp;rsquo;s not what you want).&lt;/p&gt;
&lt;p&gt;Now we must setup the iSCSI target:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Not needed on Ubuntu 20.04, may be needed on your distro&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install open-iscsi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Discover target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo iscsiadm -m discovery -t sendtargets -p &amp;lt;IP of your iSCSI Target&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Login to target (no authentication)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo iscsiadm -m node --login
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Check that new devices showed up in /dev - should see a new sgX, srX, cdrom, ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo ls -l /dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Save settings persistently, auto-start iscsi initiator on boot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo iscsiadm -m node --op update -n node.conn&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;.startup -v automatic
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo iscsiadm -m node --op update -n node.startup -v automatic
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable open-iscsi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable iscsid
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then reboot to make sure the initiator came up and you still have /dev/sgX, /dev/srX, /dev/cdrom, etc. on your initator.&lt;/p&gt;
&lt;h2 id=&#34;automatic-ripping-machine&#34;&gt;Automatic Ripping Machine&lt;/h2&gt;
&lt;p&gt;For this project I decided to try and use an open source project called &lt;a href=&#34;https://github.com/1337-server/automatic-ripping-machine&#34;&gt;&amp;lsquo;Automatic Ripping Machine (ARM)&amp;rsquo;&lt;/a&gt;, which seems to be designed to do exactly what I want. I of course didn&amp;rsquo;t bother trying it in a setup with real working hardware, and jumped straight into getting it to run over iSCSI. Since I&amp;rsquo;m using Ubuntu 20.04 which is the OS they are testing on, they have a &lt;a href=&#34;https://github.com/1337-server/automatic-ripping-machine/wiki/Setting-up-ARM-script-(Ubuntu)&#34;&gt;script to install on a bare environment&lt;/a&gt;. They note that the script has no error handling and is only for environments where you already know it will work, but I am using the exact version of Ubuntu so I ran the script (after reading it). It essentially follows a near identical path to the Ubuntu instructions (installing a ton of stuff with apt, cloning the repo, setting up udev, &amp;hellip;).&lt;/p&gt;
&lt;p&gt;After installing it and setting up a user, I popped a DVD into the (remote) drive. It took a while, and the drive made some noises, and eventually the disk showed up as active in the ARM web UI. It couldn&amp;rsquo;t identify the title, so it gave me 60 seconds to edit it before it started the rip. Unfortunately, it then tried to rip the DVD with handbrake-cli, and handbrake did not like the disk and failed. I tried several DVDs, getting the same result with each. So, given my results with Handbrake on Windows, it seems like it does not like the remote iSCSI drive. In addition, on the VM&amp;rsquo;s display, I was seeing a lot of IO device read errors, indicating a problem reading from the iSCSI device.&lt;/p&gt;
&lt;p&gt;I tried to rip the disk as data instead of DVD, but that gave me a dmesg error about reading scrambled sectors without authentication (since it is a video DVD), and caused dd to exit without copying the DVD. Probably as expected. Again, I also got a lot of IO device read errors from the kernel.&lt;/p&gt;
&lt;h2 id=&#34;manual-ripping&#34;&gt;Manual Ripping&lt;/h2&gt;
&lt;p&gt;My final try on the Linux machine was to use makemkvcon (the console version) to rip the DVD. ARM installed this, so no install guide here. This worked on Windows, but was very slow. I logged in to SSH as the arm user (which is what ARM runs as, and has permissions to access the drive), and told it to rip the first title of the DVD (usually that&amp;rsquo;s the movie) to the home directory&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;makemkvcon mkv dev:/dev/sr0 0 ~
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It found the disk, read the titles, and started working. It doesn&amp;rsquo;t have any sort of progress bar, and it pre-allocates the output file so I can&amp;rsquo;t look at the file size as an indication of how far along it is, but it seemed to be doing fine. There were no kernel errors at all. Networking about 30-40Mbps consistently from the iSCSI target device, which should mean the file should rip in under an hour (and also 50x faster than on Windows). This is not super fast, but it&amp;rsquo;s faster than the DVD would play back normally, so it&amp;rsquo;s reasonable to say this speed limit could be due to the DVD drive. I didn&amp;rsquo;t buy it for this project, it&amp;rsquo;s something I&amp;rsquo;ve had for years to install legacy software, so it might just be slow. Some drives are also known to slow down to only a bit faster than needed for playback when reading movies, for&amp;hellip; reasons? As expected by the data rate, the command finished in just under a half hour, giving me an MKV file which played back correctly, with chapter markers and everything. It&amp;rsquo;s still in MPEG2 format as it was on disk, so it&amp;rsquo;s huge, but transcoding is something Handbrake can do without needing to access the device.&lt;/p&gt;
&lt;p&gt;I also tried running the iSCSI target on a more powerful machine (a dual-core Atom, with USB3 and Gigabit Ethernet), using Ubuntu 20.04 Live Server, and got the same results. This means it&amp;rsquo;s not (largely) an issue with the Raspberry Pi, but there could be issues in tgt (since I used it for both tests).&lt;/p&gt;
&lt;p&gt;As a final test, I installed MakeMKV on the Ubuntu Live Server (the dual-core Atom), and had it extract a smaller 2 minute title from the same disk (since live CDs put the root FS on a RAM disk, it can&amp;rsquo;t fit the full title). Based on the time it took to extract the 2 hour 30 minute title over iSCSI, I estimated it should take about 25 seconds for the smaller title, and the time was fairly close, so the speed is a limitation of the drive, and not the network or iSCSI overhead (at least with the Linux initiator, and using MakeMKV)&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Does this work? Yes. MakeMKV is able to use the iSCSI device on Linux at (what I think) is about the same speed as it would on a physical device. However, not every program was able to access the device, and a lot resulted in transfer errors. I think iSCSI is a valid approach to this problem, but I need a better software stack to implement it (possibly using MakeMKV exclusively to deal with the disk, since it seems to have no problems with iSCSI on Linux). I am also pretty impressed by how well the Pi worked out as an iSCSI target, despite the low power and data throughput.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s possible I could abandon ARM and do it on my own. I don&amp;rsquo;t particularly need all of the features of ARM, and it seems to have gained an absolute ton of feature creep over the years (just look at all the options for notifications, IFTTT, etc.) but the core ripping code is still a pretty simple python script. I could also avoid iSCSI and run MakeMKV on the Pi directly, dumping the ripped file to a network share which the transcode VM scans, but I&amp;rsquo;d need to keep the temporary files on the network as well to avoid SD card wear. Maybe I just need to fork ARM and modify it to use MakeMKV for DVDs in addition to BDs, and Handbrake for transcoding the resulting file.&lt;/p&gt;
&lt;p&gt;Whatever method I go down, I&amp;rsquo;ll be sure to document it in the future.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>The Ultimate OctoPi Setup</title>
      <link>https://www.apalrd.net/projects/2021/3d_printer_octopi/</link>
      <pubDate>Mon, 04 Oct 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2021/3d_printer_octopi/</guid>
      <description>In this project, I setup a proper OctoPrint server for my 3D printer, and integrate it into the enclosure I already built. I also add some RGB flair to make it look nice, and set it up to integrate with Home Assistant. I&amp;rsquo;m very pleased with the results, so follow along for how I set it up.
Building the Circuit Since I want to use WS2812 LED strips to show the printing status, I need a small circuit.</description>
      <content>&lt;p&gt;In this project, I setup a proper &lt;a href=&#34;https://octoprint.org/&#34;&gt;OctoPrint&lt;/a&gt; server for my 3D printer, and integrate it into the &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/&#34;&gt;enclosure I already built&lt;/a&gt;. I also add some RGB flair to make it look nice, and set it up to integrate with Home Assistant. I&amp;rsquo;m very pleased with the results, so follow along for how I set it up.&lt;/p&gt;
&lt;h2 id=&#34;building-the-circuit&#34;&gt;Building the Circuit&lt;/h2&gt;
&lt;p&gt;Since I want to use WS2812 LED strips to show the printing status, I need a small circuit. I decided to buy an Adafruit PermaProto with the Raspberry Pi header already included to simplify this process. Since the Pi needs 5V and so do the LED strips, I got a nice 5V 4A power supply brick to feed power in to the board, which will feed on to the LED strips and into the header to power the Pi and USB devices.&lt;/p&gt;
&lt;p&gt;I also included a header for a BME280 to measure the temperature and humidity in the enclosure, but I haven&amp;rsquo;t finished that part yet, so I&amp;rsquo;ll update this project page when I do.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Board shot 1&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/board1.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Board shot 2&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/board2.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;The 5V power comes in with a female barrel jack and gets connected to the 5V rails on the proto board (which are already connected internally to the Pi&amp;rsquo;s 5V pins on the header). I have a 4700uF 10V cap here to filter any transients from the LEDs, and because it&amp;rsquo;s a big cap and bigger is always better. I have a 5V 2-pin header for a fan (to cool the Pi&amp;rsquo;s CPU), and two 3-pin headers for the two LED strips. Why are there both male and female headers? I built the whole setup with male headers and then realized I couldn&amp;rsquo;t have male on both end since I bought pre-made 3 pin &amp;lsquo;PWM&amp;rsquo; cables (used for hobby servos), so I added the females and left the males.&lt;/p&gt;
&lt;p&gt;The signal to the LEDs needs to be buffered, both to protect the Pi&amp;rsquo;s GPIO pin and to shift the voltage to 5V for the LEDs. I used a 74AHCT125 for this. &lt;a href=&#34;https://cdn-shop.adafruit.com/product-files/1787/1787AHC125.pdf&#34;&gt;See the datasheet for the pinout&lt;/a&gt;. I connected 5V and GND to VCC and GND, and used two of the buffers for the two strips (in case one shorts out or something). The Pi plugin is only providing a single output on the MOSI pin, so I wired that to both 1A and 2A. I jumpered both 1OE and 2OE to ground to keep the output enabled. The Adafruit guide doesn&amp;rsquo;t show this, but I found that the enable would float since I had signal wires really close to the OE pins. The resulting 1Y and 2Y outputs go to the signal pins on the two female headers, which go to the LEDs.&lt;/p&gt;
&lt;p&gt;On the LEDs, I soldered a 3-pin male 0.1&amp;quot; header, and bought standard hobby servo &amp;lsquo;PWM cables&amp;rsquo; which come pre-made in plenty of lengths and of adequate wire gauge to power the 30 LEDs per strip.&lt;/p&gt;
&lt;h2 id=&#34;mounting-the-leds&#34;&gt;Mounting the LEDs&lt;/h2&gt;
&lt;p&gt;I wanted to mount the LEDs as a bar graph, to show the print progress. I thought about using LED rings, but mounting anything to the door of the enclosure would be more of a cable management challenge. I settled on making right-angle channels to hold the LEDs, bolting them together to make longer lengths than would fit on my printer, and using them to increase the rigidity of the enclosure.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;LED bracket&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/rails.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;The LEDs I chose are 60 LED/m, WS2812 compatible RGB LEDs. I cut the strip in half, so there are 30 LEDs on each side, wired in parallel, so the bar graphs will show the same things. After printing 6 brackets (each bracket holds 10 LEDs), I assembled the two 30-LED sticks and tested them with a rainbow pattern.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Light Test&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/light_test.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;I then mounted them to the enclosure with the same #8-32 fasteners I originally used to build the enclosure. Then, I took a beauty shot with the same test pattern, but the supervisor wanted to be involved.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Assembly&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/assembly.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Test with Cat&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/box_cat.jpg&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-pi&#34;&gt;Setting Up the Pi&lt;/h2&gt;
&lt;p&gt;The star of the show here (other than the printer obviously) is a Raspberry Pi 3 Model B. The Pi 4 is available, but the Pi 3 has a decent processor and was easier to find in stock at the time of this writing. I&amp;rsquo;d highly recommend a Pi 3 or Pi 4, as the CPU performance of these is far better than the older Pi&amp;rsquo;s.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s already a distribution of &lt;a href=&#34;https://octoprint.org/&#34;&gt;OctoPrint&lt;/a&gt; for the Raspberry Pi, named &lt;a href=&#34;https://github.com/guysoft/OctoPi&#34;&gt;OctoPi&lt;/a&gt;. I downloaded the latest image and burned it to an SD card using &lt;a href=&#34;https://www.balena.io/etcher/&#34;&gt;Etcher&lt;/a&gt;. I&amp;rsquo;m not using WiFi, so I didn&amp;rsquo;t have to do anything to setup the wireless credentials, but if you are reliant on WiFi, you&amp;rsquo;ll need to edit a file in the boot partition (Which is the only partition that shows up on non-Linux computers) called octopi-wpa-supplicant.txt to configure WiFi.&lt;/p&gt;
&lt;p&gt;Once I powered it on, I had to do some basic housekeeping tasks to get it ready for prime time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Find the IP address. It responds to mDNS/Bonjour under the name octopi.local, but I went to my router and found the IP address it got over DHCP.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Log in via SSH, and run raspi config. There are 3 things we need to set here - the hostname (change it from octopi so you can have more than one octopi in the future), the local Linux user password (default is &amp;lsquo;raspberry&amp;rsquo;), and the timezone. Once that is done, reboot&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; sudo raspi config
 &amp;lt;follow the menu for configuration&amp;gt;
 sudo shutdown -r now
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect to the OctoPrint instance, using the https://IP (note that the certificate is self-signed so it might complain a bit)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup the printer - for the Prusa i3 MK3s, the build volume is 210x210x250&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set a custom bounding box with the Y limit at -20, since the Prusa purge line is outside of the build volume and the OctoPrint will complain if the g-code tries to take the printer out of bounds&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a folder on your NAS to store the data from OctoPrint, so we can avoid writing to the SD card where possible. Ideally all of the g-code, timelapes, etc. all goes to the NAS.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install autofs so we can mount the NAS on the Pi&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; sudo apt-get install autofs
 sudo shutdown -r now
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Log in via ssh again and setup the autofs monut. &lt;a href=&#34;https://www.apalrd.net/posts/2021/autofs/&#34;&gt;I have a guide on this&lt;/a&gt;. I mounted the folder on my NAS for this printer at /mnt/printer with full permissions to that directory for all users. I used the noperm option to disable client-side permissions to the share (so permissions are enforced only server-side), due to issues with OctoPrint and especially OctoLapse trying to modify file permissions on their own. You should only do this if you know you can manage permissions server-side, such as creating a dedicated user on the NAS with permissions to access the dataset for this printer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(Optional) - You can also add an additional mount at /home/pi/.octoprint/data/backup/ which is where the Backup plugin will store backup zips. There&amp;rsquo;s no way to redirect the backups folder from within the config.yaml, so you&amp;rsquo;d need to make a new autofs mount here. In my case, I have a different NAS dataset for backups anyway, so it made sense for me to mount the backups folder separately. I don&amp;rsquo;t use scheduled backups, but I do manually create a backup (without timelapses or uploads) when I change settings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Point all of the folders in OctoPrint to subfolders of this mount. Note that you need a dedicated folder on the NAS for each OctoPrint install, since it doesn&amp;rsquo;t like other programs touching it&amp;rsquo;s files. It will move files out of the Watched folder and into the Uploads folder automatically, and you should not touch files in the Uploads folder without going through the Octoprint GUI. Mounting these folders from a NAS is really done to prevent wear and usage on the Pi&amp;rsquo;s SD Card, not to give you better access (other than the Watched and Timelapse folders, where you can copy in/out directly). I found that OctoPrint seems to reset all of the folders to the defaults if the timelapse temp folder is mounted remotely (I&amp;rsquo;m not sure the triggering condition, but it won&amp;rsquo;t let you set a remote folder for timelapse temp and setting it from the yaml file will cause it to reset all of the folder settings if you view them from the web UI). OctoLapse does not use that temp folder, only the built-in timelapse, so this might not be an issue for you. You can edit the folder paths from the command line a bit faster than from the GUI:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl stop octoprint
mkdir /mnt/printer/logs
mkdir /mnt/printer/timelapse
mkdir /mnt/printer/uploads
mkdir /mnt/printer/watched
nano ~/.octoprint/config.yaml

Replace the folder section with this:
folder:
    logs: /mnt/printer/logs
    timelapse: /mnt/printer/timelapse
    uploads: /mnt/printer/uploads
    watched: /mnt/printer/watched

exit (and save)
sudo systemctl start octoprint
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the Folders menu in Octoprint, check &amp;lsquo;Actively poll watch folder&amp;rsquo;. I found this works better when the watched folder is network mounted.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go into the GUI and install plugins. I installed all of these:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MQTT
HomeAssistant Discovery
WS281x LED Status
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After they all install, we need to configure them. Go into Plugins and disable the new ones except for MQTT, then restart. We will tackle MQTT first.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to Settings, scroll down to MQTT, configure it for your broker information. You should also change the default path, since it assumes you&amp;rsquo;ll only have one octoprint. I made my path octoprint/columbia/ since my printer is named Columbia, after the first Space Shuttle. Save settings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;a href=&#34;https://mqtt-explorer.com/&#34;&gt;MQTT Explorer&lt;/a&gt; to verify that data is being published in the right place. It should have at least some information under your chosen path.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to Settings, Plugins, and enable HomeAssistant Discovery. Save, and restart OctoPrint when asked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Optionally, go to Settings, HomeAssistant Discovery, and change the Device Name if you have more than one printer, so they don&amp;rsquo;t collide in Home Assistant&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Entities should show up in Home Assistant automatically. Go there and check if it found them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to Settings, Plugins, and enable WS281x LED Status. Save, and restart OctoPrint when asked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A menu should popup asking you to configure the plugin. It will guide you through the setup process. Once that is done and the hardware SPI is working, you can set the length of your LED string (in my case 30) and test the LEDs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once everything is working in OctoPrint, create a backup. I excluded timelapses and uploads from my backups since they are already on the NAS. This will generate a zip file with all of your Octoprint configuration data which you can use in case the Pi&amp;rsquo;s SD card fails in the future or you have to re-install for any reason.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;setting-up-home-assistant&#34;&gt;Setting Up Home Assistant&lt;/h2&gt;
&lt;p&gt;Since the HomeAssistant Discovery plugin did most of the hard work here, I just had to go in and rename the Device and set the Area for it. Once that was done, I made a simple dashboard to view the 3D printer progress (including my &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/&#34;&gt;PoE camera&lt;/a&gt;). I attached the Lovelace dashboard as a yaml file in the Project Files below. It requires the &lt;a href=&#34;https://github.com/thomasloven/lovelace-auto-entities&#34;&gt;auto entities card&lt;/a&gt;, which you can install through HACS.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Lovelace dashboard&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/lovelace.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;If you are using the default OctoPi webcam function, here&amp;rsquo;s the yaml for adding the camera to Home Assistant. I have mine in camera.yaml, with a pointer in configuration.yaml (camera: !include camera.yaml) since I have quite a few generic cameras. If you don&amp;rsquo;t have a camera.yaml, you can put this in the camera: section of your configuration.yaml.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Printer Webcam using OctoPi defaults&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;generic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Printer Webcam&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;still_image_url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;http://&amp;lt;IP&amp;gt;/webcam/?action=snapshot&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;stream_source&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;http://&amp;lt;IP&amp;gt;/webcam/?action=stream&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;testing-it&#34;&gt;Testing It&lt;/h2&gt;
&lt;p&gt;With everything hooked up, I was ready to test my first print. I used the &lt;a href=&#34;https://www.3dbenchy.com/&#34;&gt;3D Benchy&lt;/a&gt;, a model used to test 3D printers for their capabilities (overhangs, curves, etc.). I was in the mood for speed, so I used the 0.3mm DRAFT profile.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;OctoPrint while printing&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/octoprint.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;OctoPrint UI while beginning to print&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;LEDs in preheat state&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/print_heat.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;LEDs while heating to begin a print&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;LEDs in print progress state&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/print_progress.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;LEDs showing print progress&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;LEDs in cooldown state&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/print_cooldown.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;LEDs showing cooldown after print&lt;/div&gt;
&lt;h2 id=&#34;future-ehnahcements&#34;&gt;Future Ehnahcements&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll continue updating this project page in the future with some future enhancements. Specifically, I&amp;rsquo;d like to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Print a custom case to mount the Pi to the enclosure&lt;/li&gt;
&lt;li&gt;Add the Enclosure plugin or something like it for enclosure ambient temp+humid sensing (and hopefully get this data back over MQTT)&lt;/li&gt;
&lt;li&gt;Add The Spaghetti Detective, including setting up a local server&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project. As usual, all design files are licensed Creative Commons CC-BY-SA unless otherwise noted.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Raspberry Pi 3 Model B+ - I like &lt;a href=&#34;https://www.adafruit.com/product/3055&#34;&gt;Adafruit&lt;/a&gt;, but there are many other resellers.&lt;/li&gt;
&lt;li&gt;WS2812 or equivalent RGB LED strip - I like &lt;a href=&#34;https://www.adafruit.com/product/1138?length=1&#34;&gt;Adafruit&lt;/a&gt;, but there are many other resellers&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.adafruit.com/product/2310&#34;&gt;PermaProto Pi Hat Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.adafruit.com/product/1787&#34;&gt;74AHCT124 Quad Buffer / Level Shifter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Female 0.1&amp;quot; Pin Headers&lt;/li&gt;
&lt;li&gt;Male 0.1&amp;quot; Pin Headers&lt;/li&gt;
&lt;li&gt;3 pin &amp;lsquo;PWM&amp;rsquo; cables for hobby servos&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.adafruit.com/product/373&#34;&gt;2.1MM DC barrel jack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://octoprint.org/&#34;&gt;OctoPrint Website (for reference)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/guysoft/OctoPi&#34;&gt;OctoPi Website (for reference)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://plugins.octoprint.org/plugins/ws281x_led_status/&#34;&gt;WS281x LED Status Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://plugins.octoprint.org/plugins/mqtt/&#34;&gt;MQTT Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://plugins.octoprint.org/plugins/homeassistant/&#34;&gt;HomeAssistant Discovery Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.thingiverse.com/thing:4981872&#34;&gt;Thingiverse Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.prusaprinters.org/prints/77906-modular-right-angle-rgb-led-bracket-for-printer-en&#34;&gt;PrusaPrinters Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/thomasloven/lovelace-auto-entities&#34;&gt;HomeAssistant Auto Entities Card&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/lovelace-printers.yaml&#34;&gt;HomeAssistant Lovelace Dashboard for my printer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>A Little LED Teaser</title>
      <link>https://www.apalrd.net/posts/2021/led_teaser/</link>
      <pubDate>Sun, 03 Oct 2021 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/led_teaser/</guid>
      <description>I&amp;rsquo;ve been working on a new OctoPrint system for my 3D printer, and as part of this project I made some nice flashy individually addressable LEDs for the sides of the enclosure to show the print status. The full project page is coming soon, but I just had to give you guys a sneak peek at the LEDs. These are WS2812 style individually addressible LEDs, controlled by an OctoPrint plugin on the Raspberry Pi, along with a perf board PCB I soldered to power and level-shift them.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve been working on a new OctoPrint system for my 3D printer, and as part of this project I made some nice flashy individually addressable LEDs for the sides of the enclosure to show the print status. The full project page is coming soon, but I just had to give you guys a sneak peek at the LEDs. These are WS2812 style individually addressible LEDs, controlled by an OctoPrint plugin on the Raspberry Pi, along with a perf board PCB I soldered to power and level-shift them.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Bracket 1&#34; src=&#34;https://www.apalrd.net/posts/2021/led_teaser/led_bracket.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Bracket 2&#34; src=&#34;https://www.apalrd.net/posts/2021/led_teaser/led_bracket2.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Lit Rainbow&#34; src=&#34;https://www.apalrd.net/posts/2021/led_teaser/rainbow.jpg&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;links&#34;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_octopi/&#34;&gt;Project Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.thingiverse.com/thing:4981872&#34;&gt;Thingiverse Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.prusaprinters.org/prints/77906-modular-right-angle-rgb-led-bracket-for-printer-en&#34;&gt;PrusaPrinters Page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Experimenting with Kitchen Lighting Automation</title>
      <link>https://www.apalrd.net/posts/2021/kitchen_lighting/</link>
      <pubDate>Sat, 02 Oct 2021 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/kitchen_lighting/</guid>
      <description>I bought a ton of new Z-wave switches and dimmers, and I&amp;rsquo;m still trying to find the best user interface for automated lighting given the equipment I have, as well as what would be ideal in a new built house. Today, I tried a few automations for my kitchen lighting, which being the center of activity in the house, are the most noticed by everyone, and must work properly at all times.</description>
      <content>&lt;p&gt;I bought a ton of new Z-wave switches and dimmers, and I&amp;rsquo;m still trying to find the best user interface for automated lighting given the equipment I have, as well as what would be ideal in a new built house. Today, I tried a few automations for my kitchen lighting, which being the center of activity in the house, are the most noticed by everyone, and must work properly at all times.&lt;/p&gt;
&lt;p&gt;First things first, what I&amp;rsquo;m working with to start. The kitchen has 4 can lights, 3 island pendants, and 2 strings of color changing LEDs fixed to blue on top of the cabinets. The kitchen has an open entry from the great room, stairs going to the second floor, short path to the basement stairs and front TV room, a door to the mud room (which is always left open), and a door to the back deck. Electrically, there is a 3-way switch for the can and pendant lights together (no separate control unfortunately), with the passage to the front TV room lackng a switch (which has been an annoyance for a long time). The color changing LEDs are wired to a single switch next to the stove, as the wiring was intended for under-cabinet lights.&lt;/p&gt;
&lt;p&gt;The first place to start with any automation is sensing. In this case, I have a mix of motion sensors and door contacts which I&amp;rsquo;ve chosen for this project. The mud room already has a motion sensor, and I&amp;rsquo;m going to trigger the kitchen lights when the motion sensor in the mud room is triggered, since it&amp;rsquo;s likely the kitchen is the next destination. I also already have a door contact (from my &lt;a href=&#34;https://www.apalrd.net/projects/2021/xfinity_hardware/&#34;&gt;Xfinity Sensors project&lt;/a&gt; on the deck door, and I&amp;rsquo;d like to turn the kitchen light on when the deck door is opened or closed (when the state &lt;strong&gt;changes&lt;/strong&gt;, not when the state is open). I also decided to relocate the Inovelli 4-in-1 motion sensor from my &lt;a href=&#34;https://www.apalrd.net/projects/2021/smart_bathroom/&#34;&gt;Smart Bathroom&lt;/a&gt; to the kitchen, since the bathroom was doing fine with cheaper sensors and the Inovelli motion sensor has a sensing pattern that wasn&amp;rsquo;t very good in the tiny bathroom.&lt;/p&gt;
&lt;p&gt;The next step is control. I chose the Inovelli &lt;a href=&#34;https://inovelli.com/red-series-dimmer-switch-z-wave/&#34;&gt;Red Series Dimmer&lt;/a&gt; to control the kitchen lights, and was forced to mount it at the bottom of the stairs since that&amp;rsquo;s the 3-way switch where power enters the circuit. Ideally I could put it on the other side of the kitchen, but I&amp;rsquo;ll do some magic later to make both switches work. For the over-cabinet lights, I chose the Inovelli &lt;a href=&#34;https://inovelli.com/red-series-on-off-switch-z-wave/&#34;&gt;Red Series Switch&lt;/a&gt;. Because the wiring in the kitchen is bizarre, these lights are actually fed by the mud room power circuit, and are located next to the dumb 3-way switch for the main lights. This means I can use multi-taps of the over-cabinet switch to control the main light switch, or the dumb 3-way switch.&lt;/p&gt;
&lt;p&gt;Finally, we have to bridge the two togehter with logic. In my case, there are a few rules for the logic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lights should default to a dim level at night, but only well after dark, and should revert to full brightness by sunrise&lt;/li&gt;
&lt;li&gt;Lights should turn on automatically if motion is detected in the kitchen, mud room, or the deck door is opened/closed&lt;/li&gt;
&lt;li&gt;Lights should have a way to be forced to stay on automatically at full brightness regardless of other commands&lt;/li&gt;
&lt;li&gt;Lights should have a way to revert to automatic control&lt;/li&gt;
&lt;li&gt;Lights should indicate to the user if they are in forced on mode&lt;/li&gt;
&lt;li&gt;Lights should automatically exit forced on mode after several hours if they are not turned off manually&lt;/li&gt;
&lt;li&gt;Lights should exit forced on mode if they are turned off manually by either the main or slave 3-way switch&lt;/li&gt;
&lt;li&gt;Lights should have a way to be forced on from the other side of the room as intuitively as possible&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I ended up breaking this down into a few key bits of automation in Home Assistant:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Group containing the binary sensors which trigger the automated lights&lt;/li&gt;
&lt;li&gt;Input boolean containing the state of the forced on override&lt;/li&gt;
&lt;li&gt;Automation to turn the lights on automatically&lt;/li&gt;
&lt;li&gt;Automation to handle changes to the forced on override state&lt;/li&gt;
&lt;li&gt;Automation to handle multi-presses of the button to change the forced override state&lt;/li&gt;
&lt;li&gt;Automation at sunrise/sunset to change the default levels of the switch&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The code for each of these is below.&lt;/p&gt;
&lt;h3 id=&#34;1-group-for-sensors&#34;&gt;1. Group for Sensors&lt;/h3&gt;
&lt;p&gt;In templates.yaml, I have a template which turns on a binary_sensor whenever the door state changes (and off automatically later). Since the template uses now() it is processed every minute, so the binary_sensor will stay on between 10 and 70 seconds depending on when the processing occurs.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;binary_sensor&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Indicate if any door switches have **changed** recently (for motion lights) &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Kitchen Door Deck Contact Changed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kitchen_door_deck_contact_changed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ (as_timestamp(now()) - as_timestamp(states.binary_sensor.kitchen_door_deck_contact.last_changed)) | float &amp;lt; 10 }}&amp;#34;&lt;/span&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In groups.yaml I have the group for the sensors:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Triggers for kitchen lights&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kitchen_light_motion&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Kitchen Light Motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;entities&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Motion sensors in the kitchen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.kitchen_motion_occupancy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#Other sensors which should trigger kitchen lights&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.mud_room_motion_occupancy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.kitchen_door_deck_contact_changed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;2-input-boolean&#34;&gt;2. Input Boolean&lt;/h3&gt;
&lt;p&gt;Just go to Helpers and create an Input Boolean. Mine is named input_boolean.kitchen_light_override&lt;/p&gt;
&lt;h3 id=&#34;3-automation-to-turn-on-the-lights-automatically&#34;&gt;3. Automation to turn on the lights automatically&lt;/h3&gt;
&lt;p&gt;I can&amp;rsquo;t use the Blueprint that ships with HA to do this since I&amp;rsquo;m using a Group instead of a binary_sensor, so I implemented the equivalent manually.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Kitchen Lights Motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;description&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Turn on Kitchen Lights based on Motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;trigger&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;group.kitchen_light_motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;to&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;on&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;condition&lt;/span&gt;: []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;action&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;light.turn_on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;target&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;light.kitchen_lights&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;wait_for_trigger&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;group.kitchen_light_motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;to&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;off&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;delay&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;hours&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;minutes&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;seconds&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;milliseconds&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;light.turn_off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;target&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;entity_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;light.kitchen_lights&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;restart&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can create a new automation in the GUI and paste this in, and then switch back to the visual editor if you want. Since the mode is &amp;lsquo;restart&amp;rsquo;, any new motion detected during the delay period will restart the automation and turn the light on again, waiting for the motion sensor to go off again, and the final turn off won&amp;rsquo;t occur until the delay is able to complete.&lt;/p&gt;
&lt;h3 id=&#34;4-automation-to-handle-changes-to-override-state&#34;&gt;4. Automation to handle changes to Override State&lt;/h3&gt;
&lt;p&gt;This automation runs whenever the input_boolean changes and responds by setting the lights appropriately. I used a choose to implement the turned on and turned off logic, instead of two automations. It could have been done with two shorter automations instead.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alias: Kitchen Light Update Forced On
description: Update the state of Kitchen Lights when force-on is changed
trigger:
  - platform: state
    entity_id: input_boolean.kitchen_light_override
condition: []
action:
  - choose:
      - conditions:
          - condition: state
            entity_id: input_boolean.kitchen_light_override
            state: &#39;on&#39;
        sequence:
          - service: automation.turn_off
            data:
              stop_actions: true
            target:
              entity_id: automation.kitchen_lights_motion
          - service: light.turn_on
            target:
              entity_id: light.kitchen_lights
            data:
              brightness_pct: 100
          - service: zwave_js.set_config_parameter
            data:
              parameter: &#39;13&#39;
              value: &#39;85&#39;
            target:
              entity_id: light.kitchen_lights
    default:
      - service: automation.turn_on
        target:
          entity_id: automation.kitchen_lights_motion
      - service: light.turn_off
        target:
          entity_id: light.kitchen_lights
      - service: zwave_js.set_config_parameter
        data:
          parameter: &#39;13&#39;
          value: &#39;170&#39;
        target:
          entity_id: light.kitchen_lights
mode: restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In short, the automation does the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check if the input boolean is currently on or off, and either run the on or off logic (the &amp;lsquo;choose&amp;rsquo;)&lt;/li&gt;
&lt;li&gt;If the override is on:
&lt;ul&gt;
&lt;li&gt;Turn off the motion sensor automation and do not let it complete (&amp;lsquo;stop_actions: true&amp;rsquo;) so it does not turn off the light&lt;/li&gt;
&lt;li&gt;Turn on the light and force the brightness to 100%&lt;/li&gt;
&lt;li&gt;Write the parameter on the switch which sets the LED color, and set it to Green (this is Inovelli-specific) to indicate the light is under forced control&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If the override is off:
&lt;ul&gt;
&lt;li&gt;Turn the motion sensor automation back on&lt;/li&gt;
&lt;li&gt;Turn the light back off&lt;/li&gt;
&lt;li&gt;Write the parameter on the switch which sets the LED color, and set it to Blue (this is Inovelli-specific) to indicate the light is under automatic control&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;5-automation-to-handle-multi-presses&#34;&gt;5. Automation to handle multi-presses&lt;/h3&gt;
&lt;p&gt;Again, I wrote this as a single automation with multiple event triggers. Inovelli switches support up to 5x taps on the up and down button. By default, a single tap is bound to &amp;lsquo;on&amp;rsquo; or &amp;lsquo;off&amp;rsquo;, and the other taps are not bound to anything, but they still generate events of type &amp;lsquo;zwave_js_value_notification&amp;rsquo;. I capture these events and run logic based on them. I also check if the light is turned off, instead of capturing the single-press off event, so I can correctly capture any events which turn the light off (such as the remote 3-way turning the light off, which doesn&amp;rsquo;t generate any press events).&lt;/p&gt;
&lt;p&gt;For the Inovelli switches, a property key name of &amp;lsquo;001&amp;rsquo; is the down button and &amp;lsquo;002&amp;rsquo; is the up button. Value will be &amp;lsquo;KeyPressed&amp;rsquo; or &amp;lsquo;KeyPressedNx&amp;rsquo; where N is 2,3,4,5 for multi-taps. This event relies on the Z-wave node ID, in my case 23 is the kitchen dimmer and 21 is the kitchen over-cabinet switch.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alias: Kitchen Light Double-Tap Handler
description: Double-tap the kitchen light for it to stay on full brightness
trigger:
  - platform: event
    event_type: zwave_js_value_notification
    event_data:
      node_id: 23
      property_key_name: &#39;002&#39;
      value: KeyPressed2x
    id: KeyPressOn
  - platform: event
    event_type: zwave_js_value_notification
    event_data:
      node_id: 23
      property_key_name: &#39;001&#39;
      value: KeyPressed2x
    id: KeyPressOff
  - platform: state
   entity_id: light.kitchen_lights
   id: KeyPressOffSingle
    to: &#39;off&#39;
  - platform: event
    event_type: zwave_js_value_notification
    event_data:
      node_id: 21
      property_key_name: &#39;001&#39;
      value: KeyPressed2x
    id: KeyPressOffAccent
  - platform: event
    event_type: zwave_js_value_notification
    id: KeyPressOnAccent
    event_data:
      node_id: 21
      property_key_name: &#39;002&#39;
      value: KeyPressed2x
condition: []
action:
  - choose:
      - conditions:
          - condition: or
            conditions:
             - condition: trigger
                id: KeyPressOn
              - condition: trigger
                id: KeyPressOnAccent
        sequence:
          - service: input_boolean.turn_on
            target:
              entity_id: input_boolean.kitchen_light_override
          - delay:
              hours: 4
              minutes: 0
              seconds: 0
              milliseconds: 0
          - service: input_boolean.turn_off
            target:
              entity_id: input_boolean.kitchen_light_override
      - conditions:
          - condition: trigger
            id: KeyPressOffSingle
          - condition: state
            entity_id: input_boolean.kitchen_light_override
            state: &#39;on&#39;
        sequence:
          - service: input_boolean.turn_off
            target:
              entity_id: input_boolean.kitchen_light_override
    default:
      - service: input_boolean.turn_off
        target:
          entity_id: input_boolean.kitchen_light_override
mode: restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The automation first sets up 5 triggers which are named for the future. Double-tap up on either the kitchen dimmer or overcabinet switch, and change of state of the light to off (by any means).&lt;/p&gt;
&lt;p&gt;If a double-tap up is pressed (either switch), the light override is turned on, and then after 4 hours it is turned back off. Since the mode is restart, any other events will stop this delay.&lt;/p&gt;
&lt;p&gt;If the light is turned off for any reason and the override was already set on, the override is turned off to return to automatic control.&lt;/p&gt;
&lt;p&gt;If a double-tap down is pressed (either switch), the default case runs and the override is turned off.&lt;/p&gt;
&lt;h3 id=&#34;6-sunrise-and-sunset&#34;&gt;6. Sunrise and Sunset&lt;/h3&gt;
&lt;p&gt;I already have two very long sunrise and sunset automations which set up the lighting brightness and enable/disable automations, so I wrote parameters 9 and 10 (default level and default level Z-wave respectively) on the dimmer in these automations. These parameters are Inovelli specific, and even specific to the dimmer (for the LZW36 fan+light model, the parameters are 12 and 13).&lt;/p&gt;
&lt;p&gt;After all of this, I&amp;rsquo;m fairly satisfied and might expand this UI concept (green means forced, blue means automatic) to the rest of my automated lighting. The RGB indicators on Inovelli switches really make this nice.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Integrating Security Camera Motion Detection with Lighting Control</title>
      <link>https://www.apalrd.net/posts/2021/motion_camera_lights/</link>
      <pubDate>Fri, 01 Oct 2021 01:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/motion_camera_lights/</guid>
      <description>As I expand the reach of Home Assistant, I continuously try to build automations that make life generally easier for the users of the home. To me, automation isn&amp;rsquo;t about being able to control anything from my phone - in fact, the less I have to get my phone out, the better. I will still enjoy tracking history entries and status of nodes with both the web UI and app, but I shouldn&amp;rsquo;t have to, the house should just work.</description>
      <content>&lt;p&gt;As I expand the reach of Home Assistant, I continuously try to build automations that make life generally easier for the users of the home. To me, automation isn&amp;rsquo;t about being able to control anything from my phone - in fact, the less I have to get my phone out, the better. I will still enjoy tracking history entries and status of nodes with both the web UI and app, but I shouldn&amp;rsquo;t have to, the house should just work. With all of this, my next goal is to merge automated lighting with security cameras, to improve the user experience when coming home at night. This is an all-encompasing goal that includes motion sensing lighting with PIR sensors, door switches, and of course &lt;a href=&#34;https://www.apalrd.net/projects/2021/frigate_intro/&#34;&gt;Frigate&amp;rsquo;s AI person detection&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;well-leave-the-light-on-for-you&#34;&gt;We&amp;rsquo;ll Leave The Light On For You&lt;/h2&gt;
&lt;p&gt;Without any way to control exterior lighting from outside the house, this is a very common occurance when someone is out late. If someone is coming home and parking in the driveway, they will be wandering around in the dark trying to find the back door, or if they open the garage door, dealing with the dim light of a single bulb in an overhead door motor to see where they are going. It&amp;rsquo;s not a great user experience. The age-old solution to this is to leave the exterior lights on all the time, so anyone arriving after dark can see where they are going and find the back door. Even when they do find the back door, they enter the kitchen, and need to find the switch for that light (which is not near the exterior door), and the process continues with lights being turned on and off until they make it to their bedroom.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m approaching this in a multi-pronged way. I need more sensor information to make informed decisions about lighting, and I need more control of the lights. I&amp;rsquo;ve started with the following goals for automation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The back deck exterior lights and deck rope lights shall turn on when persons are detected on the deck or in the driveway next to the garage between sunset and sunrise&lt;/li&gt;
&lt;li&gt;The front and side exterior lights shall turn on when persons are detected on the deck, in the driveway next to the garage, in the front yard, or on the front porch, between sunset and sunrise&lt;/li&gt;
&lt;li&gt;The front and side exterior lights shall turn on when any garage overhead door is opened, between sunset and sunrise&lt;/li&gt;
&lt;li&gt;The garage lights shall turn on when any garage overhead door is opened, between sunset and sunrise&lt;/li&gt;
&lt;li&gt;The mud room lights shall turn on when the garage to mud room door is opened or when motion is detected, at all times&lt;/li&gt;
&lt;li&gt;The kitchen lights shall turn on when the deck door is opened, motion is detected in the kitchen, or motion is detected in the mud room, between sunset and sunrise, and automatically dim based on the time of day if on.&lt;/li&gt;
&lt;li&gt;The second floor stair lights shall turn on when motion is detected, between sunset and sunrise, and dim based on the time of day if on.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;detecting-if-a-door-contact-recently-changed&#34;&gt;Detecting if a door contact recently changed&lt;/h2&gt;
&lt;p&gt;One key here is that I don&amp;rsquo;t want the lights to stay one when the door is open, I want them to turn on when the door is &lt;strong&gt;opened&lt;/strong&gt; and stay on for a few minutes. Since closing the door usually follows, but closing the door also indicates a person is in the vicinity of the door, I&amp;rsquo;m okay triggering when the door opens or closes, but not when it remains in the opened state. To do this, I wrote a template sensor for each door switch which triggers if the value has changed in the last 10 seconds. Since triggers are evaluated whenever a corresponding entity changes, but triggers containing now() are also evaluated every 60 seconds, this means the resulting binary sensor will stay true for between 10 and 70 seconds depending on when the condition is re-evaluated. This is acceptable to me. The following needs to go in your templates.yaml:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Indicate if any door switches have **changed** recently (for motion lights) &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;binary_sensors&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Kitchen Door Deck Contact Changed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kitchen_door_deck_contact_changed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ (as_timestamp(now()) - as_timestamp(states.binary_sensor.kitchen_door_deck_contact.last_changed)) | float &amp;lt; 10 }}&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Garage Door Entry Contact Changed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;garage_door_entry_contact_changed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ (as_timestamp(now()) - as_timestamp(states.binary_sensor.garage_door_entry_contact.last_changed)) | float &amp;lt; 10 }}&amp;#34;&lt;/span&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Front Door Contact Changed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;front_door_contact_changed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ (as_timestamp(now()) - as_timestamp(states.binary_sensor.front_door_contact.last_changed)) | float &amp;lt; 10 }}&amp;#34;&lt;/span&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you don&amp;rsquo;t have a templates.yaml, see if you have a templates in your configuration.yaml and add them there. If not, make a new templates.yaml and point to it from configuration.yaml like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;template: !include templates.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;setting-up-motion-groups&#34;&gt;Setting Up Motion Groups&lt;/h2&gt;
&lt;p&gt;The easiest way to implement this in Home Assistant is to create groups for each of these events (groups OR the entities they contain by default), and use that group as the trigger for the motion sensing lights automation. In my case, I started with a group for the back deck lights based on person detection from the 3 relevant cameras, and a group for the mud room lights based on the door and motion sensors. These go in groups.yaml:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Motion sensors which contribute to Deck Lights&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;deck_light_motion&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Deck Light Motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;entities&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.back_door_person_motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.parking_person_motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.driveway_person_motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.kitchen_door_deck_contact_changed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Sensors which contribute to mud room lights&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;mud_room_light_motion&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Mud Room Light Motion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;entities&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.garage_door_entry_contact_changed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#ae81ff&#34;&gt;binary_sensor.mud_room_motion_occupancy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Obviously, more motion groups exist for all of the scenarios above, but this is an example.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-lighting-automations&#34;&gt;Setting Up Lighting Automations&lt;/h2&gt;
&lt;p&gt;Although there is already a blueprint for motion-activated lights, it&amp;rsquo;s very picky about what it accepts. In my case, the issue is it will only accept a Light entity, not a Switch entity, so I can&amp;rsquo;t use it since I use Switches (Inovelli Red) for my exterior lights. I could use it for my interior lights which have Dimmers (and are Light entities), but it&amp;rsquo;s not a terribly hard automation to write manually.&lt;/p&gt;
&lt;p&gt;So, the automation goes something like this (using the GUI):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mode - Restart - means it will start the timer over when new motion is detected before the lights have turned off automatically&lt;/li&gt;
&lt;li&gt;Triggers - State - (group name), to on&lt;/li&gt;
&lt;li&gt;Conditions - none&lt;/li&gt;
&lt;li&gt;Actions:
&lt;ul&gt;
&lt;li&gt;Turn on light (using either Call Service or Device)&lt;/li&gt;
&lt;li&gt;Wait for Trigger - State - (group name), to off, no timeout&lt;/li&gt;
&lt;li&gt;Delay - the time you want the lights to remain on after motion is not detected&lt;/li&gt;
&lt;li&gt;Turn off light (using either Call Service or Device)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Copy that automation for every case where you want to use it.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-sunrisesunset-actions&#34;&gt;Setting Up Sunrise/Sunset Actions&lt;/h2&gt;
&lt;p&gt;I setup two automations, one which runs at Sunrise + 30min, and one which runs at Sunset -30min, to setup the house for day and night time activities. These two automations are exactly the opposite of each other, and basically do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Turn on/off all of the Automations which are responsible for daytime only motion sensing (bedrooms)&lt;/li&gt;
&lt;li&gt;Turn on/off all of the Automations which are responsible for nightitme only motion sensing (garage, deck, kitchen)&lt;/li&gt;
&lt;li&gt;Set parameters on the dimmers for the default dim level, to either 100% (daytime) or the night time % selected for that room, duplicated for both the local on and Z-wave on parameters - for my Inovelli dimmers, this is parameters 9 and 10 respectively (parameter 12 and 13 instead for Inovelli LZW-36 dual fan light dimmer))&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;results&#34;&gt;Results&lt;/h2&gt;
&lt;p&gt;So far, I&amp;rsquo;ve been running this for a few weeks with a few different lighting groups - one for the back deck lights and one for the front porch lights. So far, feedback has been excellent. The front porch and garage exterior lights come on when cars or people are detected in the driveway, so they come on quickly as someone arrives. The back deck lights come on when people are detected on the deck or in the driveway, so they come on with slightly more filtering compared to the porch lights. There are relatively minor issues in dealing with what happens when the automation is turned on when the lights should be on - I need a bit more logic to decide if it should turn the lights on immediately when the automation becomes active. The interior kitchen lights are also starting to be automated, more on that in the future.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Temperature and Humidity Sensor Showdown</title>
      <link>https://www.apalrd.net/posts/2021/temp_humid_showdown/</link>
      <pubDate>Mon, 27 Sep 2021 01:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/temp_humid_showdown/</guid>
      <description>When I started my bathroom automation journey, I used the Inovelli 4-in-1 Motion Sensor (LZW60) which had sensors for motion, temperature, humidity, and ambient light level in my Smart Bathroom Project. I was happy with the automation, but wanted to try out some cheaper sensors to see if they were adequate for the other bathrooms in my house. I decided to try the Aqara (Xiaomi) Temperature and Humidity Sensor and the Sonoff SNZB-02 Temperature and Humidity Sensor as cheap alternatives for temperature and humidity.</description>
      <content>&lt;p&gt;When I started my bathroom automation journey, I used the &lt;a href=&#34;https://inovelli.com/4-in-1-sensor-z-wave/&#34;&gt;Inovelli 4-in-1 Motion Sensor (LZW60)&lt;/a&gt; which had sensors for motion, temperature, humidity, and ambient light level in my &lt;a href=&#34;https://www.apalrd.net/projects/2021/smart_bathroom/&#34;&gt;Smart Bathroom Project&lt;/a&gt;. I was happy with the automation, but wanted to try out some cheaper sensors to see if they were adequate for the other bathrooms in my house. I decided to try the &lt;a href=&#34;https://www.aqara.com/us/temperature_humidity_sensor.html&#34;&gt;Aqara (Xiaomi) Temperature and Humidity Sensor&lt;/a&gt; and the &lt;a href=&#34;https://itead.cc/product/sonoff-snzb-02-zigbee-temperature-and-humidity-sensor/&#34;&gt;Sonoff SNZB-02 Temperature and Humidity Sensor&lt;/a&gt; as cheap alternatives for temperature and humidity. I bought several of each sensor on Aliexpress, and set them up in my bathroom to compare data.&lt;/p&gt;
&lt;h2 id=&#34;unboxing&#34;&gt;Unboxing&lt;/h2&gt;
&lt;p&gt;The unboxing experience for each sensor was very different.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff Unboxing&#34; src=&#34;https://www.apalrd.net/posts/2021/temp_humid_showdown/sonoff_unboxing.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;The Sonoff sensor comes in a box barely bigger than the sensor itself, along with a square of double sided foam tape to mount the sensor, and a small paper manual. The packaging is efficient and functional. You must pry off the back of the sensor using a small flat blade screwdriver (I was worried I&amp;rsquo;d break it) and remove a piece of paper covering the battery terminals, then it&amp;rsquo;s ready for pairing. To pair, you can hold the button on the sensor with your finger for 5 seconds or so and it will start the process.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Aqara Unboxing&#34; src=&#34;https://www.apalrd.net/posts/2021/temp_humid_showdown/xiaomi_unboxing.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;The Aqara sensor comes in a much larger box. The sensor itself is fairly small, but it&amp;rsquo;s sitting in a white paper board stand which is actually entirely empty inside. The sensor comes with a pre-installed foam tape ring, and they include an extra one in the box, along with a small paper manual. The box could have easily been half the size or less and still fit everything inside. I mention this because I find the large white interior box very wasteful, and it adds up when you buy dozens of sensors per house. The inclusion of an extra foam tape ring was a nice touch though. I was unable to remove the battery cover easily with the screwdrivers I had on hand, it seems to be designed to use a really wide blade (such as a butter knife). However, there is no paper covering the battery terminals, so it&amp;rsquo;s ready for pairing out of the box. Unlike the Sonoff sensor, the button is not readily accessible, and must be poked through a hole using a bent papercip or similar tool.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Size Comparison&#34; src=&#34;https://www.apalrd.net/posts/2021/temp_humid_showdown/size_comparison.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;The Aqara sensor is significantly smaller than the Sonoff sensor, although neither is particularly large. Both would be relatively unobtrusive mounted on the ceiling of a room.&lt;/p&gt;
&lt;h2 id=&#34;test-setup&#34;&gt;Test Setup&lt;/h2&gt;
&lt;p&gt;Both sensors were mounted on the ceiling in between the shower and the bathroom fan, with the ventilation holes in both sensors facing the shower. This gives these sensors a significant advantage over the Inovelli sensor, which is mounted on the opposite corner of the room for good motion view.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Mounted&#34; src=&#34;https://www.apalrd.net/posts/2021/temp_humid_showdown/mounted.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;Both sensors were paired in Zigbee2MQTT through the same repeater, and added to Home Assistant. Both had approximately 70 LQI (link quality). Both were left with all default settigns. Both sensors report all of the same data (Battery, Voltage, Temperature, Humidity, Linkquality), with the Aqara sensor also reporting pressure. I did not include pressure data or long term battery life in this comparison, only temperature and humidity reporting. The Inovelli sensor is paired with ZWaveJS2MQTT and has the reporting interval set to 1 minute (not the default), which is how it was already configured from my &lt;a href=&#34;https://www.apalrd.net/projects/2021/smart_bathroom/&#34;&gt;Smart Bathroom Project&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;the-test&#34;&gt;The Test&lt;/h2&gt;
&lt;p&gt;All three sensors ran for a week to compare results. During this time, control of the bath fan was still done by the Inovelli sensor, with the other sensors only used for logging. Data from a single shower is shown below, for analysis.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;ha_shower&#34; src=&#34;https://www.apalrd.net/posts/2021/temp_humid_showdown/ha_shower.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;A few conclusions can be made from this data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All of the sensors report the same temperature steady-state, before the shower.&lt;/li&gt;
&lt;li&gt;The Sonoff sensor reports slightly higher humidity than the other two sensors at all times, but this is within the tolerance of all of the sensors.&lt;/li&gt;
&lt;li&gt;As &lt;a href=&#34;https://www.zigbee2mqtt.io/devices/SNZB-02.html&#34;&gt;Zigbee2MQTT&amp;rsquo;s documentation warns&lt;/a&gt;, the Sonoff sensor has a very slow reporting interval for temperature, but a fairly quick reporting interval for humidity (which seems odd). This is confirmed with this data, where the Sonoff sensor reports no temperature changes for over a half hour, but continues reporting humidity changes.&lt;/li&gt;
&lt;li&gt;The Aqara (Xiaomi) sensor also does some stair-stepping in reporting with both temperature and humidity, but the response seems closer for both signals than the Sonoff, and is fast enough for bathroom humidity control.&lt;/li&gt;
&lt;li&gt;Neither sensor is fast enough for closed-loop temperature control.&lt;/li&gt;
&lt;li&gt;Due to their location much closer to the shower, the Sonoff and Aqara (Xiaomi) sensors both report humidity much faster and reach much higher numbers than the Inovelli motion sensor on the far side of the fan from the shower. This also causes the humidity to decay much slower from these sensors than the Inovelli, as air enters the bathroom near the Inovelli motion sensor and exits through the fan, while the shower area itself is essentially not ventilated.&lt;/li&gt;
&lt;li&gt;While not part of the showdown, I also included a Sonoff SNZB-03 motion sensor mounted between the two temperature + humidity sensors, and found that it performed better than the Inovelli at detecting motion in the bathroom. This is due to the very small size of the bathroom and the detection pattern of the Inovelli being designed for wall mounting (with a half-cone shape), while the Sonoff SNZB-03 has a full cone shape for ceiling mounting. In the tiny bathroom, the ceiling mount sensor is a better choice as it can &amp;lsquo;see&amp;rsquo; into the shower and not turn the lights off while showering as the Inovelli would. I don&amp;rsquo;t believe this is a fault of the Inovelli sensor, but you do have to be aware of the detection pattern when selecting a sensor for wall vs ceiling mounting.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;the-parts-list&#34;&gt;The Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://inovelli.com/4-in-1-sensor-z-wave/&#34;&gt;Inovelli 4-in-1 Motion Sensor (LZW60)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.aqara.com/us/temperature_humidity_sensor.html&#34;&gt;Aqara (Xiaomi) Temperature and Humidity Sensor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://itead.cc/product/sonoff-snzb-02-zigbee-temperature-and-humidity-sensor/&#34;&gt;Sonoff SNZB-02 Temperature and Humidity Sensor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>A Quick 3D Printer Box Update, and a Raspberry Pi Case</title>
      <link>https://www.apalrd.net/posts/2021/3d_printer_update/</link>
      <pubDate>Fri, 24 Sep 2021 13:06:32 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/3d_printer_update/</guid>
      <description>I finished the box! At least I finished it enough to start using it. It still needs OctoPrint, lighting, and some RGB LEDs (doesn&amp;rsquo;t everything these days?). But, it&amp;rsquo;s usable now. Check out the Project Page for the full story.
The New Box In addition, I&amp;rsquo;ve started designing a Raspberry Pi case for my OctoPrint Pi. First revisions are shown below. I thought I&amp;rsquo;d start with this case and re-print it as I add things to the enclosure, but I think I&amp;rsquo;m going to go caseless for now and work up to what I want the final design to be.</description>
      <content>&lt;p&gt;I finished the box! At least I finished it enough to start using it. It still needs OctoPrint, lighting, and some RGB LEDs (doesn&amp;rsquo;t everything these days?). But, it&amp;rsquo;s usable now. Check out the &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/&#34;&gt;Project Page&lt;/a&gt; for the full story.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;3D Printer Box&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/newbox1.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;The New Box&lt;/div&gt;
&lt;p&gt;In addition, I&amp;rsquo;ve started designing a Raspberry Pi case for my OctoPrint Pi. First revisions are shown below. I thought I&amp;rsquo;d start with this case and re-print it as I add things to the enclosure, but I think I&amp;rsquo;m going to go caseless for now and work up to what I want the final design to be. This is the first Pi case I&amp;rsquo;ve printed, and I&amp;rsquo;ve learned a bit about fitment for the Pi along the way. I designed around the Rasbperry Pi 3, not the 4, since that&amp;rsquo;s what I&amp;rsquo;m using for my printer.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Case, With Pi&#34; src=&#34;https://www.apalrd.net/posts/2021/3d_printer_update/case1.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Case, With Pi&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Case, Closed&#34; src=&#34;https://www.apalrd.net/posts/2021/3d_printer_update/case2.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Case, Closed&lt;/div&gt;
&lt;p&gt;The biggest issues are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The USB ports do not clear the enclosure, they need another mm or two. I should have accounted for the flange on the ports more carefully. The opening for the ports needs to be wider&lt;/li&gt;
&lt;li&gt;The pegs which the Pi sits on are quite a snug fit, and I don&amp;rsquo;t know if I&amp;rsquo;d be able to get the Pi back out without breaking it. I need to loosen these up. I can secure the Pi with hot glue if necessary. The holes are spec at 2.75mm, my pegs are 2.6mm, I&amp;rsquo;m going to go down to ~2.25mm ish.&lt;/li&gt;
&lt;li&gt;The analog audio jack does not clear. I can either move the Pi up by a bit, or make the walls thinner to leave a bit more clearance. I don&amp;rsquo;t really need 5mm thick walls, so reducing these to 3.5mm should leave enough clearance for the audio jack. I don&amp;rsquo;t actually use the audio jack, so it doesn&amp;rsquo;t have a hole through the enclosure&lt;/li&gt;
&lt;li&gt;The hexagonal hole for the power port is designed to avoid printing a square hole, which will cave in a bit without support, but I realized later that I can make it slightly larger to clear both the micro-USB on the Pi 3 and the USB-C on the Pi 4, making the case universal.&lt;/li&gt;
&lt;li&gt;I printed the lid with a very small undersize between the wings, which are supposed to friction fit to the case. Depsite making this a fraction of a mm, the case is very loose, and I should print it exactly to size next time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&#34;Case, fitment issue&#34; src=&#34;https://www.apalrd.net/posts/2021/3d_printer_update/case3.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;USB Connector Interference&lt;/div&gt;
&lt;p&gt;In the future, I plan on expanding my OctoPrint setup and printing a new case dedicated to whatever electronics I come up with. Some things I&amp;rsquo;d like to include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Large 5V power supply for LEDs and the Pi&lt;/li&gt;
&lt;li&gt;Either all WS2812 type individually addressable LEDs, or MOSFETs to control the enclosure white LEDs plus WS2812 status indicators&lt;/li&gt;
&lt;li&gt;Temperature and humidity sensor in the enclosure&lt;/li&gt;
&lt;li&gt;Fan for the Pi and MOSFETs&lt;/li&gt;
&lt;li&gt;Case design to support Pi 3 or Pi 4 with no mods (although the HDMI ports won&amp;rsquo;t be accessible in either case, since you don&amp;rsquo;t need them with OctoPi)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Follow along for more updates on this and other projects!&lt;/p&gt;
&lt;p&gt;Andrew&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Diskless Windows Desktop using PXE with a Linux backend</title>
      <link>https://www.apalrd.net/posts/2021/pxe_windows/</link>
      <pubDate>Tue, 21 Sep 2021 01:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/pxe_windows/</guid>
      <description>Inspired by recent a recent video on the basics of PXE booting by &amp;lsquo;Tall Paul Tech&amp;rsquo; (formerly known as CWNE88), as well as a comment by Linus of Linus Tech Tips that his new home server could &amp;rsquo;network boot everything in his house&amp;rsquo;, I wondered how easy it would be to network boot everything in my house. In an ideal world, this would solve a lot of problems regarding managing backups of the drives - by simply not having drives at any client, they can all be managed and backed up centrally by the server.</description>
      <content>&lt;p&gt;Inspired by recent a recent video on the basics of &lt;a href=&#34;https://www.youtube.com/watch?v=OuhFbr6gt44&#34;&gt;PXE booting by &amp;lsquo;Tall Paul Tech&amp;rsquo; (formerly known as CWNE88)&lt;/a&gt;, as well as a comment by &lt;a href=&#34;https://www.youtube.com/watch?v=TWRvB8fh8T8&#34;&gt;Linus of Linus Tech Tips&lt;/a&gt; that his new home server could &amp;rsquo;network boot everything in his house&amp;rsquo;, I wondered how easy it would be to network boot everything in my house. In an ideal world, this would solve a lot of problems regarding managing backups of the drives - by simply not having drives at any client, they can all be managed and backed up centrally by the server. I&amp;rsquo;ve already come to love the flexiblity in separating storage from compute in a virtualization environment, where I can use a ZFS backend to deal with snapshots, replication, and file integrity checking, and I&amp;rsquo;ve upgraded the network speed for my workstation so I can work on files directly off the network using mapped network drives, but this still leaves my primary boot disk vulnerable, and while my files are safe, my installed programs are not. I could certainly recover from a boot disk failure without data loss, but it would take a while to get everything re-installed again. So, if I could keep the boot disk on the storage backend, it would gain the integrity protection and snapshots that the data has. Being that Linus will only be concerned with gaming, it&amp;rsquo;s probably important to be able to boot Windows, as unfortunate as that sounds going in to this project.&lt;/p&gt;
&lt;h2 id=&#34;the-basic-design&#34;&gt;The Basic Design&lt;/h2&gt;
&lt;p&gt;In short, we are going to rely on PXE to get the system off the ground, and then load iPXE (a better PXE) using the &amp;lsquo;chainloading&amp;rsquo; method (where traditional PXE is used to load the improved open-source PXE), which we will then use to boot off an iSCSI target containing a Windows disk. If we had Linux clients, we could rely on NFS instead of iSCSI for the root filesystem, and we would curse a whole lot less.&lt;/p&gt;
&lt;p&gt;So, there are a few components needed here&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The DHCP server, which at a minimum has to point to the PXE server (the &amp;rsquo;next-server&amp;rsquo; directive as well as the boot file directive).&lt;/li&gt;
&lt;li&gt;The TFTP server, which stores the files used by PXE to load iPXE&lt;/li&gt;
&lt;li&gt;The HTTP server, which stores additional files used by iPXE to load the operating system, although not required after the bootable iSCSI drive is configured. This could also be expanded to serve custom iPXE scripts to each client based on their MAC address or other unique identifiers.&lt;/li&gt;
&lt;li&gt;The Samba server, which stores the Windows installation media, not required after installation&lt;/li&gt;
&lt;li&gt;The iSCSI target, which stores the virtual block device used to store the Windows C drive&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To implement this project, for testing, I&amp;rsquo;ve created an Ubuntu 20.04 VM on &lt;a href=&#34;https://www.apalrd.net/projects/2021/minilab/&#34;&gt;Minilab&lt;/a&gt; to act as the server for TFTP + HTTP + Samba + iSCSI, and I have an old amd64 machine which will act as the client. It physically has no hard drive installed. It&amp;rsquo;s an old Atom processor in an ITX embedded motherboard, but it should be enough to prove that this method works without buying any hardware.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-dhcp-server&#34;&gt;Setting Up the DHCP server&lt;/h2&gt;
&lt;p&gt;This one is pretty simple. I use &lt;a href=&#34;https://opnsense.org/&#34;&gt;OPNsense&lt;/a&gt; as my DHCP sever for my existing network, so I just had to go down to Network Booting, Enable Network Booting, and set next-server IP and boot file name. I set the DHCPv4 and DHCPv6 server to have a static reservation for the Ubuntu VM, so it will have a consistent IP without setting a static IP inside the VM, and set next-server to that IP. So, clients will now look to the Ubuntu server for their PXE boot files. I just need enough configuration in the DHCP server to get the dumb PXE clients to load iPXE which is compiled with an embedded script pointing it to the HTTP server, where it can go for the rest of its configuration.&lt;/p&gt;
&lt;p&gt;What happens at this point? If I power on the test system with next-server set, and it tries, but there is no TFTP server for it to find. In this case, we want to boot &lt;a href=&#34;https://ipxe.org/&#34;&gt;iPXE&lt;/a&gt;, which is a better PXE environment than the default, and will hopefully let us boot from iSCSI.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-tftp-server&#34;&gt;Setting Up the TFTP server&lt;/h2&gt;
&lt;p&gt;This one is also pretty simple. In my Ubuntu VM, I installed it from apt and that was that.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install tftpd-hpa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default it places the data at /srv/tftp, but the config file is located at /etc/default/tftpd-hpa if you&amp;rsquo;d like to change that. I&amp;rsquo;m fine with the default location.&lt;/p&gt;
&lt;p&gt;I added a blank file called undionly.kpxe to the tftp folder and set that as the boot file name for BIOS in the DHCP settings (the name will become relevant later). I booted my test system (which is old enough to use legacy BIOS) and it attempted to load the file but couldn&amp;rsquo;t boot it, since it&amp;rsquo;s just a blank file.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-iscsi-target&#34;&gt;Setting Up the iSCSI Target&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re doing this for a &amp;lsquo;production&amp;rsquo; environment, you should use something like TrueNAS and setup your iSCSI target there. I&amp;rsquo;m not an iSCSI expert by any means, but I got this to work. The whole point of this project is to try new things.&lt;/p&gt;
&lt;p&gt;First we need to install the iscsi target on Ubuntu:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install tgt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we need to setup an iSCSI target.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/tgt/conf.d/target01.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the contents:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;target iqn.2021-09.net.apalrd:win10&amp;gt;
    backing-store /srv/disks/win10.img
&amp;lt;/target&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we need a blank image file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fallocate -l 20G /srv/disks/win10.img
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restart the server&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart tgt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look at the status&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo tgtadm --mode target --op show
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So now we have an iSCSI target which we can use to store the Windows C drive, but nothing is installed on the disk image.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-ipxe&#34;&gt;Setting up iPXE&lt;/h2&gt;
&lt;p&gt;We would like to use &lt;a href=&#34;https://ipxe.org/&#34;&gt;iPXE&lt;/a&gt; to get the process rolling. So, cd to a place you can keep a git repo, and clone it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone git://git.ipxe.org/ipxe.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Follow the instructions &lt;a href=&#34;https://ipxe.org/download&#34;&gt;here&lt;/a&gt; to make sure you have the dependencies installed so you can build&lt;/p&gt;
&lt;p&gt;Then we need to create an embedded file so it will run a script when it boots:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ipxe/src
nano boot.ipxe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the contents:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!ipxe
#Setup networking
echo Setup Networking
dhcp
#Boot from SAN
echo Boot from SAN
sanboot iscsi:&amp;lt;IP&amp;gt;:::&amp;lt;LUN&amp;gt;:iqn.2021-09.net.apalrd:win10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although all of the examples for ipxe show LUN as blank (iscsi::::iqn&amp;hellip;), I found that I needed to set LUN to 1 with the default configuration of tgt. It seems like LUN 0 is always a Controller, with LUN 1 being the Disk. Not sure why exactly this is, but tgtadm shows the LUN numbers for each target correctly. Additionally, I had trouble with Windows giving me an &amp;lsquo;INACCESSIBLE BOOT DEVICE&amp;rsquo; error, which I&amp;rsquo;ll get to in a bit.&lt;/p&gt;
&lt;p&gt;Then we can build ipxe with our embedded script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;make bin/undionly.kpxe EMBED=boot.ipxe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then finally we copy that into our tftp folder so clients can find it&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cp ./bin/undionly.kpxe /src/tftp
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;setting-up-apache2&#34;&gt;Setting up Apache2&lt;/h2&gt;
&lt;p&gt;Since TFTP is pretty ugly, I installed Apache2 to serve files over HTTP for the installation process. This isn&amp;rsquo;t used after install, but it could be used along with PHP / some scripts to send more complex commands to iPXE once it&amp;rsquo;s been loaded via TFTP. There are better guides than mine out there, so just setup a basic apache2 with the http root in /srv/html with full read access to anyone.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-samba&#34;&gt;Setting up Samba&lt;/h2&gt;
&lt;p&gt;Again, we need Samba for the install process so I installed it with no permissions and mounting a share &amp;lsquo;server&amp;rsquo; at location /srv. This also lets me copy files to the http root, tftp root, and iscsi disks folder from my Windows workstation as needed.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install samba
sudo nano /etc/samba/smb.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the following lines to the end:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[server]
  comment = Server directory
  path = /srv
  browseable = yes
  guest ok = yes
  read only = no
  create mask = 0777
acl allow execute always = True
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then restart Samba&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart smbd nmbd
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;installing-windows&#34;&gt;Installing Windows&lt;/h2&gt;
&lt;p&gt;I first tried to install Windows in a VM, then copy that VM to the win10.img disk that&amp;rsquo;s being shared over iSCSI. It was not properly configured for iSCSI and gave me the &amp;lsquo;INACCESSABLE BOOT DEVICE&amp;rsquo; error. So, I decided to install it over the network.&lt;/p&gt;
&lt;p&gt;I chose to go with the &amp;lsquo;wimboot&amp;rsquo; method, booting WinPE (windows preboot execution environment) according to &lt;a href=&#34;https://ipxe.org/howto/winpe&#34;&gt;this guide&lt;/a&gt;. I modified my boot.ipxe temporarily while installing, created the folder structure using copype, and moved it to my HTTPS directory. Since I was embedding the script instead of loading it from HTTP, I modified all of the paths to include http://&amp;lt;IP&amp;gt;/ in front of them. The resulting script is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!ipxe
#Start networking
echo Start Networking
dhcp
#Set web root
set webroot http://&amp;lt;IP&amp;gt;
echo Webroot is ${webroot}
#Set architecture
cpuid --ext 29 &amp;amp;&amp;amp; set arch amd64 || set arch x86
echo ARCH is ${arch}
#Sanhook the Windows drive
echo Attaching iSCSI drive
sanhook iscsi:&amp;lt;IP&amp;gt;:::1:iqn.2012-09.net.apalrd:win10
#Load wimboot
echo Loading Wimboot
kernel ${webroot}/wimboot
initrd ${webroot}/${arch}/media/Boot/BCD        BCD
initrd ${webroot}/${arch}/media/Boot/boot.sdi   boot.sdi
initrd ${webroot}/${arch}/media/sources/boot.wim    boot.wim
boot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, you need to make ipxe again and copy the new undionly.kpxe to the tftp root.&lt;/p&gt;
&lt;p&gt;Now we need a Windows install to install from. Download the Microsoft media creation tool and use it to create an ISO image. I then unzipped the files on my Windows computer using 7-zip, dropping them in the ISO folder.&lt;/p&gt;
&lt;p&gt;Now boot the client. It should boot into a Windows graphical command prompt. We now need to connect over Samba to the location of the Windows ISO and run the installer. Be warned, it&amp;rsquo;s a very slow process, don&amp;rsquo;t expect anything to happen instantly.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;net use \\&amp;lt;ServerIP&amp;gt;\server
\\&amp;lt;ServerIP&amp;gt;\server\html\iso\sources\setup.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we told Samba earlier that executing anything is fine (who needs security when you&amp;rsquo;re prototyping), we can execute the installer. We now get a normal-ish Windows GUI installer, loaded over SMB, from the WinPE environment we network booted over HTTP, from the iPXE environment we loaded over PXE, with no physical storage or disks at all on the client. Not bad.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Finally, Windows installs&#34; src=&#34;https://www.apalrd.net/posts/2021/pxe_windows/installer_iscsi.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, this win was short lived, as I couldn&amp;rsquo;t get the installer to partition the iSCSI drive. It found it, and it was blank, but clicking &amp;rsquo;new&amp;rsquo; would let me go through the process of creating the partition, and then it would hang when actually creating it. Unfortunately, this is the end of my adventure, as I&amp;rsquo;m sick of dealing with Windows 10. I&amp;rsquo;ve read (relatively few) guides of this working correctly in Windows 7, but it seems to be a fairly unpopular solution in the modern era.&lt;/p&gt;
&lt;h1 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;Is this a good idea in a homelab in 2021? Probably not the best idea. There are far better options for VDI than network booting a Windows installation over iSCSI. Is it an option for the right scenario? Definitely. PXE has its place, and it&amp;rsquo;s definitely been a fun project to learn about it. The key lesson I&amp;rsquo;ve learned is that it should be used when you are booting a read-only something, and a whole lot of that something, to justify setting up and configuring a server. If you just want to network boot one media center PC to avoid buying an SSD, this is probably not the solution for you.&lt;/p&gt;
&lt;h3 id=&#34;where-does-network-booting-have-a-place&#34;&gt;Where does network booting have a place?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;installers&lt;/strong&gt;, where you network boot into a menu to select which installer you want to run off a network store, and install something on the computer, setting up a PXE server and all of the associated ipxe configuration is fantastic. I found a great example file for that &lt;a href=&#34;https://gist.github.com/robinsmidsrod/2234639&#34;&gt;here&lt;/a&gt;, although you could easily use an embedded script in ipxe to avoid writing rules in the DHCP configuration. You also have the option of identifying clients by MAC or other unique address to serve the right installer.&lt;/li&gt;
&lt;li&gt;For an application like a computing lab, you could use Linux and mount the root filesystem read-only using NFS, which lets you deal with common ancestry and deduplication at a file level instead of a block level as in iSCSI. You could also mount the home directory read-write using NFS separately, so every computer boots the golden root image and any changes are lost when it reboots (except the user&amp;rsquo;s home directory). Since all of the computers are physically identical, drivers and such should be the same.&lt;/li&gt;
&lt;li&gt;For a server cluster, it&amp;rsquo;s not a bad way to distribute the cluster OS and root filesystem either. Again, you&amp;rsquo;d setup a &amp;lsquo;golden&amp;rsquo; image, mount that over iSCSI or NFS, and boot into it. The applications in the cluster must all rely entirely on network storage for this to work, which is a very reasonable expectation of a cluster, and the server would need to configure its networking based on its MAC address. Using DHCP static allocations would be easeiest for this, although if they are all nodes in a cluster they might not need reserved IPs at all and plain DHCP might be fine.&lt;/li&gt;
&lt;li&gt;For home use such as media centers or wall mounted tablets, it might be a decent idea to network boot into a Linux OS which again mounts a read only filesystem designed for this purpose, loading the media over the network. For this to be viable you really need a decent number of nodes, and you really need to be running Linux, which is much less of a headache to network boot. The new Raspberry Pi 4 keeps the first stage boot image in EEPROM instead of on the SD card, meaning you can reprogram it to look for other boot devices, including PXE. The older Pi&amp;rsquo;s would need an SD card to store the first stage boot image, which could then go out and network boot, leaving the SD card otherwise unused. That said, simply booting a read only filesystem from the SD card and loading the media and configuration off the network would be easier to setup and easy to replace if it breaks.&lt;/li&gt;
&lt;li&gt;For a home lab which uses GPU partitioning, where you lose the ability to use the physical outputs on the GPU (or use GPUs which never had them), you could network boot a Linux image on all of your computers which in turn launches Parsec as the only graphical environment, to connect remotely to the host on the compute server.&lt;/li&gt;
&lt;li&gt;While researching this, I found a number of companies offering software to centrally store the boot disks of Windows corporate workstations, so the company could keep classified data safe overnight without manually removing all of the hard drives from the computers. By removing the drives from the server or keeping it physically secure and disconnected overnight, they could network boot all of the workstations and reduce the chance of physical data theft. There is also some advantage in doing this that you can make a golden corporate image and clone the image for each employees workstation image (or, if you&amp;rsquo;re really paranoid, wipe them overnight back to the golden image), reducing space on the server since they are all based on a common ancestor, keep central backups of the images, and let any physical workstation boot to anyone&amp;rsquo;s personal workstation image as required, so no more cloning hard disks when replacing desktops. If your workflow is already heavily based on keeping files on the server and only programs and customizations are stored locally, this could work very well. Linus (of LTT) might be better off network booting all of his editing workstations rather than his living room gaming computer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;whats-a-better-option-for-a-home-lab&#34;&gt;What&amp;rsquo;s a better option for a home lab?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;For a media center or home theater that also does gaming, using VFIO (PCIe passthrough or SR-IOV) to a GPU in a compute server and connecting that via long distance HDMI / DisplayPort / USB3 active optical cables is probably cheaper and less power intense way to get 4K/60 video to the client. You&amp;rsquo;ll be able to use the compute resources you already have in the rack, and unless you&amp;rsquo;re getting small form factor desktops which can fit a GPU in bulk, probably save money by only adding the GPU to an existing compute node. If you are gaming, you probably don&amp;rsquo;t want to deal with the latency of streaming over the network, although apparently Parsec isn&amp;rsquo;t bad (I haven&amp;rsquo;t used it myself). The downside is that there is no standard for connecting any of these things over networking fiber, so your cheapest option is usually an active fiber cable instead of using standard networking fiber, which means pulling wires which are essentially already dated when installed (i.e. HDMI 2.0 = no 8K without pulling new wires). You also can&amp;rsquo;t partition the GPU if you use the physical video outputs, since GPU partitioning was never designed to be used with consumer GPUs in the first place (on either the AMD or nVidia side), and the tricks used to partition Geforce GPUs essentially make the drivers believe it&amp;rsquo;s an equivalent Quadro or Tesla with the same silicon.&lt;/li&gt;
&lt;li&gt;Give each user a laptop with a locally installed OS and let them connect to hosts in the compute node (which can use GPU partitioning) for workloads that need more compute or GPU performance.&lt;/li&gt;
&lt;li&gt;For a dedicated single user workstation, using dedicated local storage still isn&amp;rsquo;t an awful choice, it just makes backing up the OS drive more difficult than network booting. The same goes for laptops.&lt;/li&gt;
&lt;li&gt;For both laptops and desktops, you have the option of installing the user&amp;rsquo;s OS inside a hypervisor and using the hypervisor to manage backups. You may use XCP-NG or Proxmox, pass through the physical GPU to the guest, mount the guest from local storage, and have the hypervisor snapshot and push the backup to the server periodically. You&amp;rsquo;ll have less space available to the guest due to snapshots, but SSDs are cheap enough now. Re-installing the hypervisor on disk failure and then restoring a backup of the guest disk is probably easier than re-installing the guest OS and all of the programs on it, even if you have good data backups. For this to work, you can&amp;rsquo;t pass through the entire disk to the guest, since you need to manage snapshots through the hypervisor.&lt;/li&gt;
&lt;li&gt;Installing Windows programs on a network share is possible, with the right permissions in Samba. You can also locate your Steam library on a network drive. Steam games are very easy to reinstall, but tend to be massive, so keeping them backed up locally just saves internet bandwidth if you have a drive failure.&lt;/li&gt;
&lt;li&gt;For macOS, apps are considerably easier to backup since they are usually part of an App Bundle which can be copied freely, so backing up the entire Applications directory isn&amp;rsquo;t really difficult. There are certainly some apps which don&amp;rsquo;t respect the App Bundle, but it&amp;rsquo;s a lot easier than on Windows.&lt;/li&gt;
&lt;li&gt;For Linux, writing an Ansible playbook to install your normal desktop apps on top of a fresh distro install is a pretty decent solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hope to explore some of these options in a future adventure.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Home Automation Christmas in September</title>
      <link>https://www.apalrd.net/posts/2021/ha_christmas/</link>
      <pubDate>Mon, 20 Sep 2021 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/ha_christmas/</guid>
      <description>It&amp;rsquo;s always a good day to receive new hardware, and today is no different. Over the past few days, I&amp;rsquo;ve received a bunch of hardware in the mail and I&amp;rsquo;d like to share my plans with you. Ever since I setup my first automations with my blinds and started automating my lighting and bathroom, I&amp;rsquo;ve been addicted to automating more and more of the house. So, after spending a lot of money on high end Z-wave motion sensors, dimmers, and switches, I went searching for some more cost-effective products to try out.</description>
      <content>&lt;p&gt;It&amp;rsquo;s always a good day to receive new hardware, and today is no different. Over the past few days, I&amp;rsquo;ve received a bunch of hardware in the mail and I&amp;rsquo;d like to share my plans with you. Ever since I setup my first automations with &lt;a href=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/&#34;&gt;my blinds&lt;/a&gt; and started automating my &lt;a href=&#34;https://www.apalrd.net/projects/2021/zwave_intro/&#34;&gt;lighting&lt;/a&gt; and &lt;a href=&#34;https://www.apalrd.net/projects/2021/smart_bathroom/&#34;&gt;bathroom&lt;/a&gt;, I&amp;rsquo;ve been addicted to automating more and more of the house. So, after spending a lot of money on high end Z-wave motion sensors, dimmers, and switches, I went searching for some more cost-effective products to try out. WiFi, Zigbee, Z-Wave, and 433Mhz (sensors only) were all on the table. At this point, I have no data on how well any of these products work. I will start incorporating them into projects going forward, so follow along for the long-term data on how these end up working out! Here&amp;rsquo;s the total haul that came in over the last few weeks:&lt;/p&gt;
&lt;h2 id=&#34;inovelli-z-wave-dimmers-and-switches&#34;&gt;Inovelli Z-Wave Dimmers and Switches&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve already used the Inovelli &lt;a href=&#34;https://inovelli.com/red-series-fan-light-switch-z-wave/&#34;&gt;LZW36 dual fan+light switch module&lt;/a&gt;, which has an RF controlled canopy module allowing control of the fan and light without dedicated power wires for the fan and the light. I also have an &lt;a href=&#34;https://inovelli.com/4-in-1-sensor-z-wave/&#34;&gt;LZW60 4-Way sensor&lt;/a&gt; (Motion, Light, Temperature, Humidity), which is used in my &lt;a href=&#34;https://www.apalrd.net/projects/2021/smart_bathroom/&#34;&gt;Smart Bathroom&lt;/a&gt;. After being impressed with this hardware, I decided to buy some of the backordered Inovelli red series dimmers and switches (&lt;a href=&#34;https://inovelli.com/red-series-dimmer-switch-z-wave/&#34;&gt;LZW31-SN Dimmer&lt;/a&gt; and &lt;a href=&#34;https://inovelli.com/red-series-on-off-switch-z-wave/&#34;&gt;LZW30-SN Switch&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Inovelli switch 10-pack&#34; src=&#34;inivelli.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;I only ordered two dimmers, so I&amp;rsquo;ll have to plan carefully where I put those, but I bought a 10-pack of switches, so I&amp;rsquo;ll have plenty of places to put those if I can get away without dimming. I already want to switch the exterior lights based on &lt;a href=&#34;https://www.apalrd.net/projects/2021/frigate_intro&#34;&gt;Frigate&lt;/a&gt; motion events, so we don&amp;rsquo;t have to &amp;rsquo;leave the lights on&amp;rsquo; when someone is out late. I&amp;rsquo;m sure I&amp;rsquo;ll find more uses for the dimmers and switches.&lt;/p&gt;
&lt;h2 id=&#34;sonoff-itead-zigbee-products&#34;&gt;Sonoff (ITEAD) Zigbee Products&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve used Sonoff products before, but only their ESP based products, which I flashed with Tasmota. This time, I went specifically for Zigbee. I&amp;rsquo;d still recommend their Wifi smart plugs (especially the S31 with power monitoring if you&amp;rsquo;re in the US), but for sensors I&amp;rsquo;m willing to tolerate Zigbee for better battery life over WiFi. They had a sale on Zigbee products, so I went a bit overboard and bought a lot. I bought directly from ITEAD and shipping via DHL was less than a week.&lt;/p&gt;
&lt;p&gt;Overall, I got 3 products:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://itead.cc/product/sonoff-snzb-03-zigbee-motion-sensor/&#34;&gt;SNZB-03 Zigbee motion sensor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://itead.cc/product/sonoff-snzb-02-zigbee-temperature-and-humidity-sensor/&#34;&gt;SNZB-02 Zigbee temperature + humidity sensor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://itead.cc/product/sonoff-zbmini-zigbee-smart-switch/&#34;&gt;ZBMINI Zigbee version of the Sonoff Mini mains relay and switch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&#34;Sonoff/ITEAD Products&#34; src=&#34;https://www.apalrd.net/posts/2021/ha_christmas/sonoff.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;My plans for the products, and why I chose them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;m trying to try a wide variety of low cost sensors to collect as much data on their reliability / functionality as possible before outfitting my future house with a ton of them. The SNZB-02 will go head to head against the much more expensive Z-Wave motion and more sensors (Aeotec 6-way multisensor and Inovelli 4-way multisensor) and the Xiaomi Aqara temperature + humidity sensor.&lt;/li&gt;
&lt;li&gt;The IKEA Zigbee motion sensor I have in my bedroom was out of stock, and I want to do more motion controlled lighting. The Sonoff SNZB-03 motion sensor also looks better (it&amp;rsquo;s physically smaller at least), is physically symmetrical, and has a cone of view optimized for ceiling or wall mounting, whereas the IKEA sensor was designed exclusively for wall mounting. This is important for stairway lighting where the sensor will be above the stairs.&lt;/li&gt;
&lt;li&gt;I have more bathrooms with combined fan+light on a single switch that I want to separate into control of the fan and control of the light. The Inovelli LZW-36 fan+light switch I already used is out of stock and not expected to return until 2022, and want to see if I can setup something as functional for less money for the less frequently used bathrooms. I plan on combining the ZBMINI with a smart bulb and a switch on the wall, and may experiment with Zigbee binding so it works during a hub failure.&lt;/li&gt;
&lt;li&gt;I didn&amp;rsquo;t buy the SNZB-04 door contacts from Sonoff, but maybe someday I&amp;rsquo;ll compare them against the Aqara door contacts. Pricing is about the same for both of them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;xiaomi-aqara-zigbee-products&#34;&gt;Xiaomi Aqara Zigbee Products&lt;/h2&gt;
&lt;p&gt;Xiaomi is a well-known Chinese brand, and they have a sub-brand called Aqara for some of their home automation products using Zigbee. I purchased their sensors to compare against what I already have from IKEA and Sonoff. Since I went through Aliexpress, I had to wait a bit longer for shipping, but they were significantly cheaper than Amazon and were price competitive to Sonoff, with cheaper shipping, so they&amp;rsquo;re a great option if you plan ahead enough to be able to wait. I got a bit of a different variety here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Door And Window Sensor&lt;/li&gt;
&lt;li&gt;Water Leak Sensor&lt;/li&gt;
&lt;li&gt;Temperature, Pressure, and Humidity Sensor&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&#34;Xiaomi Aqara Temp + Humid Sensor&#34; src=&#34;https://www.apalrd.net/posts/2021/ha_christmas/xiaomi_temphumid.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;The box for the Temperature + Humidity sensor contains the sensor (which is really very small), small manual, and an extra foam tape ring (there&amp;rsquo;s already one attached to the sensor), but the whole white paper box inside is empty, meaning the packaging could have been considerably less wasteful. I setup the first sensor and paired it with my Zigbee network to verify that it works as expected, and it does.&lt;/p&gt;
&lt;p&gt;My plans for the products, and why I chose them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Aqara sensors seemed reasonably priced for door contacts, and they visually look better than the &lt;a href=&#34;https://www.apalrd.net/projects/2021/xfinity_hardware/&#34;&gt;Visonic&lt;/a&gt; ones I have already (leftover from Xfinity, so I didn&amp;rsquo;t spend money on them). I&amp;rsquo;m going to try these out with overhead garage doors as well. No temperature data from these, although it&amp;rsquo;s not really necessary anyway. The Sonoff SNZB-04 door contact doesn&amp;rsquo;t have temperature either.&lt;/li&gt;
&lt;li&gt;The Temp + Pressure + Humid sensor will have a showdown with the similarly priced Sonoff model, which doesn&amp;rsquo;t include pressure. I don&amp;rsquo;t expect pressure to add a lot of functionality to the sensor. Additionally, although neither this sensor nor the Sonoff model are listed for outdoor use, this one has a narrower temperature range.&lt;/li&gt;
&lt;li&gt;The Water Leak Sensor is one of the cheapest water leak sensors available, so I thought I&amp;rsquo;d give it a try. As I mentioned in my &lt;a href=&#34;https://www.apalrd.net/projects/2016/septic_plc/&#34;&gt;Septic Control Project&lt;/a&gt;, we have previously had water backups in the basement as well as condensate drain failures leading to water on the floor, so I&amp;rsquo;ll put the 3 sensors I got in the basement and laundry room and see if they ever trigger.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;acurite-433mhz-outdoor-temperature-module&#34;&gt;Acurite 433Mhz Outdoor Temperature Module&lt;/h2&gt;
&lt;p&gt;I already put this one to use in the &lt;a href=&#34;https://www.apalrd.net/projects/2021/rtl433/&#34;&gt;433Mhz Sensor&lt;/a&gt; project, just a day after receiving it. Usually hardware sits on the bench for awhile before I get around to finishing a project, but the turnaround here was fast enough that the project page is already done before this blog entry. These cost $13 each plus $7 shippping for two and were received in less than a week. &lt;a href=&#34;https://www.acurite.com/shop-all/weather-instruments/weather-sensors-and-parts/replacement-parts/indoor-outdoor-temperature-humidity-sensor.html&#34;&gt;Link to Product&lt;/a&gt;. Performance is currently under review, data is being logged by Home Assistant and seems to be reasonable so far. rtl_433 has no trouble reading this sensor, and the update rate is pretty good (~30 seconds).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Acurite 609TXC&#34; src=&#34;https://www.apalrd.net/posts/2021/ha_christmas/acurite.jpg&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;rtl-sdr-dongle-another-one&#34;&gt;RTL-SDR Dongle (Another One)&lt;/h2&gt;
&lt;p&gt;After setting up the &lt;a href=&#34;https://www.apalrd.net/projects/2021/rtl433/&#34;&gt;433Mhz Sensor&lt;/a&gt; project and committing my only SDR radio to be used for data acquisition, I soon after found myself wanting to play with SDR again in the &lt;a href=&#34;https://www.apalrd.net/posts/2021/rtlamr/&#34;&gt;rtlamr&lt;/a&gt; failed project. Since I only had one RTL-SDR dongle, I had to take down the 433Mhz sensor project for a day to use the dongle. I have now ordered another RTL-SDR dongle so I can continue to play with SDR based projects without interfering with my &amp;lsquo;production&amp;rsquo; hardware. I previously looked for a low cost but not poorly reviewed dongle, and selected the Nooelec model for its low entry price. I could have gotten a nicer dongle this time, but I bought the same one, so maybe in my future third entry into SDR I&amp;rsquo;ll get serious about higher performance, low noise dongles.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Nooelec SDR dongle&#34; src=&#34;https://www.apalrd.net/posts/2021/ha_christmas/nooelec.jpg&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;raspberry-pi-3-another-one&#34;&gt;Raspberry Pi 3 (Another One)&lt;/h2&gt;
&lt;p&gt;With all the Pi&amp;rsquo;s I use in projects, even temporarily, I&amp;rsquo;ve found that my aging collection of Raspberry Pi&amp;rsquo;s is no longer adequate to run a lot of modern software. I&amp;rsquo;ve been working with Raspberry Pi&amp;rsquo;s for a long time, and as I re-use Pi&amp;rsquo;s from older projects they continue to age. A lot of newer software is no longer built for armv6l, or even 32-bit ARM any more. Here&amp;rsquo;s a bit of my collection:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Raspberry Pi Collection&#34; src=&#34;https://www.apalrd.net/posts/2021/ha_christmas/raspi.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;From left to right, bottom to top:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;My first ever Rasperry Pi, the original Model B with the funny mechanical layout and pre-dating the now standard 40 pin GPIO header and 4-hole rectangular mounting pattern, in an &lt;a href=&#34;https://www.adafruit.com/product/1326&#34;&gt;Adafruit Case&lt;/a&gt;. This Raspberry Pi ran Raspbmc (which later became &lt;a href=&#34;https://osmc.tv/&#34;&gt;OSMC&lt;/a&gt;), along with an IR receiver chip taped to the case with bacon duct tape, feeding its analog video output to my TV. Circa 2013.&lt;/li&gt;
&lt;li&gt;My second ever Rasberry Pi, used for many years as my NAS. I had a 2TB USB HDD attached and served files for XBMC (later &lt;a href=&#34;https://kodi.tv/&#34;&gt;Kodi&lt;/a&gt;) on the first Raspberry Pi, but I also used this to back up files from my laptop. I eventually setup XBMC MySQL sharing, so all of the TVs in the house could share a common media database and watched information&lt;/li&gt;
&lt;li&gt;A &amp;lsquo;New&amp;rsquo; improved Model B+, which brought the new standard 40-pin header, mounting hole arrangement, and 4 USB ports, but was otherwise very similar to the OG Model B. This particular one was also used with Raspbmc, over HDMI, for the second TV in the house.&lt;/li&gt;
&lt;li&gt;Another Model B+, my second file server for my second 2TB drive. Due to the 100Mbps Ethernet limitation of the Pi, I used two separate Pi&amp;rsquo;s to reduce bandwidth bottlenecks to the two drives. At this point, I started naming my servers after spacecraft, and named this one &lt;a href=&#34;https://en.wikipedia.org/wiki/Voyager_program&#34;&gt;&amp;lsquo;Voyager&amp;rsquo;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Raspberry Pi 2, which introduced an improved processor over the OG Raspberry Pi, in a 3D printed case. I bought a few of these to try a multicast multi-room audio system, but testing did not go well, so I ended up using one of this batch in a standalone audio setup with a &lt;a href=&#34;https://www.hifiberry.com/shop/boards/hifiberry-amp2/&#34;&gt;HifiBerry Amp2&lt;/a&gt; and &lt;a href=&#34;https://github.com/mikebrady/shairport-sync&#34;&gt;Shairport-Sync&lt;/a&gt; along with some nice wired speakers on my deck, which I still use and love. This particular Raspberry Pi was later repurposed to run Octoprint, but I was unhappy with the performance of the older Pi and am rebuilding that for an upcoming project. Another Raspberry Pi 2 from this batch is currently in service as a USB print server, which has been reliable for many years.&lt;/li&gt;
&lt;li&gt;The brand new Raspberry Pi 3. At the time of this writing (September 2021), it&amp;rsquo;s very difficult to find a Raspberry Pi 3, 3+, or lower memory (lower cost) 4 in stock, so I just have one new one, and it&amp;rsquo;s already allocated to become an Octoprint server.&lt;/li&gt;
&lt;li&gt;This Raspberry Pi is in a &lt;a href=&#34;https://www.adafruit.com/product/1892&#34;&gt;very special case by Adafruit&lt;/a&gt;, designed to hold the OG Model B along with the &lt;a href=&#34;https://www.adafruit.com/product/1601&#34;&gt;OG PiTFT&lt;/a&gt; (back in the 26-pin days). I used this to build a user interface for a school project, loading the lite version of Raspbian (no desktop environment) and reading the touch drivers / writing the screen framebuffer raw. I published the GUI backend code &lt;a href=&#34;https://github.com/apalrd/palscreen&#34;&gt;on github as &amp;lsquo;palscreen&amp;rsquo;&lt;/a&gt;, but did not publish the other project files. Keeping with my space naming theme, I named this one &lt;a href=&#34;https://en.wikipedia.org/wiki/Discovery_One&#34;&gt;&amp;lsquo;Discovery-One&amp;rsquo;&lt;/a&gt;, after the manned spacecraft from &amp;lsquo;2001: A Space Odyssey&amp;rsquo;, as the touchscreen makes this a &amp;lsquo;manned&amp;rsquo; Raspberry Pi.&lt;/li&gt;
&lt;/ol&gt;
</content>
    </item>
    
    <item>
      <title>Raspberry Pi Follow-Up: Backing Up Zigbee2MQTT</title>
      <link>https://www.apalrd.net/posts/2021/zigbee_backup/</link>
      <pubDate>Sat, 18 Sep 2021 19:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/zigbee_backup/</guid>
      <description>After my scare with the Z-wave controller dying due to SD card failure (See the blog post), I decided that my Zigbee network is important enough to back up, especially because a whole lot more important data is stored on disk rather than in the dongle as with Z-wave. I&amp;rsquo;m going to follow the same path I took in the Z-wave blog, but for Zigbee2MQTT. Since it&amp;rsquo;s running &amp;lsquo;bare&amp;rsquo; on a raspberry pi, I can&amp;rsquo;t just backup the whole virtual machine.</description>
      <content>&lt;p&gt;After my scare with the Z-wave controller dying due to SD card failure (&lt;a href=&#34;https://www.apalrd.net/posts/2021/raspi_hardening/&#34;&gt;See the blog post&lt;/a&gt;), I decided that my Zigbee network is important enough to back up, especially because a whole lot more important data is stored on disk rather than in the dongle as with Z-wave. I&amp;rsquo;m going to follow the same path I took in the Z-wave blog, but for Zigbee2MQTT. Since it&amp;rsquo;s running &amp;lsquo;bare&amp;rsquo; on a raspberry pi, I can&amp;rsquo;t just backup the whole virtual machine. Here&amp;rsquo;s the solution I came up with.&lt;/p&gt;
&lt;p&gt;First, &lt;a href=&#34;https://www.apalrd.net/posts/2021/autofs/&#34;&gt;Install Autofs&lt;/a&gt; according to my other blog post. Setup a folder on your NAS to keep backups for Zigbee2MQTT, and mount that directory with autofs to /mnt/backup&lt;/p&gt;
&lt;p&gt;Next, we need to find where zigbee2mqtt is storing its local data. In my case, I installed it with npm, and the data directory is at /opt/zigbee2mqtt/data. This contains your configuration.yaml, which is important, along with other internal files used by Zigbee2MQTT (such as database.db).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to use essentially the same backup script as before, where I take the day of the week and append it to the filename so I automatically keep the last 7 days of backups. I keep the file on the NAS in the backup directory so the backup won&amp;rsquo;t fill the SD card with backups if the NAS doesn&amp;rsquo;t mount, since it can&amp;rsquo;t access the file. I named the shell script /mnt/backup/backup.sh&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;####################################&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Backup the Zigbee2MQTT data directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;####################################&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Create archive filename based on the day of the week&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;day&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;date +%A&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Backup the files using tar.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar czf /mnt/backup/zigbee_data_$day.tar.gz /opt/zigbee2mqtt/data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, edit the root user&amp;rsquo;s crontab so it will run all the time once per day:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo crontab -e
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the new contents - this will run at the 0 minute of the 0 hour (midnight), all days of all weeks of all months (so every day).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 * * * bash /mnt/backup/backup.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The End. After a week, there should be 7x .tar.gz files in the backup directory (Which is mounted from the NAS and can be managed according to your backup and long term storage strategy from there).&lt;/p&gt;
&lt;p&gt;Beware when extracting the archive that it restores permissions, so you need to chmod the folder once you restore it to give yourself permissions. I also realized with this that some of my Pi&amp;rsquo;s never had their timezone set, so they are still on UTC time. If that&amp;rsquo;s the case, you can sudo raspi-config to change it.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Not Every Project Works, And That&#39;s Okay</title>
      <link>https://www.apalrd.net/posts/2021/rtlamr/</link>
      <pubDate>Thu, 16 Sep 2021 22:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/rtlamr/</guid>
      <description>In my previous tests using Software Defined Radio (SDR), I used rtl_433 to successfully receive data from an outdoor weather station sensor. Always seeking more data, I found rtlamr - a tool which decodes smart meter data. I don&amp;rsquo;t really need to read smart meter data since the only smart meter I have is my power meter and I already have my own meter for that, but I still was excited to give it a try and see what I could find!</description>
      <content>&lt;p&gt;In my previous tests using Software Defined Radio (SDR), I used rtl_433 to successfully receive data from an &lt;a href=&#34;https://www.apalrd.net/projects/2021/rtl433/&#34;&gt;outdoor weather station sensor&lt;/a&gt;. Always seeking more data, I found &lt;a href=&#34;https://github.com/bemasher/rtlamr&#34;&gt;rtlamr&lt;/a&gt; - a tool which decodes smart meter data. I don&amp;rsquo;t really need to read smart meter data since the only smart meter I have is my power meter and I already have &lt;a href=&#34;https://www.apalrd.net/projects/2020/power_meter/&#34;&gt;my own meter for that&lt;/a&gt;, but I still was excited to give it a try and see what I could find! But projects don&amp;rsquo;t always go according to plan, and that&amp;rsquo;s perfectly normal when trying new things!&lt;/p&gt;
&lt;p&gt;After reading the documentation, I ran outside to snap a pic of the meter itself (with all the numbers clearly in view). I found out that I have an Itron AMI-4 meter. According to the  &lt;a href=&#34;https://github.com/bemasher/rtlamr/wiki/Compatible-Meters&#34;&gt;RTLAMR Compatible Meters page&lt;/a&gt;, it should be supported. So, I figured it would be a simple, fun project to get rtlamr to read my smart meter data, and write some sort of MQTT connector to push the data to Home Assistant since it seems like the only data output path is to InfluxDB at this point (which isn&amp;rsquo;t a bad option, just not my preference).&lt;/p&gt;
&lt;p&gt;Since I currently only own one SDR dongle (the struggle of tying up fun hardware in permanent projects!), I quickly shut down my &lt;a href=&#34;https://www.apalrd.net/projects/2021/rtl433/&#34;&gt;rtl_433 server&lt;/a&gt; and borrowed the SDR dongle, connecting it to my Windows desktop. I played with Windows for a bit to get the software installed, as one does for primarily Linux-focused software. Once I did this, I eventually got rtlamr up and running, and left it for a half hour to try and find packets from the meter (they should come every few minutes).&lt;/p&gt;
&lt;p&gt;Packets never came. I tried enabling &amp;lsquo;all&amp;rsquo; decoders, a few different frequencies, nothing. No results. At this point, I was slightly disappointed that my easy one-day project wasn&amp;rsquo;t working out, and I started reading through the rtlamr discussions on Github. I eventually found what I was looking for - The AMI-4 can be configured to support the protocols rtlamr can decode, but just because it is capable does not mean my utility company has configured it this way. It supports 900Mhz and Zigbee, and some of the branding on the meter indicates it&amp;rsquo;s configured in Zigbee mode. So, I&amp;rsquo;m out of luck, and my day of experimentation was wasted.&lt;/p&gt;
&lt;p&gt;But, despite not getting the project to work, I still enjoyed it, and that&amp;rsquo;s what matters. I had fun playing with SDR, experimenting with the software, and learning a bit more about how smart meters work. Maybe, in the future, I&amp;rsquo;ll have a smart meter that does use 900Mhz, but for now, I&amp;rsquo;m on to the next project.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Low-Cost 433Mhz Sensor Network with rtl_433 on Raspberry Pi</title>
      <link>https://www.apalrd.net/posts/2021/rtl433/</link>
      <pubDate>Thu, 16 Sep 2021 08:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/rtl433/</guid>
      <description>I&amp;rsquo;m fairly protocol agnostic in my home automation system, and that&amp;rsquo;s one of the benefits of building something with open source software like Home Assistant - there&amp;rsquo;s no vendor lock in and you can pretty much connect anything you can pull data from into it. While I&amp;rsquo;ve set up a Zigbee network for my blinds and ordered a ton of cheap sensors from Aliexpress to test, and set up a reliable Z-Wave network with more expensive sensors and lighting dimmers, I&amp;rsquo;m always looking to expand the wealth of data I can capture.</description>
      <content>&lt;p&gt;I&amp;rsquo;m fairly protocol agnostic in my home automation system, and that&amp;rsquo;s one of the benefits of building something with open source software like Home Assistant - there&amp;rsquo;s no vendor lock in and you can pretty much connect anything you can pull data from into it. While I&amp;rsquo;ve set up a Zigbee network for my blinds and ordered a ton of cheap sensors from Aliexpress to test, and set up a reliable Z-Wave network with more expensive sensors and lighting dimmers, I&amp;rsquo;m always looking to expand the wealth of data I can capture. In this project, I start up a 433Mhz receiving system to capture data from cheap &amp;lsquo;weather stations&amp;rsquo; and other consumer electronics which need decently long range wireless and employ poor to no data security.&lt;/p&gt;
&lt;h2 id=&#34;reliably-sensing-outdoors&#34;&gt;Reliably Sensing Outdoors&lt;/h2&gt;
&lt;p&gt;One of the struggles I&amp;rsquo;ve had with my &lt;a href=&#34;https://www.apalrd.net/projects/2019/onewire/&#34;&gt;Onewire&lt;/a&gt; network is sensing the outdoor temperature. I&amp;rsquo;ve replaced the outdoor temperature sensor once already, and both sensors have eventually died outdoors. I could spend more effort potting the sensor so it stops corroding, but I&amp;rsquo;d rather spend the few dollars to buy an off the shelf solution that&amp;rsquo;s outdoor resistant. I also really want to measure outdoor humidity, and these cheap &amp;lsquo;weather stations&amp;rsquo; are a perfect hardware solution to the problem.&lt;/p&gt;
&lt;p&gt;Under the hood, these sensors are very primitive. You mount them outdoors somewhere out of direct sunlight (in my case, under the front porch), and they transmit a signal containing the temperature and relative humidity to an indoor unit, which also measures temperature and relative humidity and displays both of them for you. The whole kit costs only $33 with both units with humidity, and you can buy a replacement outdoor unit for $13. I bought the &lt;a href=&#34;https://www.acurite.com/shop-all/weather-instruments/weather-sensors-and-parts/replacement-parts/indoor-outdoor-temperature-humidity-sensor.html&#34;&gt;Acurite 609TXC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But, how do you pair your replacement outdoor unit with your indoor unit? You don&amp;rsquo;t. The outdoor unit doesn&amp;rsquo;t even have a unique ID to pair with. When you put the batteries in, it generates a random number which it calls its ID, and transmits a data packet with no encryption containing that ID, the temperature, the humidity, and a simple checksum periodically until the battery dies. Presumably the indoor unit has some logic to deal with multiple outdoor units in the same area. In my case, I don&amp;rsquo;t even have an indoor unit, just the replacement outdoor unit, and a Software Defined Radio (SDR) dongle.&lt;/p&gt;
&lt;p&gt;When I went to install the sensor, I found an old remote unit that&amp;rsquo;s been there for at least 15 years at this point, with significant battery corrosion. Hopefully this sensor lasts at least a few years.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Acurite 609TXC sensor installed under porch&#34; src=&#34;https://www.apalrd.net/posts/2021/rtl433/acurite609.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Sensor Installed - I&#39;m not the first person to install a sensor here&lt;/div&gt;
&lt;h2 id=&#34;what-is-software-defined-radio-sdr&#34;&gt;What is Software Defined Radio (SDR)?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Software-defined_radio&#34;&gt;Wikipedia is always a good place to start&lt;/a&gt;. In short, SDR implements radio frequency components traditionally implemented in hardware using software combined with a basic analog frontend. In this case, the &lt;a href=&#34;https://github.com/merbanan/rtl_433&#34;&gt;rtl_433&lt;/a&gt; program uses a dongle which tunes to a specific frequency and returns analog samples, which can be demodulated and converted into a digital signal using software. The hardware does RF downconversion and analog sampling, and that&amp;rsquo;s it. The analog samples are processed by software.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/merbanan/rtl_433&#34;&gt;rtl_433&lt;/a&gt; project implements decoders for a lot of low cost consumer electronics (including the Acurite 609TXC which I bought), but it requires a SDR backend which implements support for SDR hardware. The normal backend is &lt;a href=&#34;http://osmocom.org/projects/rtl-sdr/wiki&#34;&gt;RTL-SDR&lt;/a&gt; (hence the name rtl_433), which is part of the &lt;a href=&#34;http://osmocom.org/&#34;&gt;Osmocom&lt;/a&gt; (open source mobile communications) family of projects. RTL-SDR implements a SDR receiver using the Realtek RTL2832U chip, which is commonly used inside USB TV tuners. There is now a very healthy ecosystem surrounding the RTL-SDR as it&amp;rsquo;s a very low cost entry into software defined radio, although being limited to receive only operation. I purchased a &lt;a href=&#34;https://www.nooelec.com/store/sdr/sdr-receivers/nesdr/nesdr-mini-2.html&#34;&gt;Nooelec NESDR Mini 2&lt;/a&gt; which is specifically sold for use with RTL-SDR, and only cost $25 as of this writing. It even includes a little remote antenna.&lt;/p&gt;
&lt;h2 id=&#34;installing-rtl_433-on-a-raspberry-pi&#34;&gt;Installing rtl_433 on a Raspberry Pi&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m going to install rtl_433 on a Raspberry Pi so I can locate my SDR dongle in a good location in the house, and my Home Assistant install is virtualized making hardware passthrough more work than using a separate Raspberry Pi.&lt;/p&gt;
&lt;p&gt;In short:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#Install dependencies - rtl-sdr is currently available for Pi as of this writing
sudo apt-get update
sudo apt-get install libtool libusb-1.0.0-dev librtlsdr-dev rtl-sdr doxygen git cmake

#rtl_433 is not currently available for Pi as a package
#it made it in for Debian Bullseye, but not Buster
git clone https://github.com/merbanan/rtl_433.git

#Generate the makefile with cmake
cd rtl_433
mkdir build
cd build
cmake ../

#Actually build it (this takes awhile)
make

#Install it
sudo make install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now to set configure it, test it, and set it up to run as a service.&lt;/p&gt;
&lt;h2 id=&#34;configuring-rtl_433-for-433mhz-sensors-and-mqtt&#34;&gt;Configuring rtl_433 for 433Mhz sensors and MQTT&lt;/h2&gt;
&lt;p&gt;There are a few really important config options for rtl_433 itself. The help (rtl_433 -h) is quite&amp;hellip; helpful in setting the command line arguments.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What frequency to tune to&lt;/li&gt;
&lt;li&gt;Which decoders to enable&lt;/li&gt;
&lt;li&gt;How to export the data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my case, the answer to these questions was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;433Mhz (duh), although 315 and ~900s are also somewhat popular. 433Mhz happens to be the default, so no argument required&lt;/li&gt;
&lt;li&gt;The default decoders&lt;/li&gt;
&lt;li&gt;MQTT, with the topic containing as much information as possible (-F mqtt), using the default MQTT options. By default, it publishes each measurement to a separate topic, instead of JSON-encoding the resulting data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The required command line for me was thus:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rtl_433 -C si -F &amp;quot;mqtt://&amp;lt;server&amp;gt;:1883,user=&amp;lt;user&amp;gt;,pass=&amp;lt;pass&amp;gt;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are of course more options you can use if you&amp;rsquo;d like, such as a custom MQTT topic structure, setting the retain flag, and enabling/disabling different demodulators. In my case, 433Mhz is the default frequency (no argument required), SI units are preferred, and I set the MQTT output and broker parameters while using the default topic structure. The default topic structure is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rtl_433/&amp;lt;hostname&amp;gt;/devices/&amp;lt;type&amp;gt;/&amp;lt;subtype&amp;gt;/&amp;lt;channel&amp;gt;/&amp;lt;id&amp;gt;/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now it&amp;rsquo;s time to find out if it&amp;rsquo;s publishing, using &lt;a href=&#34;https://mqtt-explorer.com/&#34;&gt;MQTT Explorer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;rtl_433 in MQTT Explorer&#34; src=&#34;https://www.apalrd.net/posts/2021/rtl433/mqtt_view.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;What&#39;s that? A tire pressure monitoring sensor? Yes.&lt;/div&gt;
&lt;h2 id=&#34;running-rtl_433-as-a-service-with-systemd&#34;&gt;Running rtl_433 as a service with systemd&lt;/h2&gt;
&lt;p&gt;Ideally we can setup a service so rtl_433 starts on boot, and creating a systemd service is a good way to do that.&lt;/p&gt;
&lt;p&gt;First we need to create the service file in a location where systemd expects it, then open it for editing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo touch /etc/systemd/system/rtl433.service
sudo chmod 664 etc/systemd/system/rtl433.service
sudo nano /etc/systemd/system/rtl433.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we need to write our service config file for systemd (and save it)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=rtl_433 SDR Receiver Daemon
After=network-online.target

[Service]
ExecStart=/usr/local/bin/rtl_433 -C si -F &amp;quot;mqtt://&amp;lt;broker&amp;gt;:1883,user=&amp;lt;user&amp;gt;,pass=&amp;lt;pass&amp;gt;&amp;quot;
Restart=always

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a pretty basic service that should do what we want. Feel free to read the systemd docs (&lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/systemd.service.html&#34;&gt;systemd.service&lt;/a&gt;, &lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/systemd.unit.html&#34;&gt;systemd.unit&lt;/a&gt;) for more info on what can go in this file. Note that ExecStart needs to be a full path, so you might need to track down rtl_433 like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;which rtl_433
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After writing the service file, you need to tell systemd to reload it&amp;rsquo;s daemon files (since we modified them), then start the service (launch it now), then enable the service (set it to launch on boot).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl start rtl433
sudo systemctl enable rtl433
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also view the latest bit of the log to check for any errors&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl status rtl433
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hopefully it looks something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  Loaded: loaded (/etc/systemd/system/rtl433.service; enabled; vendor preset: enabled)
  Active: active (running) since Wed 2021-09-15 11:44:23 EDT; 44s ago
 Main PID: 4005 (rtl_433)
    Tasks: 2 (limit: 2059)
 CGroup: /system.slice/rtl433.service
         └─4005 /usr/local/bin/rtl_433 -C si -F mqtt://&amp;lt;broker&amp;gt; 1883

Sep 15 11:44:24 zeus rtl_433[4005]: Found Rafael Micro R820T tuner
Sep 15 11:44:24 zeus rtl_433[4005]: Exact sample rate is: 250000.000414 Hz
Sep 15 11:44:24 zeus rtl_433[4005]: [R82XX] PLL not locked!
Sep 15 11:44:24 zeus rtl_433[4005]: Sample rate set to 250000 S/s.
Sep 15 11:44:24 zeus rtl_433[4005]: Tuner gain set to Auto.
Sep 15 11:44:24 zeus rtl_433[4005]: Tuned to 433.920MHz.
Sep 15 11:44:24 zeus rtl_433[4005]: Allocating 15 zero-copy buffers
Sep 15 11:44:25 zeus rtl_433[4005]: baseband_demod_FM: low pass filter for 250000 Hz at cutoff 25000 Hz, 40.0 us
Sep 15 11:44:26 zeus rtl_433[4005]: MQTT Connected...
Sep 15 11:44:26 zeus rtl_433[4005]: MQTT Connection established.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;adding-rtl_433-sensors-to-home-assistant&#34;&gt;Adding rtl_433 sensors to Home Assistant&lt;/h2&gt;
&lt;p&gt;Home Assistant prefers MQTT Discovery, where devices publish to the homeassistant topic with information that points HA on topics of interest and how to decode them. I use this with Zigbee2MQTT, and there are some Python scripts that try to do this with rtl_433, but given the vast number of useless junk that you find on 433Mhz (such as TPMS sensors), I decided to avoid MQTT Discovery and manually enter the sensors in the yaml configuration. In this case, I found that the ID of my sensor is 252 using MQTT Explorer. The ID will change when you replace the batteries and you will have to update Home Assistant&amp;rsquo;s yaml configuration with the new ID, but it should keep the same entity as before.&lt;/p&gt;
&lt;p&gt;The 609TXC publishes 9 variables to MQTT via rtl_433: time, ID, battery_ok (boolean), temperature (number), humidity (number), status, and mic. Of these, Time is not needed (Home Assistant will log the time the message was received), ID is part of the topic, the next three should be read by Home Assistant as sensors or binary_sensors, status always appears to be 2, and mic will always be CHECKSUM. To create sensors in Home Assistant for the three signals we would like to read, we need to edit sensor.yaml and binary_sensor.yaml. If you don&amp;rsquo;t have either of these files, you need to add to the sensor: and binary_sensor: section in configuration.yaml. Ideally, your configuration.yaml includes pointers to files for sensors and binary sensors, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sensor: !include sensor.yaml
binary_sensor: !include binary_sensor.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add to binary_sensor.yaml (or your binary_sensor section):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Acurite outdoor temp/humid sensor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Outdoor Temperature Humidity Battery OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;outdoor_temperature_humidity_battery_ok&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rtl_433/zeus/devices/Acurite-609TXC/252/battery_ok&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;payload_on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;payload_off&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add to sensor.yaml (or your sensor section):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Outdoor temperature and humidity sensor (Acurite 609TXC)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Outdoor Temperature&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;outdoor_temperature&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rtl_433/zeus/devices/Acurite-609TXC/252/temperature_C&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;°C&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Outdoor Humidity&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;outdoor_humidity&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rtl_433/zeus/devices/Acurite-609TXC/252/humidity&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, replace zeus with the hostname of your Pi and 252 with the ID of your sensor, or replace the path entirely if you used a different sensor than I did. You can also copy the path directly from MQTT Explorer.&lt;/p&gt;
&lt;p&gt;Make sure to go to Configuration -&amp;gt; Server Control and click &amp;lsquo;Check Configuration&amp;rsquo;, and that you fix any errors it returns before restarting Home Assistant. It gets angry if you mess up the YAML.&lt;/p&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.acurite.com/shop-all/weather-instruments/weather-sensors-and-parts/replacement-parts/indoor-outdoor-temperature-humidity-sensor.html&#34;&gt;Acurite model 609TXC Outdoor Unit&lt;/a&gt; - Select &amp;lsquo;Sensor #2&amp;rsquo;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.nooelec.com/store/sdr/sdr-receivers/nesdr/nesdr-mini-2-plus.html&#34;&gt;Nooelec NESDR Mini 2+ for RTL-SDR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Raspberry Pi - Preferably a Model 2, 3, or 4, but any will work if the Pi has no other tasks&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/merbanan/rtl_433&#34;&gt;rtl_433 installed on your Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mqtt-explorer.com/&#34;&gt;MQTT Explorer installed on your host&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>A Quick Primer on Autofs</title>
      <link>https://www.apalrd.net/posts/2021/autofs/</link>
      <pubDate>Wed, 15 Sep 2021 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/autofs/</guid>
      <description>As mentioned in my last blog post, I setup an autofs share to mount my NAS for backups. Since I&amp;rsquo;ve always used fstab in the past to mount this, and it&amp;rsquo;s quite unreliable for cifs shares, and some internet articles go into way more detail than necessary on setting up autofs, here&amp;rsquo;s a very quick overview on setting up samba / CIFS shares with autofs on Raspberry Pi OS (or any other Debian / Ubuntu based system).</description>
      <content>&lt;p&gt;As mentioned in my last blog post, I setup an autofs share to mount my NAS for backups. Since I&amp;rsquo;ve always used fstab in the past to mount this, and it&amp;rsquo;s quite unreliable for cifs shares, and some internet articles go into way more detail than necessary on setting up autofs, here&amp;rsquo;s a very quick overview on setting up samba / CIFS shares with autofs on Raspberry Pi OS (or any other Debian / Ubuntu based system). I tested this on Raspberry Pi OS (formerly Rasbian) Buster.&lt;/p&gt;
&lt;h2 id=&#34;install-autofs&#34;&gt;Install Autofs&lt;/h2&gt;
&lt;p&gt;First you need the package. Often a good idea to reboot after doing things with apt.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install autofs
sudo shutdown -r now
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;add-a-samba-shares-file-to-the-master-autofs-file&#34;&gt;Add a samba shares file to the master autofs file&lt;/h2&gt;
&lt;p&gt;Edit the autofs master file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/auto.master
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add a line pointing to a (yet non existant) samba config file&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/- /etc/auto.smb.shares --timeout 15 browse
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Brekaing down this command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/- indicates that the following file should be mounted relative to / (i.e. all paths in the file are absolute, if you put /mnt here, then everything in auto.smb.shares would be mounted below /mnt)&lt;/li&gt;
&lt;li&gt;/etc/auto.smb.shares is the file we will create to list our SMB shares&lt;/li&gt;
&lt;li&gt;timeout is how long to keep the shares mounted&lt;/li&gt;
&lt;li&gt;browse seems to work well&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;add-a-new-samba-shares-file-and-add-a-share-to-it&#34;&gt;Add a new samba shares file and add a share to it&lt;/h2&gt;
&lt;p&gt;Edit the samba shares file we pointed to earlier&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/auto.smb.shares
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add your new mount point&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/mnt/data -fstype=cifs,rw,username=&amp;lt;user&amp;gt;,password=&amp;lt;pass&amp;gt;,credentials=&amp;lt;file&amp;gt;,noperm,dir_mode=0777,file_mode=0777 ://server/share
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not all of these options should be used all the time.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/mnt/data - the path on the local system to mount to&lt;/li&gt;
&lt;li&gt;-fstype=cifs - always needed for samba shares&lt;/li&gt;
&lt;li&gt;rw - enable read/write access to the share&lt;/li&gt;
&lt;li&gt;username=&amp;lt;user&amp;gt; - put the username here or use a credentials file&lt;/li&gt;
&lt;li&gt;password=&amp;lt;password&amp;gt; - put the password here or use a dredentials file&lt;/li&gt;
&lt;li&gt;credentials=&amp;lt;file&amp;gt; - Alternative to putting the uname/password here, point to a file that has the credentials&lt;/li&gt;
&lt;li&gt;noperm - ignore permissions for local users accessing the share&lt;/li&gt;
&lt;li&gt;dir_mode / file_mode - default UNIX permissions for directories and files on the Windows share&lt;/li&gt;
&lt;li&gt;://server/share - you can put in an IP or hostname, and the share can be multiple folders deep&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you created a credentials file, it needs to look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;username=&amp;lt;user&amp;gt; 
password=&amp;lt;pass&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure the mount point exists&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo mkdir /mnt/data
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;restart-autofs-so-it-finds-the-new-config-entries&#34;&gt;Restart autofs so it finds the new config entries&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart autofs
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;try-to-access-the-share&#34;&gt;Try to access the share&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;ls /mnt/data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;rsquo;s It! Have fun. If you&amp;rsquo;re having trouble, make sure you rebooted after installing everything, otherwise you might not have the cifs kernel module loaded.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Raspberry Pi SD Failure, and Backing Up ZWaveJS2MQTT</title>
      <link>https://www.apalrd.net/posts/2021/raspi_hardening/</link>
      <pubDate>Tue, 14 Sep 2021 11:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/raspi_hardening/</guid>
      <description>I got my Z-Wave Raspberry Pi setup a few weeks ago, and then spent a ton of time setting up my Bedroom Lights, Bathroom Fan+Light, and ordered even more Z-wave hardware. I also started up an RTL-433 server for a yet unfinished project, and about a week later, Home Assistant suddenly reported all of my Z-wave devices offline. Home Assistant was unable to connect to the WebSocket of ZWaveJS. The Pi was acting really weird.</description>
      <content>&lt;p&gt;I got my Z-Wave Raspberry Pi setup a few weeks ago, and then spent a ton of time setting up my &lt;a href=&#34;https://www.apalrd.net/projects/2021/zwave_intro/&#34;&gt;Bedroom Lights&lt;/a&gt;, &lt;a href=&#34;https://www.apalrd.net/projects/2021/smart_bathroom/&#34;&gt;Bathroom Fan+Light&lt;/a&gt;, and ordered even more Z-wave hardware. I also started up an RTL-433 server for a yet unfinished project, and about a week later, Home Assistant suddenly reported all of my Z-wave devices offline. Home Assistant was unable to connect to the WebSocket of ZWaveJS. The Pi was acting really weird. SSH responded but rejected my login, and when I plugged in an HDMI cable and rebooted it got a kernel panic due to mmc driver failure. The SD card had failed. It wasn&amp;rsquo;t a new SD card, so I guess I should buy a bulk pack and stop re-using them. Since I really liked having a Z-Wave network, I want to make sure that I properly setup the new raspberry pi OS install to prevent excessive logging from taking down the whole thing in the future. This also gives me a huge appreciation for how nice the backup features of virtual machines are, and how much I miss them on the Raspberry Pi. I don&amp;rsquo;t have a backup of the Z-Wave network, so that&amp;rsquo;s another feature that would be nice to consider in the second try.&lt;/p&gt;
&lt;p&gt;I started with a brand new SD card and imaged it with Raspberry Pi OS in Etcher. I did the usual raspi-config, set the hostname, timezone, apt-get update/upgrade, the usual. Then I proceeded to install ZWaveJS2MQTT according to their instructions (using the Snap package). Thankfully, a lot of the Z-wave network parameters are actually stored in the dongle, so I didn&amp;rsquo;t have to re-associate all of the devices (whew!). But, the metadata is stored locally, and was lost. Home Assistant didn&amp;rsquo;t care about the loss of metadata, since it keeps its own metadata for each node ID, but things like node names in zwavejs2mqtt were gone. Not nearly as bad as I thought it would be.&lt;/p&gt;
&lt;p&gt;My next plan is to start backing up the zwavejs2mqtt install&amp;rsquo;s store folder for safe keeping. With the snap package it&amp;rsquo;s stored in:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/var/snap/zwavejs2mqtt/current
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So I can just make an autofs mount to the place I keep backups on my NAS, then tar that directory into the backup folder. This won&amp;rsquo;t keep revisions, but it will keep the latest copy. What I really want is to keep the last few days of backups (presumably I&amp;rsquo;d notice something within a few days?), but with as simple a script as possible. I found &lt;a href=&#34;https://ubuntu.com/server/docs/backups-shell-scripts&#34;&gt;this script&lt;/a&gt; helpful in creating my own. After mounting my desired backup location using autofs to /mnt/backup, I wrote my backup script and added it to root&amp;rsquo;s crontab.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;####################################&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Backup the ZWaveJS2MQTT stores directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;####################################&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Create archive filename based on the day of the week&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;day&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;date +%A&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Backup the files using tar. Need h since &amp;#39;current&amp;#39; is a symlink from Snap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar chzf /mnt/backup/zeus_store_$day.tar.gz /var/snap/zwavejs2mqtt/current
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After stripping down the script to the bare minimum, it will generate a new tar.gz file for each day of the week, overwriting the previous. Now I need to add a cron job to run the backup script&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo crontab -e
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the new contents - this will run at the 0 minute of the 0 hour (midnight), all days of all weeks of all months (so every day).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 * * * bash /mnt/backup/backup.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After making sure my backups are in order, I need to make the SD card stop dying. After reading some Raspberry Pi specific help, it seems like /var/run used to be on the SD card but is now a symlink to /run, which is a tmpfs in RAM. So that&amp;rsquo;s good. /var/log is still on the SD card and I could make that a tmpfs as well, but I&amp;rsquo;m not sure if that&amp;rsquo;s actually being written to regularly. It doesn&amp;rsquo;t seem like ZWaveJS2MQTT is creating any trouble on the filesystem, so maybe it was RTL-433 that was on my last setup, and I&amp;rsquo;ll need to more closely monitor it when I get to fixing that.&lt;/p&gt;
&lt;p&gt;At this point, ZWave is working again (very happy about that), so I need to setup RTL-433 again, and write the project page on my 433Mhz sensors. More to come!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Re-Using Old XFINITY Security Hardware in a Real Automation System</title>
      <link>https://www.apalrd.net/posts/2021/xfinity_hardware/</link>
      <pubDate>Mon, 13 Sep 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/xfinity_hardware/</guid>
      <description>A number of years ago, my dad subscribed to Comcast / Xfinity&amp;rsquo;s security system to get a discount on internet, then un-subscribed when the promotional period ended. Their system relied on a Technicolor touchscreen which acted as a Zigbee hub, connected to a number of Zigbee door switches and a Zigbee wall moounted keypad. They wanted their touchscreen back, but didn&amp;rsquo;t care about all of the dirt cheap sensors or the keypad, so they&amp;rsquo;ve been sitting in place in the house for many years now.</description>
      <content>&lt;p&gt;A number of years ago, my dad subscribed to Comcast / Xfinity&amp;rsquo;s security system to get a discount on internet, then un-subscribed when the promotional period ended. Their system relied on a Technicolor touchscreen which acted as a Zigbee hub, connected to a number of Zigbee door switches and a Zigbee wall moounted keypad. They wanted their touchscreen back, but didn&amp;rsquo;t care about all of the dirt cheap sensors or the keypad, so they&amp;rsquo;ve been sitting in place in the house for many years now. In this project, I revived them with new batteries and added them to my Zigbee network, trying to find a good use for them.&lt;/p&gt;
&lt;h2 id=&#34;the-hardware&#34;&gt;The Hardware&lt;/h2&gt;
&lt;p&gt;There were two pieces of hardware which I had available. The door contacts are Visonic MCT-340 SMA magnetic sensors (with temperature sensing, even), and the keypad is a Centralite 3400-D. Both of them are already supported by Zigbee2MQTT, which I use to manage my Zigbee network.&lt;/p&gt;
&lt;p&gt;The Visonic sensors were all mounted with double sided foam tape and were kinda ugly, but they&amp;rsquo;ve been there for years so I don&amp;rsquo;t want to mess with them. One of them had been installed on top of 3 layers of foam tape to prevent the door from hitting the magnet, so I spent some time with the foam tape getting that sensor and magnet in a less ugly position without moving them too far. The sensors need CR2032 batteries, so I bought a bulk pack since it&amp;rsquo;s a fairly common size for this low cost automation stuff. In Zigbee2MQTT they report the switch status, the tamper status (if the battery cover is removed), the temperature in integer degrees celsuis, battery %, and link quality. Nothing super special here. They seem to work fine, latency isn&amp;rsquo;t bad, nothing much to write home about. They were basically free and now they are useful for only the cost of a new battery.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Visonic MCT-340 SMA sensor&#34; src=&#34;https://www.apalrd.net/posts/2021/xfinity_hardware/visonic_sensor.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Visonic MCT-340 SMA Magnetic Door/Window Sensor&lt;/div&gt;
&lt;p&gt;The Centralite keypad is .. special? It has a wall bracket which is screwed to the wall, but it readily clips off the bracket. It has a tamper switch to detect when it&amp;rsquo;s removed from the wall bracket, and this switch is also used for pairing, but it doesn&amp;rsquo;t seem to report the tamper status in Zigbee2MQTT. It does report an &amp;lsquo;occupancy&amp;rsquo; status, but I haven&amp;rsquo;t found out why, it never triggers it, even when waking the keypad up by waving my hand over it. It uses two CR123A batteries, which is also fairly common with low cost automation stuff, so again I bought a bulk pack.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Centralite 3400-D Keypad&#34; src=&#34;https://www.apalrd.net/posts/2021/xfinity_hardware/centralite_keypad.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Centralite 3400-D Keypad&lt;/div&gt;
&lt;h2 id=&#34;keypad-codes&#34;&gt;Keypad Codes&lt;/h2&gt;
&lt;p&gt;The keypad reports a topic named &amp;lsquo;Action&amp;rsquo; whenever it detects a valid keycode. It does not validate the keycode itself, rather it passes the keys typed to the Zigbee controller which is supposed to process the keycode and return if the key was valid or not. It only accepts 4 digit keycodes, and transmits the entire code as soon as the 4th digit is pressed. I was hoping to be able to enter shorter key combinations to control automations, sorta like a many-button remote, but it absolutely must be 4 digits for the keypad to send it. If you only type 4 digits, it will send a &amp;lsquo;disarm&amp;rsquo; command with the keycode. If you first press one of the 3 buttons on the top, it will instead send one of the arm variants (arm all, arm day, arm night). So, you get an event from the keypad with 4 numbers and one of 4 modes associated with it, and you need to respond for the keypad to beep a happy beep or not respond for the keypad to beep a sad beep. In addition, if the code is incorrect (or it doesn&amp;rsquo;t get a Zigbee response confirming it), it will wait a few seconds before letting you try again.&lt;/p&gt;
&lt;p&gt;Because of the complex logic required to check if the keypad code is valid and carry through the transaction ID of the keypad when responding, I decided to implement the log in Node-Red, using the built-in Home Assistant add-on and integration. I wrote a Node-Red flow which demonstrates how to deal with the keypad, have a list of codes to check, and how to change or enable some of these codes from Home Assistant (using input_boolean and input_number, although you could also use a binary_sensor). This only deals with the keypad, you still need to use the associated alarm control panel logic in Home Assistant or your alarm panel integration to make a fully working alarm system. The Node-Red flow for this is available below.&lt;/p&gt;
&lt;p&gt;Of course, there&amp;rsquo;s no reason you need to limit yourself to only treating this keypad as an alarm keypad as I have. It would certainly be possible to set each &amp;lsquo;disarm code&amp;rsquo; to turn on or off a different entity, if you wish to use this as something more of a bedside automatino keypad. It&amp;rsquo;s not great for that, but with a little node-red magic it will definitely function. A Node-Red flow for this is also available.&lt;/p&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Visonic MCT-340 SMA as provided by XFINITY - You can do better with another Zigbee vendor, but they were free to me.&lt;/li&gt;
&lt;li&gt;Centralite 3400-D keypad as provided by XFINITY - You can probably do better here, although I don&amp;rsquo;t have a product suggestion to give&lt;/li&gt;
&lt;li&gt;Working &lt;a href=&#34;https://www.zigbee2mqtt.io/&#34;&gt;Zigbee2MQTT&lt;/a&gt; install&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/xfinity_hardware/nodered_keypad_flow.json&#34;&gt;Node-Red Flow to use Keypad as Alarm Keypad&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/xfinity_hardware/nodered_automation_flow.json&#34;&gt;Node-Red Flow to use Keypad as Automation Keypad&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>A Quick Infill Project</title>
      <link>https://www.apalrd.net/posts/2021/a_quick_infill_project/</link>
      <pubDate>Sun, 12 Sep 2021 14:17:00 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/a_quick_infill_project/</guid>
      <description>Everyone who has 3D printed something is at least vaguely aware of the concept of infill. Unless you want your 3D prints to be totally solid, you usually reduce the density of the center of the part, creating a number of solid layers around a central void. The percentage of this central void that is filled with material is known as the infill ratio. A lot of slicers will automatically pick some level of infill and some pattern to distribute the material in the most structurally sound way, but that doesn&amp;rsquo;t mean you have to stick to these settings.</description>
      <content>&lt;p&gt;Everyone who has 3D printed something is at least vaguely aware of the concept of infill. Unless you want your 3D prints to be totally solid, you usually reduce the density of the center of the part, creating a number of solid layers around a central void. The percentage of this central void that is filled with material is known as the infill ratio. A lot of slicers will automatically pick some level of infill and some pattern to distribute the material in the most structurally sound way, but that doesn&amp;rsquo;t mean you have to stick to these settings. With some clever slicer settings, you can make the infill visible from the outside of the part, giving a unique artistic view into the inards of 3D printing.&lt;/p&gt;
&lt;p&gt;Recently, I was asked to help make &amp;lsquo;MAKERSPACE&amp;rsquo; letters for a sign for a makerspace classroom. Emphaszing the process of 3D printing, I chose to expose the infill of each letter. I made a CAD model of each letter in FreeCAD, using the clearest font known to man, &lt;a href=&#34;https://en.wikipedia.org/wiki/Helvetica&#34;&gt;Helvetica&lt;/a&gt;. Being a Mac user, I had access to the TrueType for the true font, not the Arial knockoff. As I wanted the infill to be clearly visible in the final prints, I chose to use the Bold version for the wider stroke width.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Letter A with infill visible in PrusaSlicer&#34; src=&#34;https://www.apalrd.net/posts/2021/a_quick_infill_project/prusaA.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Letter A, in PrusaSlicer, using gyroid infill pattern&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Letter M and A with infill visible after printing&#34; src=&#34;https://www.apalrd.net/posts/2021/a_quick_infill_project/letterA.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Letters A as printed using gyroid infill pattern, next to letter M printed with line pattern&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Letter R, showint the true Helvetica font&#34; src=&#34;https://www.apalrd.net/posts/2021/a_quick_infill_project/letterR.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;How can you tell the real Helvetica? By the capital letter R. The tail should always be vertical, a diagonal tail indicates an inferor clone&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Complete Makerspace sign&#34; src=&#34;https://www.apalrd.net/posts/2021/a_quick_infill_project/sign.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Completed sign, using different infill patterns for each letter&lt;/div&gt;
</content>
    </item>
    
    <item>
      <title>Starting my Personal Website</title>
      <link>https://www.apalrd.net/posts/2021/starting_my_website/</link>
      <pubDate>Sat, 11 Sep 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/starting_my_website/</guid>
      <description>I&amp;rsquo;ve wanted to document my projects for a few years, after following plenty of other creators with excellent project documentation, but I&amp;rsquo;ve never found the time to start. This is my start. I&amp;rsquo;ve built my personal website, created content for back projects worth sharing with the world, and I&amp;rsquo;m committed to continuing to document and share the things that I make.
All In The Name I started off with choosing a name.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve wanted to document my projects for a few years, after following plenty of other creators with excellent project documentation, but I&amp;rsquo;ve never found the time to start. This is my start. I&amp;rsquo;ve built my personal website, created content for back projects worth sharing with the world, and I&amp;rsquo;m committed to continuing to document and share the things that I make.&lt;/p&gt;
&lt;h2 id=&#34;all-in-the-name&#34;&gt;All In The Name&lt;/h2&gt;
&lt;p&gt;I started off with choosing a name. I&amp;rsquo;ve used the name &amp;lsquo;apalrd&amp;rsquo; for many years as a personal account, and I decided to make that the domain name. But, I still had to choose a top-level domain. Do I want the trendy .tech? Personal .me? Slightly less expensive but also trendy .io? I settled for .net since it&amp;rsquo;s less expensive. It&amp;rsquo;s also a classic TLD, and fits well with the technology and homelab vibe.&lt;/p&gt;
&lt;h2 id=&#34;the-wild-west-of-internet-security&#34;&gt;The Wild West of Internet Security&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve experimented before with running self-hosted websites, and for awhile in the past I had a personal forum hosted at my house, accessible only to those friends who knew my free dynamic DNS name. I played with administering Linux servers starting all the way back with Ubuntu 6.06 Dapper Drake, on my parents used desktop. I was able to get a basic enough Apache and MySQL setup in the most insecure way, load phpBB and Drupal, and go to town. Back then, AIM was still the messenger of choice for a lot of people, Facebook had just launched to the public a few months prior, and this private forum is how my friends and I communicated with each other from our home computers.&lt;/p&gt;
&lt;p&gt;In the years since that forum, I&amp;rsquo;ve learned a lot about security. In fact, I&amp;rsquo;ve learned that security is something I really want to leave to the experts as much as possible. I&amp;rsquo;m also much more conscious of the proliferation of user tracking, and want to minimize how much my site feeds Big Data information on my viewers. To me, the best way to achieve all of this is to make the site completely static, not include any social media &amp;lsquo;share this&amp;rsquo; buttons, and not include advertising. Without any server-side code execution, the exploitable surface area is minimal, and with as little client-side code as possible, the site should load quickly on all devices, and should even look reasonably close to correct with Javascript disabled completely. In fact, I audit the view of the site using NoScript to make sure the site looks as I intend for those viewers who have chosen to block Javascript by default (and this is something I&amp;rsquo;d encourage everyone to use where possible).&lt;/p&gt;
&lt;h2 id=&#34;a-new-hope&#34;&gt;A New Hope&lt;/h2&gt;
&lt;p&gt;I use a tool called &lt;a href=&#34;https://gohugo.io/&#34;&gt;Hugo&lt;/a&gt; to generate this site, and store the contents of the site in a Git repository, entirely separate from the public server. Pages are written in Markdown, a simple textual language that can be rendered directly to HTML by Hugo, and the site&amp;rsquo;s theme can be added to all pages when generated. After page generation, the site&amp;rsquo;s HTML files on my local computer are synchronized to the hosting provider, which is operating as a static content delivery network. This also means I am not responsible for administering a virtual private server, and can let the experts handle hosting security without giving up full control of the exact HTML and Javascript that my viewers get.&lt;/p&gt;
&lt;p&gt;I hope you enjoy the collection of projects I work on, and I hope I can continue creating content that&amp;rsquo;s enjoyable to my viewers. Feel free to contact me by clicking on my email address at the bottom of any page (Javascript must be enabled for it to show up).&lt;/p&gt;
&lt;p&gt;Signed,
Andrew&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>3D Printer Mood</title>
      <link>https://www.apalrd.net/posts/2021/3d_printer_mood/</link>
      <pubDate>Wed, 08 Sep 2021 22:06:32 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/3d_printer_mood/</guid>
      <description>As all of you can appreciate, my interest in projects varies with time. At any given time, I have plenty of projects in process, and my moods change which projects I work on at any given time.
Given that information, here&amp;rsquo;s an update on what I&amp;rsquo;m working on currently:
Cheap PoE Fisheye Camera for 3D Printing - This project finished months ago, but I wrote a detailed review of the camera and published it.</description>
      <content>&lt;p&gt;As all of you can appreciate, my interest in projects varies with time. At any given time, I have plenty of projects in process, and my moods change which projects I work on at any given time.&lt;/p&gt;
&lt;p&gt;Given that information, here&amp;rsquo;s an update on what I&amp;rsquo;m working on currently:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/&#34;&gt;Cheap PoE Fisheye Camera for 3D Printing&lt;/a&gt; - This project finished months ago, but I wrote a detailed review of the camera and published it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/&#34;&gt;Simple Polycarbonate Enclosure for Prusa Printers&lt;/a&gt; - I just finished the first revision of this, and am starting trials using it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since I&amp;rsquo;m on a 3D printing kick, expect at leat one of these projects to appear in the future, depending on how long I can keep this motivation up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Ultimate OctoPi Setup - in which I upgrade my OctoPi setup to a Raspberry Pi 3, print an enclosure to bolt to my polycarbonate box, and setup autofs and all of that good stuff to integrate with my NAS.&lt;/li&gt;
&lt;li&gt;Pimping my 3D Printer Lighting - in which I add LED lights to my 3D printer so I can stop using the work light, which is only needed so the camera has a view of the print overnight&lt;/li&gt;
&lt;li&gt;Setting up The Spaghetti Detective cloud-free - in which I venture into The Spaghetti Detective to reduce my unattended 3d print messes&lt;/li&gt;
&lt;li&gt;How Much Power does my 3D Printer Use - in which I flash a Sonoff S31 power meter smart plug with Tasmota, and then attempt to measure how much power an average 3D print uses.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stick around and find out what I end up making.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>My First Post</title>
      <link>https://www.apalrd.net/posts/2021/my-first-post/</link>
      <pubDate>Wed, 08 Sep 2021 13:44:05 -0400</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/my-first-post/</guid>
      <description>This is my first post on my new blog. I&amp;rsquo;m starting this new endeavour in my life, the creation of my personal website. I hope you enjoy this content.</description>
      <content>&lt;p&gt;This is my first post on my new blog. I&amp;rsquo;m starting this new endeavour in my life, the creation of my personal website. I hope you enjoy this content.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Simple Polycarbonate Enclosure for Prusa Printers</title>
      <link>https://www.apalrd.net/projects/2021/3d_printer_box/</link>
      <pubDate>Wed, 08 Sep 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2021/3d_printer_box/</guid>
      <description>In 2018 I bought a Prusa i3 MK3s kit, and I&amp;rsquo;ve been very happy with it. However, I&amp;rsquo;ve found that it really struggles with early layer curling, even with PLA, in my cold basement. The solution to this problem is to build a box around the printer. The box will retain more of the heat generated by the printer, hopefully resulting in less warping due to cooling of the printed parts.</description>
      <content>&lt;p&gt;In 2018 I bought a Prusa i3 MK3s kit, and I&amp;rsquo;ve been very happy with it. However, I&amp;rsquo;ve found that it really struggles with early layer curling, even with PLA, in my cold basement. The solution to this problem is to build a box around the printer. The box will retain more of the heat generated by the printer, hopefully resulting in less warping due to cooling of the printed parts. This box should work with any other printer too, as long as you get a sheet of polycarbonate large enough for your printer.&lt;/p&gt;
&lt;h2 id=&#34;the-first-box&#34;&gt;The First Box&lt;/h2&gt;
&lt;p&gt;To test if the temperature / airflow was causing my print issues, I built a box out of foam floor tiles. The box worked remarkably well, instantly reducing curling of print edges and prints coming off the bed. It wasn&amp;rsquo;t exactly pretty though.
&lt;img alt=&#34;Old Box, Closed&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/oldbox_closed.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;The Old Box, Closed for printing&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Old Box, Open&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/oldbox_open.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;The Old Box, Open for viewing&lt;/div&gt;
&lt;p&gt;Obviously, this wasn&amp;rsquo;t a great long term solution. It does have a decent mount for the &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/&#34;&gt;3D Printer Camera&lt;/a&gt; though.&lt;/p&gt;
&lt;h2 id=&#34;the-second-box&#34;&gt;The Second Box&lt;/h2&gt;
&lt;p&gt;The second box is designed to use 2&amp;rsquo;x2&amp;rsquo; sheets of polycarbonate. I already had a box of 2x2 sheets of 0.060&amp;quot; polycarbonate leftover from other projects, so that&amp;rsquo;s the thickness I used. Had I purchased material for this project, I would have gone with a thicker sheet for increased stiffness.&lt;/p&gt;
&lt;p&gt;I decided to design and print corner brackets first. These are triangular with 3 sides, each with space for a #8-32 UNF fastener, and a nut pocket that&amp;rsquo;s a little oversized to avoid the need for a wrench. Since a cube has 8 corners, I need 8 brackets, and made them all with the same design instead of modeling specific variants for bottom or front corners.&lt;/p&gt;
&lt;p&gt;After the corner brackets, I designed a similar shaped bracket to hold the &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/&#34;&gt;camera&lt;/a&gt;. I used a #8-32 UNF fastener to mount the camera.&lt;/p&gt;
&lt;p&gt;The final model for the initial design is the hinge stiffener bracket. It has 3 holes to mount the hinge. I used &lt;a href=&#34;https://www.vexrobotics.com/275-1272.html&#34;&gt;VEX Robotics Hinges&lt;/a&gt; since I had easy access to them, and they use a 1/2&amp;quot; hole spacing, so the model picks up 3 of the 5 holes, plus spreads the load across a wider area to reduce local bending of the polycarbonate. The width was chosen based on the print bed limits of my Prusa i3 MK3s printer.&lt;/p&gt;
&lt;p&gt;While the printer started working, I ordered my fasteners from &lt;a href=&#34;https://mcmaster.com&#34;&gt;McMaster-Carr&lt;/a&gt; and waited impatiently for them to arrive.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;All the 3d printed parts for the original design&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/new_printparts.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;All of the 3D printed parts&lt;/div&gt;
&lt;h2 id=&#34;assembling-the-box&#34;&gt;Assembling The Box&lt;/h2&gt;
&lt;p&gt;Newly printed parts and fasteners in hand, I started to assemble the box. I quickly found that there were a few issues with the design that I would need to address:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The nut pockets in the parts were all designed 1mm oversized (flat to flat), which was a bit on the large side, but when I tested the first printed part, I found that certain edges of the hexagon would sag as they were printed unsupported overhangs, and the nuts I had on hand had no problem tightening with that large of an oversize. However, the nuts I had on hand were not nylon locknuts, and didn&amp;rsquo;t require as much torque to tighten. With the nylon locknuts, one of the three hexagons (the one printed flat without any overhang sag) would spin in the pocket when tightened. The other two were usually fine. I chose to jam a screwdriver into the nut pocket to hold the nut instead of re-printing the parts, but I did go back and fix the original models and export new AMF files for you guys, so the downloads are all corrected with an 0.5&amp;quot; oversize, which I used for the later stiffener parts.&lt;/li&gt;
&lt;li&gt;The plastic is way too thin to support the box with only corner brackets. I designed and printed a new side stiffener bracket to mount in the center of each edge, where two side panels meet, to hopefully improve the rigidity of the cube.&lt;/li&gt;
&lt;li&gt;The front corners of the box spread easily. This may or may not be a problem, I&amp;rsquo;m going to see what happens once the stiffeners are installed. I can&amp;rsquo;t print a single piece to span the gap, but I should be able to fit 3x pieces in the printer and assemble them. Alternatively, I could use rubber feet to try and keep the box in place.&lt;/li&gt;
&lt;li&gt;The center sags between the two hinges, and the left and right panels also sag in the front. I need to find a way to stiffen the center aruound the hinges at the top of the box, and interlock the door better to keep the whole box solid. Maybe magnets are the solution here. They are handy sometimes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;completed-box&#34;&gt;Completed Box&lt;/h2&gt;
&lt;p&gt;After printing more edge stiffeners and linear stiffeners, I assembled the box for the last time, and added the door. I also made 10mm feet for each corner, to lift the box up a little bit to leave room for cables. Due to the hinge design, the door ends about 10-20mm below the bottom of the box, but I didn&amp;rsquo;t trim it, intead I use this to &amp;lsquo;prop up&amp;rsquo; the box since the polycarbonate is so thin. If you copy this, definitely use a thicker plastic, I just used what I had.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Box Complete&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/newbox1.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Box Complete&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/newbox2.jpg&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project. All design files are licensed Creative Commons CC-BY-SA.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.vexrobotics.com/275-1272.html&#34;&gt;VEX Robotics Hinges&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;1/16&amp;quot; thick 2&amp;rsquo;x2&amp;rsquo; Polycarbonate Shets - You should buy 1/8&amp;quot; or thicker&lt;/li&gt;
&lt;li&gt;#8-32 UNF x 1/2&amp;quot; stainless steel bolt - Increase the length of the bolt if you go above 1/8&amp;quot; thickness&lt;/li&gt;
&lt;li&gt;#8-32 UNF stainless steel nylon lock nut&lt;/li&gt;
&lt;li&gt;#8 stainless steel washer&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/PrinterBox_AMF.zip&#34;&gt;3D Models (AMF format)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/PrinterBox_FreeCAD.zip&#34;&gt;3D Model originals (FreeCAD format)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.thingiverse.com/thing:4973505&#34;&gt;Thingiverse Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.prusaprinters.org/prints/76704-3d-printer-polycarbonate-enclosure-bracketry&#34;&gt;PrusaPrinters Page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>First (mis)Steps in Bathroom Automation</title>
      <link>https://www.apalrd.net/posts/2021/smart_bathroom/</link>
      <pubDate>Mon, 06 Sep 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/smart_bathroom/</guid>
      <description>I&amp;rsquo;d already had a start in Home Automation with my IKEA Blinds Project and Z-Wave with my Bedroom Lighting, so I was ready for something more advanced. Little did I know that automating a bathroom light and fan switch would require so much logic to avoid being stuck in the dark in the shower at night, and all the other corner cases that come up when you try to implement real automation logic instead of &amp;lsquo;smart home&amp;rsquo; party tricks.</description>
      <content>&lt;p&gt;I&amp;rsquo;d already had a start in Home Automation with my &lt;a href=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/&#34;&gt;IKEA Blinds Project&lt;/a&gt; and Z-Wave with my &lt;a href=&#34;https://www.apalrd.net/projects/2021/zwave_intro/&#34;&gt;Bedroom Lighting&lt;/a&gt;, so I was ready for something more advanced. Little did I know that automating a bathroom light and fan switch would require so much logic to avoid being stuck in the dark in the shower at night, and all the other corner cases that come up when you try to implement real automation logic instead of &amp;lsquo;smart home&amp;rsquo; party tricks. I also had to deal with an existing bathroom exhaust fan + light that didn&amp;rsquo;t have separate wiring to control the fan and light, requiring some special hardware.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Fan + Light in the bathroom&#34; src=&#34;https://www.apalrd.net/posts/2021/smart_bathroom/fanlight.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Existing Fan + Light in future Smart Bathroom&lt;/div&gt;
&lt;h2 id=&#34;the-magic-fan--light-dimmer&#34;&gt;The Magic Fan + Light Dimmer&lt;/h2&gt;
&lt;p&gt;The existing fan + light had a single power wire (line + neutral) to a single wall switch, which controlled both the fan and the light. This was not ideal, since I&amp;rsquo;d often leave the light off at night since the fan was so loud, and I can&amp;rsquo;t use a light dimmer because it would also attempt to dim the fan. I really wanted the light to dim automatically at light, and to turn the fan on and off automatically with humidity due to the shower, so I needed separate control of the fan and light, but I didn&amp;rsquo;t have the wiring in the wall to accomodate a wall switch and wall dimmer. I was luckliy able to snag a few of the &lt;a href=&#34;https://inovelli.com/red-series-fan-light-switch-z-wave/&#34;&gt;Inovelli Red Series Fan + Light Switch (LZW36)&lt;/a&gt;, which uses a single-gang space for the wall switch with both a fan and light dimmer, and a RF remote &amp;lsquo;canopy module&amp;rsquo; designed to mount on top of a ceiling fan, but controlling the power up at the fan instead of in the switch itself. I took the motor section out of the fan+light, revealing the wiring area and fan duct, wired the canopy module into the wiring area, and tucked it in next to the fan duct. It was an extremely tight fit, and there was basically no wire length for access, so I was very thankful to have Wago push connectors instead of wire nuts. I managed to fit the canopy module in there, and wrapped the black antenna wire in red electrical tape to prevent it from getting damaged when I re-installed the metal fan.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;LZW36 Switch&#34; src=&#34;https://www.apalrd.net/posts/2021/smart_bathroom/lzw36_switch.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Inovelli Red Fan + Light Switch mounted in the bathroom&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;LZW36 Canopy Module in Fan Enclosure&#34; src=&#34;https://www.apalrd.net/posts/2021/smart_bathroom/lzw36_canopy.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Canopy Module tucked very tightly inside fan housing&lt;/div&gt;
&lt;h2 id=&#34;sensor-module&#34;&gt;Sensor Module&lt;/h2&gt;
&lt;p&gt;I could have looked for separate temperature+humidity and motion sensor modules, but I wanted to try out the &lt;a href=&#34;https://inovelli.com/4-in-1-sensor-z-wave/&#34;&gt;Inovelli 4-in-1 Motion Sensor (LZW60)&lt;/a&gt;, which includes motion, light, temperature, and humidity. I think I could do better on cost in the future by going with Zigbee sensors, but the Inovelli sensor has an absolute ton of configuration ability (parameters like motion reset time, sensor reporting interval, etc.) whereas none of the Zigbee sensors I have can be configured at all.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;LZW60 multi-sensor module&#34; src=&#34;https://www.apalrd.net/posts/2021/smart_bathroom/lzw60_motion.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;4-in-1 Motion Sensor installed in the Smart Bathroom&lt;/div&gt;
&lt;h2 id=&#34;first-pass-at-logic&#34;&gt;First Pass at Logic&lt;/h2&gt;
&lt;p&gt;First, I setup an Automation in Home Assistant using the Motion Controlled Lights blueprint that&amp;rsquo;s built in. I matched up the motion sensor entity with the light entity, and set the time I wanted (4 minutes, minus the 30 seconds built in to the sensor). This functioned, and there was much rejoicing!&lt;/p&gt;
&lt;p&gt;Second, I setup an Automation in Home Assistant for the fan humidity control. I used Numeric State trigger, so when the humidity goes above 69%, it will trigger. It turns on the fan, then waits for another Numeric State trigger, for the humidity to go below 66%. I turned the shower on, waited for the fan to come on, turned the shower off, and waited for the fan to turn off automatically, and there was much rejoicing!&lt;/p&gt;
&lt;p&gt;After a day of playing with this, I quickly found a bunch of issues with this very basic automation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The motion sensing light turns off when you&amp;rsquo;re in the shower, and  you&amp;rsquo;re left in the dark. What a bummer.&lt;/li&gt;
&lt;li&gt;It takes a really, really long time for the humidity to come back down after a long shower. Ideally we could keep the fan on until it does go back down, but there&amp;rsquo;s just too much moisture in the air and the fan is too in effective at venting. I might have to tolerate a higher turn-off humidity, turn the fan on sooner, or something like that, but I need to do something so the fan doesn&amp;rsquo;t run for hours.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;d like the light to be dimmer at night, and not so darn bright when I&amp;rsquo;m barely awake trying to use the bathroom.&lt;/li&gt;
&lt;li&gt;Sometimes, people push the up/down buttons on the face of the dimmer and that messes up the level the dimmer returns to when it turns on/off.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;second-pass-at-logic&#34;&gt;Second Pass at Logic&lt;/h2&gt;
&lt;p&gt;After learning from the basic fan and light automations over a few days, I realized that they still weren&amp;rsquo;t that great and I could improve.&lt;/p&gt;
&lt;p&gt;First, I quicly setup the dimmer to always return to a set level when turned on, instead of the last value. I also added this  default brightness parameter to my sunrise/sundown automations (parameter 12 for local control and 13 for Z-wave control), seting the night value to 11% and the day value to 100%, similar to my bedroom lighting. I also set the fan to not be dimmable at all (minimum dim level 3), so it will either be on or off. Being an exhaust fan, it already doesn&amp;rsquo;t move a ton of air, and going down to lower dim levels makes it basically useless.&lt;/p&gt;
&lt;p&gt;Second, I set a timeout of 35 minutes on the fan automation, so it will turn the fan off no more than 35 minutes after it goes on. For a quick shower it should turn off in about 20 minutes, but some people take excessively long showers, and the fan just cna&amp;rsquo;t remove the moisture in any amount of time without opening the doors and ventilating the room.&lt;/p&gt;
&lt;p&gt;Third, I added logic to the fan automation to override the light. It now follows this sequence of events&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trigger when humidity rises above 69%&lt;/li&gt;
&lt;li&gt;Turn the fan on&lt;/li&gt;
&lt;li&gt;Turn off the bathroom light motion automation, without letting it continue running any subsequent events&lt;/li&gt;
&lt;li&gt;Turn on the bathroom light and set the brightness to 100% (even at night, you probably want light in the shower)&lt;/li&gt;
&lt;li&gt;Wait for the humidity to fall below 66%, or 35 minutes&lt;/li&gt;
&lt;li&gt;Turn the fan off&lt;/li&gt;
&lt;li&gt;Turn the bathroom light motion automation back on&lt;/li&gt;
&lt;li&gt;Turn the light back off&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I then lived with this automation for a few more days, and there was again much rejoicing. However, I did find one corner case where I restarted Home Assistant while the automation was in its 35 minute fan cycle, and the automation ended without finishing, leaving the motion sensing lights disabled and the fan running.&lt;/p&gt;
&lt;p&gt;As of the writing of this, I still have a few lingering issues that I might try to resolve with a more complex automation, or possibly by implementing it differently:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Even if the fan and light are turned off manually, the motion sensing lights will remain disabled until the fan would have automatically turned off. They should go back to automatic if the lights are manually turned off, but should not turn on until motion is re-detected (i.e. should not turn on because someone was in the room in the last 30s, as they obviously turned the lights off for a reason)&lt;/li&gt;
&lt;li&gt;If the fan is turned off manually, but not the lights, the lights should stay on but revert to motion control.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;manual-backup&#34;&gt;Manual Backup&lt;/h2&gt;
&lt;p&gt;After all the work on automation, I still struggled with two unrelated issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you sit on the toilet too long, sometimes, the light turns back off. I played with the motion sensitivity and timeout to reduce the chance of this, but it&amp;rsquo;s still possible. Waving your hands can get the lights back on, but the position of the motion sensor isn&amp;rsquo;t perfect.&lt;/li&gt;
&lt;li&gt;Since the fan no longer comes on automatically with the light (they used to be physically tied together), and sometimes you wished you turned it on when you&amp;rsquo;re already on the toilet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I could have done more work on the automation to fix these issues, but for issue #2 specifically, I just didn&amp;rsquo;t have a good way to automate the fan. So, I went with the easy way out - I added a pushbutton next to the toilet so you can toggle the fan and light from the toilet. I used one of the two double pushbuttons that came with my &lt;a href=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/&#34;&gt;IKEA Blinds&lt;/a&gt;, and setup an automation to toggle the light in response to the top button and toggle the fan in response to the bottom button.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;IKEA button next to toilet&#34; src=&#34;https://www.apalrd.net/posts/2021/smart_bathroom/ikea_button.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Sometimes easier user control is better than more automation&lt;/div&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://inovelli.com/red-series-fan-light-switch-z-wave/&#34;&gt;Inovelli Red Series Fan + Light Switch (LZW36)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://inovelli.com/4-in-1-sensor-z-wave/&#34;&gt;Inovelli 4-in-1 Motion Sensor (LZW60)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Tracking my Cat with Frigate NVR</title>
      <link>https://www.apalrd.net/posts/2021/frigate_intro/</link>
      <pubDate>Sun, 05 Sep 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/frigate_intro/</guid>
      <description>Previosly, I built a home security camera system using ZoneMinder. Somewhat dissatisfied with the status quo of ZoneMinder, I set out to try a brand new security NVR - Frigate - and see if an NVR written specifically to integrate into Home Assistant could be used for more than just recording and viewing camera footage.
The Old System I am using the same Dahua cameras I installed in the ZoneMinder System.</description>
      <content>&lt;p&gt;Previosly, I built a home security camera system using &lt;a href=&#34;https://www.apalrd.net/projects/2020/zoneminder_intro/&#34;&gt;ZoneMinder&lt;/a&gt;. Somewhat dissatisfied with the status quo of ZoneMinder, I set out to try a brand new security NVR - Frigate - and see if an NVR written specifically to integrate into Home Assistant could be used for more than just recording and viewing camera footage.&lt;/p&gt;
&lt;h2 id=&#34;the-old-system&#34;&gt;The Old System&lt;/h2&gt;
&lt;p&gt;I am using the same Dahua cameras I installed in the &lt;a href=&#34;https://www.apalrd.net/projects/2020/zoneminder_intro/&#34;&gt;ZoneMinder System&lt;/a&gt;. In fact, I ran both Zoneminder and Frigate for about a month while I validated functionality of the new system, using the same ZFS pool! Read that project page for information on the cameras I chose and why. There may be newer cameras available now, but I&amp;rsquo;m still satisfied with the image quality from what I already have.&lt;/p&gt;
&lt;p&gt;Since writing the article on the old system, I added a few cameras in ZoneMinder just for viewing in the app - the USB security camera connected to my 3D printer&amp;rsquo;s OctoPrint setup, and the PoE camera I got to monitor my 3D printer (&lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/&#34;&gt;Project Here&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-vm&#34;&gt;Setting Up the VM&lt;/h2&gt;
&lt;p&gt;I setup a new Ubuntu VM on my &lt;a href=&#34;https://www.apalrd.net/projects/2021/minilab/&#34;&gt;Minilab&lt;/a&gt; to run Frigate. Without an AI accelerator, and only giving it 4 vcpu cores so it doesn&amp;rsquo;t starve Home Assistant, I was able to comfortably run ai inferencing on two cameras and not really on 3. My goal was to run ai on the close-up door cameras at a high enough resolution to detect the cat, which means I can&amp;rsquo;t run at the low-res D1 (704x480) sub stream on my 1440p cameras and either have to drop the 1440p main stream down and reduce the main stream resolution to the resolution I can do AI at, or do AI at full 1440p main stream. Hence the massive CPU penalty. I was okay running the D1 stream for the far shot cameras where I was more focused on car and person detect, and both cars and people are significantly larger than cats. With this in mind, I ordered two &lt;a href=&#34;https://www.coral.ai/&#34;&gt;Coral AI&lt;/a&gt; accelerators to fit in the two M.2 slots of Minilab.&lt;/p&gt;
&lt;p&gt;As you can read in the Minilab project, I really struggled with PCIe passthrough on Xen, and even a bit once I moved to Proxmox, but it ended up working out, and I found myself with a brand new Ubuntu VM with two working Coral AI accelerators for use. I still gave it 4 vcpu cores and 4G of RAM, which is hopefully enough for the full camera system. I setup Docker according to the Docker install guide for Ubuntu, and was off to the races.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-frigate&#34;&gt;Setting up Frigate&lt;/h2&gt;
&lt;p&gt;At this point, I have the 5 Dahua cameras I setup for the &lt;a href=&#34;https://www.apalrd.net/projects/2020/zoneminder_intro/&#34;&gt;ZoneMinder System&lt;/a&gt;, the OctoPrint raspberry pi and it&amp;rsquo;s USB webcam, and the &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/&#34;&gt;wide angle PoE camera&lt;/a&gt; watching the 3D printer. I setup my Ubuntu VM to load the Frigate directory off a dedicated zfs dataset from the file server, and that includes storage of recordings, clips, and the config.yml file. I relocated the database file off the remote zfs dataset onto the VM&amp;rsquo;s 30GB OS drive due to file locking issues with Samba shares. I wrote up a config file I was happy with, assuming the Coral AI was all powerful (and I had &lt;strong&gt;two&lt;/strong&gt; of them), using the 5 Dahua cameras and the wide angle PoE camera. I quickly learned a lot:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Frigate does not let you create a camera without a detect behavior, at all. It really wants to try object detection, and I don&amp;rsquo;t want to do that for my 3D printer cameras.&lt;/li&gt;
&lt;li&gt;I expected a bit too much from the little Coral AI chip, even with two of them. Trying to run 4 cameras at 1440p, 15fps analysis and one at 1080p (the 4K camera which supports higher resolution sub-streams), it was not happy.&lt;/li&gt;
&lt;li&gt;ffmpeg decoding of so many high resolution streams at high framerate is quite CPU intensive without the ability to offload it to a GPU, and I don&amp;rsquo;t feel comfortable giving up my only way to access the Proxmox console physically to pass-through the iGPU.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After struggling for a bit, having learned a lot, I decided on a much more reasonable configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The two door cameras will run analysis at 5fps on the 1440p main stream. Only the main stream is used for these cameras. They have person and cat detection enabled.&lt;/li&gt;
&lt;li&gt;The two wide field 1440p cameras will run analysis at 5fps on the D1 sub stream, using the D1 stream only for detection and the main stream for everything else. These cameras have car and person detection enabled&lt;/li&gt;
&lt;li&gt;The 4K varifocal camera will run analysis at 5fps on a 720p sub stream, using the 4K stream for recording and clips and the 720p stream for real-time viewing and detection. This camera has car, person, and cat detection enabled, although I don&amp;rsquo;t think the resolution is high enough to pick out cats, I want to give it a try.&lt;/li&gt;
&lt;li&gt;The 3D printer cameras were added to Home Assistant directly, and skip Frigate entirely. HA manages the (re)streaming of these cameras to the HA app and web UI.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;cat-detection&#34;&gt;Cat Detection&lt;/h2&gt;
&lt;p&gt;As promised, I really wanted to track my cat. Frigate delivered. Here are some gems for you guys to enjoy:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;Front Door&lt;/th&gt;
&lt;th style=&#34;text-align:center&#34;&gt;Back Door&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;img alt=&#34;Cat&#34; src=&#34;https://www.apalrd.net/posts/2021/frigate_intro/catcam1.jpg&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;img alt=&#34;Cat&#34; src=&#34;https://www.apalrd.net/posts/2021/frigate_intro/catcam2.jpg&#34;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Staring into your soul&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Off on an adventure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;img alt=&#34;Cat&#34; src=&#34;https://www.apalrd.net/posts/2021/frigate_intro/catcam4.jpg&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;img alt=&#34;Cat&#34; src=&#34;https://www.apalrd.net/posts/2021/frigate_intro/catcam3.jpg&#34;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;A skilled jumper&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Supervising the humans&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;img alt=&#34;Cat&#34; src=&#34;https://www.apalrd.net/posts/2021/frigate_intro/exploring.jpg&#34;&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;img alt=&#34;Cat&#34; src=&#34;https://www.apalrd.net/posts/2021/frigate_intro/relaxation.jpg&#34;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Leaving for fun&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Relaxing in the shade&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;lovelace-view&#34;&gt;Lovelace View&lt;/h2&gt;
&lt;p&gt;I added a tab to my HA Lovelace security page specifically for watching the cat
&lt;img alt=&#34;Lovelace CatCam page&#34; src=&#34;https://www.apalrd.net/posts/2021/frigate_intro/ha_lovelace.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Cat Cam tab&lt;/div&gt;
&lt;h2 id=&#34;final-thoughts&#34;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Frigate is an excellent NVR and has earned its place in my network. Once I am satisfied with the recording and clip searching, I will deprecate ZoneMinder and switch to using Frigate exclusively for security cameras. I&amp;rsquo;m already impressed with how reliably Frigate rejects things like bugs, spiders, and swaying tree shadows, and feel like I can trust the filtered events more than ZoneMinder. I already have plans to automate exterior lighting based on person detection, so we don&amp;rsquo;t have to &amp;rsquo;leave the light on&amp;rsquo; for people coming home late, and Frigate should reduce false positives in this regard. More to come on this subject for sure.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Getting Started with Automated Lighting with Z-Wave</title>
      <link>https://www.apalrd.net/posts/2021/zwave_intro/</link>
      <pubDate>Thu, 02 Sep 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/zwave_intro/</guid>
      <description>After playing with my Zigbee-controlled IKEA FYRTUR Blinds, I wanted to experiemnt with automated lighting. Despite already having a functional Zigbee network, I wanted to choose high quality, reliable lighting components. After spending a ton of time researching on the internet, I decided to start a new Z-Wave network, using Inovelli dimmer switches. This project is my first attempt to get the network functioning.
The Choice of a Network After my (somewhat poor) experience with Zigbee, I wasn&amp;rsquo;t eager to use Zigbee hardware again for something critical like lighting.</description>
      <content>&lt;p&gt;After playing with my Zigbee-controlled &lt;a href=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/&#34;&gt;IKEA FYRTUR Blinds&lt;/a&gt;, I wanted to experiemnt with automated lighting. Despite already having a functional Zigbee network, I wanted to choose high quality, reliable lighting components. After spending a ton of time researching on the internet, I decided to start a new Z-Wave network, using Inovelli dimmer switches. This project is my first attempt to get the network functioning.&lt;/p&gt;
&lt;h2 id=&#34;the-choice-of-a-network&#34;&gt;The Choice of a Network&lt;/h2&gt;
&lt;p&gt;After my (somewhat poor) experience with Zigbee, I wasn&amp;rsquo;t eager to use Zigbee hardware again for something critical like lighting. I know hardwired devices behave better overall than battery powered ones as they don&amp;rsquo;t have to be woken up to change settings, but I&amp;rsquo;d been spending some research time comparing Zigbee with Z-Wave and Lutron Caseta, and I decided to try setting up a Z-Wave network for this project. Lutron Caseta has a fantastic reputation, but it&amp;rsquo;s pretty expensive for what you get compared to the newest generation of Z-Wave products, and has a 75 device limit. I don&amp;rsquo;t need 75 devices currently, but at this point in my life I&amp;rsquo;m already planning on my first new house build and I could easily run up on that 75 device limit in that application, so I&amp;rsquo;d like to experiment with technologies I&amp;rsquo;d actually put in my house build.&lt;/p&gt;
&lt;p&gt;I started with my bedroom combined fan and light. I am planning on adding additional lighting in the future, but that is another project. For now, I selected the &lt;a href=&#34;https://inovelli.com/red-series-fan-light-switch-z-wave/&#34;&gt;Inovelli Red Series Fan + Light Switch (LZW36)&lt;/a&gt;. As of this writing it&amp;rsquo;s out of stock, but I was able to snag two by closely following the forums. It uses Z-Wave Plus, sports a double button plus double up/down toggle control, and two of the RGB indicator bargraphs that Inovelli is famous for. The Fan + Light switch has a remote module which actually controls the fan and light, and mounts like an RF fan remote module would.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-network&#34;&gt;Setting Up the Network&lt;/h2&gt;
&lt;p&gt;For the Z-Wave controller, I got an &lt;a href=&#34;https://aeotec.com/z-wave-usb-stick/&#34;&gt;Aeotec Z-Stick Gen5+&lt;/a&gt; because the Gen7 was out of stock. My existing raspberry pi in the laundry room (located in the center of all of the bedrooms) which is running Zigbee2MQTT is an old Raspberry Pi 2, which is too old to run the latest versions of Node.JS required for ZWaveJS. So, time to track down a newer Raspberry Pi. I&amp;rsquo;ve been involved with Raspberry Pi&amp;rsquo;s for a long time and I&amp;rsquo;ve gotten most of my older ones embedded into projects by this point, but I bought 10+ of them in the ARMv6L days, so most of them are still older. Given the current Raspberry Pi shortages and the lack of software to run on ARMv6L, I&amp;rsquo;ll probably have to start slowly buying Model 3 and 4&amp;rsquo;s as I can. I was able to find a Raspberry Pi 3 not involved in a project, and set it up as my Z-Wave master using &lt;a href=&#34;https://zwave-js.github.io/zwavejs2mqtt/#/&#34;&gt;ZWaveJS2MQTT&lt;/a&gt;. I chose to use ZWaveJS2MQTT to use it&amp;rsquo;s good web UI, and ran it remotely from Home Assistant to keep it running when I restart the HA server and locate it in a better place for coverage than the depths of the basement lab.&lt;/p&gt;
&lt;h2 id=&#34;automating-my-lights&#34;&gt;Automating my Lights&lt;/h2&gt;
&lt;p&gt;After setting up the Z-Wave controller, adding the ZWaveJS integration to Home Assistant and pointing it to my ZWaveJS2MQTT installation on the Raspberry Pi, I paired the LZW36 in my bedroom to the network. I was instantly impressed by the breath of configurationability of the LZW36, compared to my Zigbee network where all of my devices have essentially no configuration ability. I played with the dimming ramp rates, default levels, and even set the LEDs to different colors for fun. Super easy with ZWaveJS2MQTT.&lt;/p&gt;
&lt;p&gt;I already bought an &lt;a href=&#34;https://www.ikea.com/us/en/p/tradfri-wireless-motion-sensor-white-60377655/&#34;&gt;IKEA TRÅDFRI Motion Sensor&lt;/a&gt; when I bought my blinds, since it was really cheap and didn&amp;rsquo;t cost extra to ship, and I decided to try that in my bedroom instead of buying a new Z-Wave motion sensor. This means I won&amp;rsquo;t get all of the features of something like the Inovelli LZW60, but it&amp;rsquo;s functional and 1/3 the price. There are no settings to adjust on the motion sensor, it returns a boolean sensor in Home Assistant with a 90 second turn off delay. I configured the lights with the Home Assistant built-in &amp;lsquo;motion controlled lighting&amp;rsquo; blueprint, matching the motion sensor with the light device. It works pretty well, and I&amp;rsquo;m generally happy with it.&lt;/p&gt;
&lt;p&gt;After living with it for a few days, I found that the automation is perfect during the day, but can be irritating at night. The motion sensor also doesn&amp;rsquo;t have a great view of my bed, so sometimes it turns itself off if I&amp;rsquo;m using my laptop in bed. My solution to this is to expand the sunset automation I started in my &lt;a href=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/&#34;&gt;Smart Blinds Project&lt;/a&gt;, making a pair of automations for sunrise and sunset tasks. I change the default brightness of the switch (parameter 12 for local and 13 for Z-wave &amp;lsquo;on&amp;rsquo; command) to 66% after sundown and back to 100% after sunrise, and disable the motion sensing automation between sunset and sunrise so the lights don&amp;rsquo;t accidentaly turn on at night. I&amp;rsquo;ll have to suffer with only manual or app control in those situations, which is still better than what I had before this, so I&amp;rsquo;m pretty happy overall.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t experimented with Inovelli&amp;rsquo;s RGB indicator for notifications yet other than manually changing the color for fun, but that&amp;rsquo;s certainly a project for the future. I already love the look and function of my automated light switch, and I&amp;rsquo;ve ordered a 10-pack of switches and a few dimmers to automate a whole bunch of other stuff in my house.&lt;/p&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://aeotec.com/z-wave-usb-stick/&#34;&gt;Aeotec Z-Stick Gen5+&lt;/a&gt; - NOTE - They have a Gen7 but it was out of stock so I got the Gen5+&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://zwave-js.github.io/zwavejs2mqtt/#/&#34;&gt;ZWaveJS2MQTT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://inovelli.com/red-series-fan-light-switch-z-wave/&#34;&gt;Inovelli Red Series Fan + Light Switch (LZW36)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ikea.com/us/en/p/tradfri-wireless-motion-sensor-white-60377655/&#34;&gt;IKEA TRÅDFRI Motion Sensor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>How I Solved My Afternoon Sun Glare with IKEA and Zigbee</title>
      <link>https://www.apalrd.net/projects/2021/ikea_blinds/</link>
      <pubDate>Sat, 24 Jul 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2021/ikea_blinds/</guid>
      <description>My bedroom faces to the West. As with most McMansions in the United States, the architect had absolutely no consideration for the angles of the sun in each room throughout the day. In fact, the architect wasn&amp;rsquo;t even involved in building this house, the plans were purchased as a set. As a result, I get blasted in the mid afternoon summer sun, greatly raising the temperature in my room and causing far too much screen glare for my taste.</description>
      <content>&lt;p&gt;My bedroom faces to the West. As with most McMansions in the United States, the architect had absolutely no consideration for the angles of the sun in each room throughout the day. In fact, the architect wasn&amp;rsquo;t even involved in building this house, the plans were purchased as a set. As a result, I get blasted in the mid afternoon summer sun, greatly raising the temperature in my room and causing far too much screen glare for my taste. My solution to this is to cover my windows with motorized roller blinds.&lt;/p&gt;
&lt;h2 id=&#34;ikea-to-the-rescue&#34;&gt;IKEA To The Rescue&lt;/h2&gt;
&lt;p&gt;As with all things in interior decorating and the finest Swedish meatballs, my very first place to look is IKEA. IKEA has actually come out with some low-cost home automation products based on Zigbee, their TRÅDFRI line, which indludes a Zigbee gateway, app, low cost Zigbee smart buttons, motion sensors, light bulbs, etc&amp;hellip; and of course their FYRTUR motorized roller blinds!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Blinds Installed animation&#34; src=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/blinds.gif&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Blinds as they move&lt;/div&gt;
&lt;p&gt;Without much information at all on these, but knowing they came in a complete kit (including a repeater/controller and pre-paired button), and they look pretty decent as far as blinds go, I bought a pair of them for my two windows. They only came in 2&amp;quot; width increments, and all come with a ton of height (which you can adjust to the exact window height during setup). After mounting it in my windows, they come pretty close to completely covering the glass, but it&amp;rsquo;s good enough.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Mounting clip&#34; src=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/mounting_clip.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Clips that attach the blinds to the window frame&lt;/div&gt;
&lt;p&gt;The FYRTUR motorized roller blinds come with a right angle USB power supply, a Zigbee controller/repeater with a USB power passthrough, a battery pack with micro-USB input, a micro USB cord to connect to the passthrough on the repeater and charge the battery pack, and a two button battery powered Zigbee remote.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Included Zigbee controller and power supply&#34; src=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/repeater.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Included Zigbee controller/repeater with USB passthrough and power supply&lt;/div&gt;
&lt;h2 id=&#34;living-with-manual-control&#34;&gt;Living with Manual Control&lt;/h2&gt;
&lt;p&gt;Since the blinds come pre-paired, I just needed to power the included Zigbee controller and the included button would work with the blinds. Since the controller has a USB in and out, I could stack them all up on the same USB power supply. It&amp;rsquo;s possible to pair multiple blinds with a single controller and button without their hub, but I left them as-is and had a separate button for my left and right blind. This is honestly a pretty adequate way to use these roller blinds, with the buttons on my nightstand next to my bed.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Included button and base&#34; src=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/button.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Included button (integrated magnet), plus included metal button base&lt;/div&gt;
&lt;h2 id=&#34;how-long-does-the-battery-last&#34;&gt;How Long does the Battery Last?&lt;/h2&gt;
&lt;p&gt;The battery is an 18 Ah Li-Ion pack with integrated charger with a micro-USB port for charging. The battery is charged by removing it from the blinds and plugging it in to any micro USB charger. I&amp;rsquo;ve been using these for about 6 months and the batteries haven&amp;rsquo;t died yet. I will update this page when I get better battery voltage tracking.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Battery door&#34; src=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/battery_door.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Battery Door with battery installed&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Battery&#34; src=&#34;https://www.apalrd.net/projects/2021/ikea_blinds/battery.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Battery&lt;/div&gt;
&lt;h2 id=&#34;starting-my-first-zigbee-network&#34;&gt;Starting my first Zigbee network&lt;/h2&gt;
&lt;p&gt;To better automate these blinds based on weather and time of day, I sought to integrate them with the Home Assistant system I&amp;rsquo;ve been playing with for a bit. I decided to run a &lt;a href=&#34;https://www.zigbee2mqtt.io/&#34;&gt;Zigbee2MQTT&lt;/a&gt; system, and bought a Texas Instruments CC2531 based Zigbee controller pre-flashed to work with Zigbee2MQTT. &lt;a href=&#34;https://www.zigbee2mqtt.io/information/supported_adapters.html&#34;&gt;Read more on the Z2M page about supported adapters&lt;/a&gt;. When I selected the CC2531, it was noted as having a poor antenna and not recommended for large networks, but there weren&amp;rsquo;t many options listed on the Z2M site. Over the past year, Z2M have added a lot more options for Zigbee USB sticks, and I&amp;rsquo;d recommend you read their updated page before selecting one. I&amp;rsquo;ve certainly noticed that the CC2531 has terrible link quality.&lt;/p&gt;
&lt;p&gt;Despite the poor link quality, I paired both of the included IKEA controllers as repeaters to my Z2M network, placing one on the first floor and one in the laundry room (the same room where the Z2M raspberry pi is located, but on the other side of the room). By pairing as many devices as possible through these two repeaters, I&amp;rsquo;ve gotten much better signal strength than pairing directly to the controller.&lt;/p&gt;
&lt;p&gt;I paired all of the IKEA hardware (both buttons, both blinds, both repeaters) individually, and removed all associations in the Zigbee network. I also connected Z2M to my MQTT broker. This paved the way for Home Assistant to manage the show.&lt;/p&gt;
&lt;h2 id=&#34;roller-blind-automation-with-home-assistant&#34;&gt;Roller Blind Automation with Home Assistant&lt;/h2&gt;
&lt;p&gt;I setup Home Assistant on my &lt;a href=&#34;https://www.apalrd.net/projects/2021/minilab/&#34;&gt;Minilab&lt;/a&gt;, connecting it to my MQTT broker on &lt;a href=&#34;https://www.apalrd.net/projects/2020/first_automation/&#34;&gt;Telstar&lt;/a&gt;. Enabling MQTT Discovery in Z2M was very easy, and the devices showed up quickly in Home Assistant. I renamed them all to make sense, and set the location so I can use Area based automations.&lt;/p&gt;
&lt;p&gt;My first two automations run when the up and down button are pressed on one of the Zigbee remotes. This directly commands the blinds to open and close. This restores the functionality that I had previously, but using only one remote for both blinds.&lt;/p&gt;
&lt;p&gt;My first real automation opens the blinds automatically at sunset. This ensures that I can wake up naturally with the sun, as previously I would accidentally leave the blinds closed at night and not wake up with the sun as I prefer. After that, I started experimenting with automation rules that close the blinds in the afternoon depending on the weather. As I improve the sensor suite the automation system has access to, I hope to base the blind automation based on UV Index instead of just &amp;lsquo;sunny&amp;rsquo; or &amp;lsquo;partly cloudy&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;I always hate how most people consider &amp;lsquo;smart&amp;rsquo; devices as having app control, but no real automation ability. I didn&amp;rsquo;t even consider the Home Assistant app until many weeks of tweaking the automation rules so the system works for me. I already had a wireless remote I could have used, so why should I use an app instead? My goal is to open the app as infrequently as possible, and take the time upfront to integrate everything properly so it just works as I expect. This project was pretty simple in that regard, but I&amp;rsquo;m sure I&amp;rsquo;ll expand my usage of Home Assistant in the future with much more complex automations.&lt;/p&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ikea.com/us/en/p/fyrtur-blackout-roller-blind-wireless-battery-operated-gray-50417464/&#34;&gt;IKEA FYRTUR Zigbee Roller Blinds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.zigbee2mqtt.io/information/supported_adapters.html&#34;&gt;Zigbee2MQTT Supported Adapter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Raspberry Pi (I used a Raspberrry Pi 2 Model B since it was already in the laundry room, but you really should use an ARMv8 64-bit version 3/3+/4).&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Cheap PoE Fisheye Camera for 3D Printing</title>
      <link>https://www.apalrd.net/projects/2021/3d_printer_camera/</link>
      <pubDate>Mon, 10 May 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2021/3d_printer_camera/</guid>
      <description>The quest for the best camera/angle for my 3D Printer My original plan was to use Octoprint with a USB camera (since that&amp;rsquo;s the cool thing to do, right?). I got a Logitech C270 USB webcam and was very underwhelmed by the image quality. I found that the field of view was just too narrow to get a good shot of the entire 3d print, especially if I was printing something big.</description>
      <content>&lt;h2 id=&#34;the-quest-for-the-best-cameraangle-for-my-3d-printer&#34;&gt;The quest for the best camera/angle for my 3D Printer&lt;/h2&gt;
&lt;p&gt;My original plan was to use Octoprint with a USB camera (since that&amp;rsquo;s the cool thing to do, right?). I got a Logitech C270 USB webcam and was very underwhelmed by the image quality. I found that the field of view was just too narrow to get a good shot of the entire 3d print, especially if I was printing something big. I ended up mounting it to the back of a chair and moving it around.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Old Camera, zip tied to chair&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/old_camera.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;I connected it to my OctoPi (OctoPrint on a Raspberry Pi), and streamed it, and it functioned. I could watch it remotely. At this point, I was not using OctoPrint for the printer, since I was having printing troubles and was trying to minimize the number of variables. I would later find that the &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/&#34;&gt;3D Printer Box&lt;/a&gt; solved the printing issues, and am planning on building a new, evolved OctoPi setup in the future.&lt;/p&gt;
&lt;h2 id=&#34;the-new-camera&#34;&gt;The New Camera&lt;/h2&gt;
&lt;p&gt;I set the following goals for my next camera:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Camera must have 120° or wider field of view for close mounting&lt;/li&gt;
&lt;li&gt;Camera must be as small as posible to fit in the 3d printer enclosure&lt;/li&gt;
&lt;li&gt;Camera must be 1080p (or higher)&lt;/li&gt;
&lt;li&gt;Camera must be Ethernet based and support h.264 natively - I don&amp;rsquo;t want to rely on my Raspberry Pi for streaming, and Octoprint plugins always take a stream or image URL instead of a local camera anyway&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From this set of requirements, since I prefer not to purchase from Amazon, I went to &lt;a href=&#34;https://aliexpress.com&#34;&gt;Aliexpress&lt;/a&gt; to search for a low cost camera. I ended up buying this (affiliate link):&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://s.click.aliexpress.com/e/_9G5UVT&#34;&gt;JIENUO 5MP Mini Panoramic Camera POE&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I obviously chose the PoE version, to reduce cable clutter around the printer, since I already use PoE extensively for IoT devices and cameras.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;New camera, front view&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/new_front.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;The New Camera&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;New camera, side view&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/new_side.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Another View&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;New camera, PoE power supply inline&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/new_conn.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;PoE power electronics in-line in the cable&lt;/div&gt;
&lt;h2 id=&#34;testing-the-new-camera&#34;&gt;Testing the new camera&lt;/h2&gt;
&lt;p&gt;I mounted the new camera on the foam tile printer box (see the &lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_box/&#34;&gt;3D Printer Box&lt;/a&gt; backstory). I connected it to the network, configured it with the web UI, but couldn&amp;rsquo;t figure out what the stream and image URLs were from the minimal documentation. Thankfully, it is truly ONVIF compliant, so I used &lt;a href=&#34;https://sourceforge.net/projects/onvifdm/&#34;&gt;ONVIF Device Manager&lt;/a&gt; to figure out the stream URL.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;tl;dr, here are the stream URLs you need:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For the main stream:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  rtsp://user:password@&amp;lt;ip_address&amp;gt;:554/11
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For the sub stream:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  rtsp://user:password@&amp;lt;ip_address&amp;gt;:554/12
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For the still image:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  http://&amp;lt;ip_address&amp;gt;/tmpfs/auto.jpg
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Web UI uses HTML frames, but this is what one of the configuration frames looks like. Very basic HTML, but functional.
&lt;img alt=&#34;What the web interface looks like&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/sc_videoset.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;A view of the web interface&lt;/div&gt;
&lt;p&gt;The main stream supports up to 2560x1920 and the sub stream supports up to 800x600. Both support up to 30fps, and either h.264 or h.265 (although both streams must use the same codec!). I chose h.264 over h.265 since most web browsers (except Safari) do not currently support h.264 natively, and compatibility without transcoding was important to me.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/auto_original.jpg&#34;&gt;&lt;img alt=&#34;What the image from the camera looks like&#34; src=&#34;https://www.apalrd.net/projects/2021/3d_printer_camera/auto.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;A snapshot from the camera (click for an unmodified image)&lt;/div&gt;
&lt;h2 id=&#34;home-assistant-config&#34;&gt;Home Assistant Config&lt;/h2&gt;
&lt;p&gt;If you want to use this camera with Home Assistant, here&amp;rsquo;s a sample YAML section (goes under &amp;lsquo;camera&amp;rsquo; section, or camera: !include camera.yaml)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Fisheye 3D Printer Camera&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;generic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Printer Camera&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;still_image_url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;http://10.0.0.1/tmpfs/auto.jpg?&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;stream_source&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;rtsp://admin:admin@10.0.0.1:554/11&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#/12 is the low res stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;username&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Accurate Water Measurement with ESP32</title>
      <link>https://www.apalrd.net/posts/2021/water_meter/</link>
      <pubDate>Tue, 04 May 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/water_meter/</guid>
      <description>I am currently living in my parents house, which is fed water by a private well, and we have no way of knowing exactly how much water we use. Since I&amp;rsquo;m planning on building my own house, I wanted to know how much water I (and everyone else in the house) realistically used. In addition, I wanted to know how much hot water we use and how frequently we use hot water, so I could model hot water heating systems.</description>
      <content>&lt;p&gt;I am currently living in my parents house, which is fed water by a private well, and we have no way of knowing exactly how much water we use. Since I&amp;rsquo;m planning on building my own house, I wanted to know how much water I (and everyone else in the house) realistically used. In addition, I wanted to know how much hot water we use and how frequently we use hot water, so I could model hot water heating systems.&lt;/p&gt;
&lt;h2 id=&#34;the-existing-plumbing-setup&#34;&gt;The Existing Plumbing Setup&lt;/h2&gt;
&lt;p&gt;As I mentioned, we have a private well. The well has a submersible pump near the bottom of the well, with a wire and pipe which runs into the house, where the pressure switch and fusible disconnect are located. After the pressure switch and pressure tank T off, there is a PVC manifold which directs the water to 3 places - the automated irrigation system, the hose bibs around the house, and the water softener. For those of you with city water, a water softener is a type of ion exchange filter which uses salt (sodium chloride) to replace iron and other metals in the water with sodium. Iron is not hazardous, but it does stain everything, so reducing it is desirable, but the water still isn&amp;rsquo;t perfect. Anyway, going out of the water softener the manifold splits again into two 3/4&amp;quot; PEX lines, one of which goes directly to the cold water inlet of the water heater and the other of which feeds all of the cold water outlets within the house.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;tl;dr I have four separate pipes coming out of the well manifold and by measuring two of them I can get hot and cold water usage directly&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-design&#34;&gt;The Design&lt;/h2&gt;
&lt;p&gt;Given my desire to measure the potable water usage in the house and also to measure specifically hot water flow, I decided to buy two NSF certified, revenue grade 3/4&amp;quot; cold water meters and install one on each of the cold water lines leaving the water softener. This means one meter measures hot water, but before it&amp;rsquo;s heated, so I can use a cheaper meter that isn&amp;rsquo;t rated for hot water. I ended up buying these meters: &lt;a href=&#34;https://www.flows.com/economy-plastic-water-meter-wm-pc-series/&#34;&gt;Assured Automation Economy Plastic Water Meter - WM-PC Series&lt;/a&gt;. I selected the 3/4&amp;quot; model, measuring gallons, with 10 pulses per gallon output. Since it has 10 pulses per output, I can measure both rising and falling edges resulting in 20 counts per gallon, but the pulse width is not close to 50% so there is a bit of noise in the signal.&lt;/p&gt;
&lt;h2 id=&#34;the-electronics&#34;&gt;The Electronics&lt;/h2&gt;
&lt;p&gt;Since I want this to integrate with my home automation system, the data from this water meter needs to end up on Ethernet, and pushed to an MQTT server. In 2021, the microcontroller of choice for WiFi or Ethernet is the Espressif ESP32. I specifically chose the &lt;a href=&#34;https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware&#34;&gt;Olimex ESP32-PoE&lt;/a&gt; board, which features wired Ethernet with Power over Ethernet, although the power supply on the board is not capable of handling anywhere near the 12.5W the PoE spec should allow. For this particular design, the low power is not important, we are just powering the ESP32 itself and the two dry contact switches with pull up resistors. It also helped that I&amp;rsquo;ve used them before in more than a few projects.&lt;/p&gt;
&lt;p&gt;The circuit is very simple - I used RCA connectors to connect each meter, wired both grounds to the ESP32 ground, and wired each signal to a digital pin on the ESP32, with a 4.7K pull up resistor to 3.3V. All of this was done using solid electronics wire and heat shrink without a PCB.&lt;/p&gt;
&lt;h2 id=&#34;the-enclosure&#34;&gt;The Enclosure&lt;/h2&gt;
&lt;p&gt;Astute observers will notice the similarities between this enclosure and the &lt;a href=&#34;https://www.apalrd.net/projects/2021/salt_meter/&#34;&gt;Salt Level Sensor&lt;/a&gt;. I built both of these projects around the same time, and chose to use the same hexagonal case design as that sensor for this project (you&amp;rsquo;ll also notice later that I copied and pasted the code, too). While there&amp;rsquo;s no reason for the case to be hexagonal, it is, and I printed it in a nice blue. Here&amp;rsquo;s a 3D model of the case design, showing the ESP32-PoE with Ethernet jack visible, the lower case with holes to mount both RCA jacks, and the upper case, which is an identical part to the Salt Level Sesor.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Transparent model of housing showing electronics mounting&#34; src=&#34;https://www.apalrd.net/posts/2021/water_meter/housing1.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Transparent housing showing electronics mounting&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Interior view of main housing showing PCB mount&#34; src=&#34;https://www.apalrd.net/posts/2021/water_meter/housing2.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Interior view of main housing showing PCB mount (will be hot glued)&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Ethernet end view of housing&#34; src=&#34;https://www.apalrd.net/posts/2021/water_meter/housing3.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Ethernet-end view of housing, cap transparent&lt;/div&gt;
&lt;h2 id=&#34;the-software&#34;&gt;The Software&lt;/h2&gt;
&lt;p&gt;As mentioned earlier, the software for this project was largely copied from the &lt;a href=&#34;https://www.apalrd.net/projects/2021/salt_meter/&#34;&gt;Salt Level Sensor&lt;/a&gt;. It&amp;rsquo;s built in Visual Studio Code using &lt;a href=&#34;https://platformio.org&#34;&gt;PlatformIO&lt;/a&gt;, using the ESP-IDF backend for ESP32 (instead of Arduino). All of the parameters are essentially hardcoded, and I compile/flash the board when I make changes. It isn&amp;rsquo;t as elegant as a nice web UI to set configuration parameters, but it works for me. Maybe in the future I&amp;rsquo;ll spend time developing a clean submodule for ESP-IDF projects to configure the Ethernet/MQTT backend components. Until then, you can feel free to &lt;a href=&#34;https://github.com/apalrd/PalHA_WaterMeter&#34;&gt;browse the code on github.&lt;/a&gt;. After developing both this and the Salt Level Sensor, I realized that I didn&amp;rsquo;t ever set the hostname to match the MQTT client identifier - so both of these sensors show up as &amp;rsquo;espressif&amp;rsquo; on the network and fight over the DNS name assigned to DHCP clients. Not a big deal, but it&amp;rsquo;s a bug I would fix if I revisit this.&lt;/p&gt;
&lt;p&gt;The software reads the two pulse counter pins in a 10ms timed tasks. Once the pin states are read, they are logged in a bit array, such that each bit in an integer contains a previous value of the pin, and by bit shifting the integer the previous values are copied one entry further back in the array. This method stores the last 32 pin states (320ms), but only the last 6 are used. If all of the last 6 pin states are the same (all 1 or all 0), then the pin state is determined, otherwise, the pin state is not changed from the last known state. If the pin state is determined and is different from the last known state, the counter is incremented. This provides sufficient debouncing for the water meter at maximum flow rate and provides some resilience to electrical noise (combined with the 4.7K pull up resistor). In a separate task, the data is periodically published to MQTT. At a minimum, it will publish a payload containing the two counters every 30 seconds, but it will publish instantly if either counter changes, with a maximum publishing frequency of every 1 seconds. The payload is JSON encoded, with each field named SenseX and each value being a number&lt;/p&gt;
&lt;p&gt;The MQTT data is picked up by &lt;a href=&#34;https://www.apalrd.net/projects/2020/first_automation/&#34;&gt;Node-Red (Telstar)&lt;/a&gt; and converted into gallons (using a scaling factor of 20 pulses per gallon), and re-published as cumulative gallon data to be logged in InfluxDB. In Grafana, I take the non-negative-difference followed by the sum to get the daily water consumption. Here are some helpful equations for dealing with the cumulative water consumption numbers when the numbers reset to zero whenever the sensor node reboots:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Graph the consumption of water over the time window in Grafana&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  SELECT cumulative_sum(non_negative_difference(mean(&amp;quot;Cold&amp;quot;))) FROM &amp;quot;mqtt_consumer&amp;quot; WHERE (&amp;quot;topic&amp;quot; = &#39;energy/water/meters&#39;) AND $timeFilter GROUP BY time($__interval) fill(null)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Return an array of differences, which can be summed by the Gauge visualization in Grafana&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  SELECT non_negative_difference(max(&amp;quot;Cold&amp;quot;)) FROM &amp;quot;mqtt_consumer&amp;quot; WHERE (&amp;quot;topic&amp;quot; = &#39;energy/water/meters&#39;) AND $timeFilter GROUP BY time($__interval) fill(null)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Return the derivative (flow rate)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  SELECT non_negative_derivative(max(&amp;quot;Cold&amp;quot;),1m) FROM &amp;quot;mqtt_consumer&amp;quot; WHERE (&amp;quot;topic&amp;quot; = &#39;energy/water/meters&#39;) AND $timeFilter GROUP BY time($__interval) fill(null)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;putting-it-all-together&#34;&gt;Putting It All Together&lt;/h2&gt;
&lt;p&gt;Parts in hand, this was a fairly simple project to install. I used 3/4&amp;quot; Sharkbite to 3/4&amp;quot; FNPT fittings along with plenty of Teflon tape to attach the water meter fittings to the existing PEX lines, one feeding the house and the other feeding the water heater. Water had to be shut off a few times during the install, but it was a fairly painless process overall. I&amp;rsquo;m not a fan of using either Sharkbite or NPT fittings, especially because NPT fittings rely on interference of the threads to seal, which isn&amp;rsquo;t a well engineered solution, but it&amp;rsquo;s just impossible to avoid them in home plumbing.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Water meter installed in water line&#34; src=&#34;https://www.apalrd.net/posts/2021/water_meter/installed1.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Water meter installed in water line feeding hot water heater&lt;/div&gt;
&lt;p&gt;Once the meters were installed and the water was back on, I got to setting up the electronics. I bench tested the electronics module, sealed the cover with hot glue, and installed the electronics. The cables on the water meters are long enough that I could mount the electronics module a bit out of the way, in case there is a water leak in the future. I mounted the electronics using special zip-ties with a hole in them to mount using a screw, they are very handy for stuff like this. I neatened the cables, pulled a new cat5e from the sensor back to my patch panel, and it was good to go.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Electronics testing&#34; src=&#34;https://www.apalrd.net/posts/2021/water_meter/installed2.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Testing the electronics before final mounting&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Electronics mounted&#34; src=&#34;https://www.apalrd.net/posts/2021/water_meter/installed3.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Final installed electronics&lt;/div&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are links to the files and parts required to make this project. As usual, all design files are licensed Creative Commons CC-BY-SA unless otherwise noted.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.flows.com/economy-plastic-water-meter-wm-pc-series/&#34;&gt;Assured Automation Economy Plastic Water Meter - WM-PC Series&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware&#34;&gt;Olimex ESP32-PoE Board&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.digikey.com/en/products/detail/cui-devices/RCJ-031/408499?s=N4IgTCBcDaIMIAUC0BGALCsSByAREAugL5A&#34;&gt;RCA Female Connectors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.digikey.com/en/products/detail/cui-devices/RCP-021/408540?s=N4IgTCBcDaIMIAUC0BGALAVgMxIHIBEQBdAXyA&#34;&gt;RCA Male Connectors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/water_meter/WaterMeterHousing2.amf&#34;&gt;3D Model for Housing (AMF Format)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/water_meter/WaterMeterCap.amf&#34;&gt;3D Model for Cap (AMF Format)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apalrd/PalHA_WaterMeter&#34;&gt;Github repo for the code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Measuring Water Softener Salt Remaining with ESP32</title>
      <link>https://www.apalrd.net/posts/2021/salt_meter/</link>
      <pubDate>Fri, 30 Apr 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2021/salt_meter/</guid>
      <description>I am currently living in my parents house, which is fed water by a private well. Due to the mineral content in most well water, we use a water softener. For those of you with city water, a water softener is a type of ion exchange filter which uses salt (sodium chloride) to replace calcium, magnesium, and other metals in the water with sodium. None of these minerals are hazardous, but they do stain everything, so reducing them is desirable.</description>
      <content>&lt;p&gt;I am currently living in my parents house, which is fed water by a private well. Due to the mineral content in most well water, we use a water softener. For those of you with city water, a water softener is a type of ion exchange filter which uses salt (sodium chloride) to replace calcium, magnesium, and other metals in the water with sodium. None of these minerals are hazardous, but they do stain everything, so reducing them is desirable. This process consumes salt, and the brine tank containing salt and a bit of brine water must be periodically refilled with bags of salt from the hardware store. These bags are cheap but heavy, and since it takes many months to go through a full tank of salt, it&amp;rsquo;s an easy task to forget until the water quality drops off. Thus, it&amp;rsquo;s a prime candidate for automated monitoring and alerting.&lt;/p&gt;
&lt;h1 id=&#34;contents&#34;&gt;Contents&lt;/h1&gt;
&lt;p&gt;Since this is a long project, I&amp;rsquo;ve left some links below for you to skip around. Enjoy!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/#the-video&#34;&gt;The Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/#design-concept&#34;&gt;Design Concept&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/#electronics&#34;&gt;Electronics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/#software&#34;&gt;Software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/#putting-it-all-together&#34;&gt;Putting it all Together&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/#adding-home-assistant-support&#34;&gt;Adding Home Assistant Support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/#project-files-and-parts-list&#34;&gt;Project Files and Parts List&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&#34;Salt tank, half full&#34; src=&#34;https://www.apalrd.net/posts/2021/salt_meter/salt_tank.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;The salt tank to be measured&lt;/div&gt;
&lt;h1 id=&#34;the-video&#34;&gt;The Video&lt;/h1&gt;
&lt;p&gt;There is a video corresponding to this project! Click the thumbnail below to see it.
&lt;a href=&#34;https://youtu.be/MmBF9xNavjQ&#34;&gt;&lt;img alt=&#34;Video Thumbnail&#34; src=&#34;https://www.apalrd.net/posts/2021/salt_meter/thumbnail.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;design-concept&#34;&gt;Design Concept&lt;/h1&gt;
&lt;p&gt;The design concept for this sensor was to take an off-the-shelf, sealed, ultrasonic distance measuring sensor and thread it through a hole in the lid of the salt brine tank. The sensor I chose was the &lt;a href=&#34;https://www.maxbotix.com/ultrasonic_sensors/mb7052.htm&#34;&gt;Maxbotix MB7052&lt;/a&gt; with a 1&amp;quot; NPS (National Pipe Straight) housing. An NPS thread uses the same thread profile and pitch as the more common NPT (National Pipe Taper), but without a taper, meaning it isn&amp;rsquo;t designed to seal. As the sensor has a 1&amp;quot; NPS housing, I need a  1&amp;quot; NPS nut on each side of the tank lid to secure the sensor. I found a suitable nut at &lt;a href=&#34;https://mcmaster.com&#34;&gt;McMaster-Carr&lt;/a&gt;, and downloaded their CAD file. I printed the CAD file as-is initially, to prove that the printer could resolve the thread detail well enough, and was satisfied with the fit between the printed part and the sensor. I then imported the CAD model with threads and used the hexagonal shape of the nut as the basis for the hexagonal design of the whole module. I thought it looked cool, the ESP32 board packaged well, and the Ethernet cable stuck out the top. The whole electronics module threads onto the back of the sensor, the sensor is hot-glued into the electroincs module, the wiring is completed, and finally the whole assembly is threaded through the tank and the bottom nut tightened. I eventually used this same hexagonal case on the &lt;a href=&#34;https://www.apalrd.net/projects/2021/water_meter/&#34;&gt;Water Meter&lt;/a&gt; project, although there was no reason to stick with the hexagon other than aesthetics on that project. In fact, that project also copied the software from this project as a starting point.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Hexagonal sensor housing&#34; src=&#34;https://www.apalrd.net/posts/2021/salt_meter/housing.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;The Hexagonal Housing, minus lid&lt;/div&gt;
&lt;h1 id=&#34;electronics&#34;&gt;Electronics&lt;/h1&gt;
&lt;p&gt;Given the desire to push all of my automation data to Ethernet as soon as possible, a logical choice for this project would be the ESP8266/ESP32 family of microcontrollers from Espressif. These low-cost MCUs contain built-in WiFi, and the newer ESP32 features built-in WiFi and Bluetooth (but not at the same time!), and support for many more peripherals, including optional wired 100Mbit Ethernet. There aren&amp;rsquo;t a lot of development boards with Ethernet PHYs on board, but the &lt;a href=&#34;https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware&#34;&gt;Olimex ESP32-PoE&lt;/a&gt; board is what I ended up choosing, having previously used it for the &lt;a href=&#34;https://www.apalrd.net/projects/2020/air_quality_sensor/&#34;&gt;Air Quality Project&lt;/a&gt;. It&amp;rsquo;s reasonably priced, supports PoE (even if the power supply can only handle a few watts, something I&amp;rsquo;d struggle with later), and using wired Ethernet with PoE for a sensor in my basement makes power and data that much easier to deal with.&lt;/p&gt;
&lt;p&gt;Aside from the ESP32 board, the Maxbotix sensor is wired directly to pins on the board and no other circuitry is required. I did end up adding a large capacitor across the power leads on the Maxbotix sensor to smooth power pulses during ultrasonic pings, and this greatly improved stability of the whole device when operating on PoE power. The Maxbotix sensor will run continuously by default, so I only need to wire power, ground, and UART TX from the sensor to UART RX on the ESP32.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Schematic&#34; src=&#34;https://www.apalrd.net/posts/2021/salt_meter/schematic.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;software&#34;&gt;Software&lt;/h1&gt;
&lt;p&gt;As mentioned earlier, the software for this project is the basis for the  &lt;a href=&#34;https://www.apalrd.net/projects/2021/water_meter/&#34;&gt;Water Meter&lt;/a&gt;. It&amp;rsquo;s built in Visual Studio Code using &lt;a href=&#34;https://platformio.org&#34;&gt;PlatformIO&lt;/a&gt;, using the ESP-IDF backend for ESP32 (instead of Arduino). After using Arduino for ESP32 in the &lt;a href=&#34;https://www.apalrd.net/projects/2020/air_quality_sensor/&#34;&gt;Air Quality Project&lt;/a&gt;, using the well-designed and well-documented ESP-IDF and PlatformIO is a very nice improvement to the code quality. All of the parameters are essentially hardcoded, and I compile/flash the board when I make changes. It isn&amp;rsquo;t as elegant as a nice web UI to set configuration parameters, but it works for me. Maybe in the future I&amp;rsquo;ll spend time developing a clean submodule for ESP-IDF projects to configure the Ethernet/MQTT backend components. Until then, you can feel free to &lt;a href=&#34;https://github.com/apalrd/PalHA_SaltSensor&#34;&gt;browse the code on github.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Maxbotix sensor is connected to a UART input on the ESP32, which reads and decodes the serial data stream. As the data is passed as ASCII text, the UART is configured to detect a pattern, which corresponds to a new line. When a new line is detected, UART driver adds the message to a queue, which is read by the Maxbotix task. Resulting messages are decoded into samples, which are stored in a circular buffer to be processed. If the time between a sample and the previous sample is excessively long, the circular buffer is emptied and the collection process starts over.&lt;/p&gt;
&lt;p&gt;Every 60 seconds, the data buffer is processed and the results are published to MQTT. A median filter is implemented. The median filter copies the last 64 samples into a local buffer, sorts the local buffer, removes the top 20% and bottom 20% of samples, and takes the mean of the resulting samples. As the Maxbotix sensor reports in integer centimeters but contains some sample noise, this is intended to improve accuracy of the number. The resulting sampled value, as well as the number of samples used to compute the median, are published to MQTT in JSON format. A low number of samples indicates a problem with the Maxbotix sensor. Due to the high power draw of the sensor during &amp;lsquo;ping&amp;rsquo; events, I had trouble getting the sensor to work reliably using PoE power, but eventually resolved this with large enough capacitors on the sensor power input.&lt;/p&gt;
&lt;h1 id=&#34;putting-it-all-together&#34;&gt;Putting It All Together&lt;/h1&gt;
&lt;p&gt;Assembly was pretty simple. I found the nearest hole saw size to the outer diameter of a 1&amp;quot; NPS thread. As with many other American units, 1&amp;quot; does not mean 1&amp;quot;, in this case it means the size of an iron pipe with a 1&amp;quot; inner diameter, so actual outer diamter is 1.315&amp;quot;. Imperial fist shake! The sensor had already been bench tested during software development, so I threaded the sensor and ESP32 through the housing for the last time and secured the sensor from the inside with hot glue. I hot glued the cover on, slipped the sensor into the hole in the tank lid, and secured it with the nut I&amp;rsquo;d printed earlier.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Sensor attached to tank from the outside&#34; src=&#34;https://www.apalrd.net/posts/2021/salt_meter/sense_outer.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Sensor attached to tank and functioning&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Sensor from the inside&#34; src=&#34;https://www.apalrd.net/posts/2021/salt_meter/sense_inner.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;View from the inside of the tank&lt;/div&gt;
&lt;p&gt;The measurement from the sensor is published in floating point centimeters. The tank is about a meter high, so I need to subtract the sensor reading from the height of the tank to get the centimeters of salt remaining in the tank. However, the bottom of the tank is always full of ~20cm of water, as the softener fills the bottom of the tank with water to dissolve the salt into brine, then pumps some of this water through the ion exchange resin during the regeneration process. The data is processed by Node-Red, where it is pushed to InfluxDB so I can view it in Grafana. The salt level periodically drops as the water softener regenerates, then it starts cycling between the high and low water levels frequently as the level of salt is lower than the level of the water. This is when I know it&amp;rsquo;s time to refill the salt.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Graph of 3 months of data in Grafana&#34; src=&#34;https://www.apalrd.net/posts/2021/salt_meter/graph.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Graph of 3 months of data in Grafana, including one vacation and one salt refill&lt;/div&gt;
&lt;h1 id=&#34;adding-home-assistant-support&#34;&gt;Adding Home Assistant Support&lt;/h1&gt;
&lt;p&gt;After almost a year with this sensor, I&amp;rsquo;ve migrated the home automation from Node-Red to Home Assistant, so I updated this page with the new HA configuration bits. I&amp;rsquo;m using an MQTT sensor to bring in the raw distance reading from the sensor, and a template sensor to convert from raw distance to a tank full percentage. Since the sensor measures down from the top, but we would like a percentage up from the bottom, we have to do a tiny bit of math. Both of the yaml snippets are below.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Tank Diagram&#34; src=&#34;https://www.apalrd.net/posts/2021/salt_meter/brinetank2.png&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;salt-level-sensor&#34;&gt;Salt Level Sensor&lt;/h3&gt;
&lt;p&gt;This should go in sensors.yaml. You&amp;rsquo;ll need to figure out the ESP&amp;rsquo;s MAC address, using a tool such as &lt;a href=&#34;http://mqtt-explorer.com/&#34;&gt;MQTT Explorer&lt;/a&gt;. In this case, it&amp;rsquo;s esp-6aba77, so the last 3 bytes of the MAC are 0x6ABA77.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Salt Level Sensor Reading&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mqtt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Salt Level&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;salt_level&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;state_topic&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;raw/esp-6aba77/ultra&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;value_template&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ value_json.Dist }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cm&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;salt-level-percent-template-sensor&#34;&gt;Salt Level Percent Template Sensor&lt;/h3&gt;
&lt;p&gt;Obviously if you already have a template and sensor section in your &lt;code&gt;configuration.yaml&lt;/code&gt;, put this inside instead of creating a new one.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;template&lt;/span&gt;: 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; - &lt;span style=&#34;color:#f92672&#34;&gt;sensor&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;#Salt Level Percent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Salt Level Percent&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;unique_id&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;salt_level_percent&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;unit_of_measurement&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#In this example, the tank is 140cm tall.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;#Substitute 140 with the total height of your tank in both places&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ (140 - (states(&amp;#39;sensor.salt_level&amp;#39;) | float))/140*100 }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;project-files-and-parts-list&#34;&gt;Project Files and Parts List&lt;/h1&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project. As usual, all design files are licensed Creative Commons CC-BY-SA unless otherwise noted.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.maxbotix.com/ultrasonic_sensors/mb7052.htm&#34;&gt;Maxbotix MB7052-500 (1&amp;quot; NPS housing)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware&#34;&gt;Olimex ESP32-PoE Board&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/TankSensorCap.amf&#34;&gt;3D Model for the Cap (AMF Format)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/TankSensorCap.stl&#34;&gt;3D Model for the Cap (STL Format, mm scale)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/TankSensorHousing.amf&#34;&gt;3D Model for the Housing (AMF Format)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/TankSensorHousing.stl&#34;&gt;3D Model for the Housing (STL Format, mm scale)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/posts/2021/salt_meter/Nut.stl&#34;&gt;3D Model for the Nut (STL Format, mm scale)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apalrd/PalHA_SaltSensor&#34;&gt;Github repo for the code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>My Very Tiny Virtualization Lab</title>
      <link>https://www.apalrd.net/projects/2021/minilab/</link>
      <pubDate>Tue, 16 Feb 2021 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2021/minilab/</guid>
      <description>After my experience with FreeBSD Jails and LXC containers, I wanted to get into &amp;lsquo;real&amp;rsquo; virtualization - and all of the advantages that come with it, like VM snapshot and restore features, moving VMs around between my workstation and production environment, and separating my storage from my compute. To this end, I built the Minilab, a small scale virtualization lab that will be at home in any house or appartment.</description>
      <content>&lt;p&gt;After my experience with FreeBSD Jails and LXC containers, I wanted to get into &amp;lsquo;real&amp;rsquo; virtualization - and all of the advantages that come with it, like VM snapshot and restore features, moving VMs around between my workstation and production environment, and separating my storage from my compute. To this end, I built the Minilab, a small scale virtualization lab that will be at home in any house or appartment.&lt;/p&gt;
&lt;h2 id=&#34;the-choice-of-hardware&#34;&gt;The Choice of Hardware&lt;/h2&gt;
&lt;p&gt;I already had &amp;lsquo;production&amp;rsquo; work running on my main server (including my very overworked automation server &lt;a href=&#34;https://www.apalrd.net/projects/2020/first_automation/&#34;&gt;Telstar&lt;/a&gt; and my security camera recorder &lt;a href=&#34;https://www.apalrd.net/projects/2020/zoneminder_intro/&#34;&gt;ZoneMinder&lt;/a&gt;), so I needed some new hardware to avoid downtime in the transition process. I built a my new virtualization server around an &lt;a href=&#34;https://www.asrock.com/nettop/AMD/DeskMini%20A300%20Series/index.asp&#34;&gt;Asrock Deskmini A300&lt;/a&gt;, which is a small form factor PC barebones which supports fairly modern AMD Ryzen APUs. It sported a few things that made this attractive to me as a minilab:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AMD Ryzen APUs are quite power efficient, and include a decently powerful Vega GPU (if I can ever pass that through to a VM without breaking the host)&lt;/li&gt;
&lt;li&gt;One M.2 slot for WiFi cards and one M.2 slot for NVMe storage (but &lt;em&gt;not&lt;/em&gt; SATA, as I would learn)&lt;/li&gt;
&lt;li&gt;Space and cabling for a 2.5&amp;quot; SATA SSD&lt;/li&gt;
&lt;li&gt;A full suite of video outputs (HDMI, DisplayPort, and VGA), which is important since I have an old VGA monitor next to my server rack&lt;/li&gt;
&lt;li&gt;On-board Gigabit Ethernet, USB-2, USB-3, and USB-C&lt;/li&gt;
&lt;li&gt;Single 19V power brick with all power supply circuitry on the motherboard&lt;/li&gt;
&lt;li&gt;No extra IO that I don&amp;rsquo;t need&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In all truth, I originally bought this SFF PC to be the basis of a 3D-prined PC project (since it&amp;rsquo;s small enough to 3D print a case on my Prusa), but I never actually built that project, and it was available, so it became the virtualization lab. I fitted it out with 16Gb of DDR4-3000, a 240Gb 2.5&amp;quot; SATA SSD, and most importantly, an AMD Ryzen 2400G APU. I know the 2400G is older than the 2400G in my production server, but I bought the parts for this back when the 3400G was brand new and the 2400G was on sale, so it&amp;rsquo;s what I&amp;rsquo;m going with.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-minilab&#34;&gt;Setting up the Minilab&lt;/h2&gt;
&lt;p&gt;The first choice for software on the Minilab was XCP-NG, a hypervisor operating system based around the Xen hypervisor. Xen is the open-source basis of a number of hypervisors including Cirtix XenServer, the open-source XCP-NG, and the privacy focused Quebes OS project, among others. XCP-NG combined with Xen Orchestra for management seemed like a good choice to get started with, given the desire to stay with open-source software (so Hyper-V and VMWare are out), and the great snapshot and backup features that Xen Orchestra provides on top.&lt;/p&gt;
&lt;p&gt;The Minilab has a 240Gb SSD which is available for VMs, and the Xen Orchesta VM is stored there (so I can manage the minilab if the remote storage has an issue). I also attached a zfs dataset on my primary server over the network for VM storage, and VMs can of course map their own network shares on that server as well. All seems well at this point&lt;/p&gt;
&lt;h2 id=&#34;setting-up-home-assistant&#34;&gt;Setting up Home Assistant&lt;/h2&gt;
&lt;p&gt;The first &amp;lsquo;real&amp;rsquo; VM I ran on the new minilab was Home Assistant. I imported the image of Home Assistant OS, expanded the filesystem to 32Gb, and started playing around. I don&amp;rsquo;t have a project article on my initial dealing with Home Assistant (I&amp;rsquo;m certainly not an expert on the topic yet), but it was the first real test of the Minilab.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-frigate&#34;&gt;Setting up Frigate&lt;/h2&gt;
&lt;p&gt;After many months of using the Minilab with Home Assistant, I wanted to add &lt;a href=&#34;https://www.apalrd.net/projects/2021/frigate_intro/&#34;&gt;Frigate NVR&lt;/a&gt; as a new VM. Home Assistant OS supports running it as a supervised add-on, but I wanted to store the video data on my primary storage pool over the network, and Home Assistant OS doesn&amp;rsquo;t allow any package management or file mapping within the OS (it&amp;rsquo;s purely a Docker host managed through Home Assistant Supervisor). So, I created a new Ubuntu VM to run Frigate, and bought a pair of &lt;a href=&#34;https://www.coral.ai/&#34;&gt;Coral AI&lt;/a&gt; devices to offload AI inferencing for Frigate. I was able to install Frigate and run it, but with just CPU it was unable to handle my full suite of 5 security cameras. I kept it going for just one camera, and let it run for a few weeks to get a feel for how well Frigate works with Home Assistant. This is the first time I&amp;rsquo;ve gone straight to the minilab to test new software instead of running a VM on my workstation in VirtualBox, and I&amp;rsquo;m really enjoying having a compute server to use, even if it&amp;rsquo;s not very powerful.&lt;/p&gt;
&lt;p&gt;Unfortunately, when the two coral.ai devices came (one M.2 B+M key and one M.2 E key, finally a use for the WiFi slot on the A300 Deskmini!), I struggled to get PCIe passthrough working in XCP-NG. I was able to drop the devices from dom0 (the Linux host which manages the Xen hypervisor), but couldn&amp;rsquo;t get them to pass through. Xen was not showing IOMMU as enabled, even though the CPU supported it, and IOMMU support is required for PCIe passthrough.&lt;/p&gt;
&lt;h2 id=&#34;switching-to-proxmox&#34;&gt;Switching to Proxmox&lt;/h2&gt;
&lt;p&gt;Still overall happy with XCP-NG, I decided to switch to Proxmox to get better hardware passthrough support. It&amp;rsquo;s based on Debian Linux and uses the KVM hypervisor (Linux Kernel-based Virtual Machine), so it should have the advantage of Linux&amp;rsquo;s excellent hardware support. As expected, I just had to enable AMD IOMMU in the Linux boot options and it seemed to work correctly. The host Debian system kept trying to use the Coral&amp;rsquo;s itself, so I had to blacklist the drivers for those, but they still didn&amp;rsquo;t show up in the PCIe passthrough menu. I was able to get through it using the command line, but it wasn&amp;rsquo;t a smooth process. But, now, I have an Ubuntu 20.04 VM which has the two Coral AI accelerators available for use, and I can install Frigate.&lt;/p&gt;
&lt;p&gt;Because I blew away my XCP-NG install, I had to backup and reload my Home Assistant installation across hypervisors. I decided to do a backup in Home Assistant OS and also a backup in Xen Orchestra, so I&amp;rsquo;d have options in the restore process. When restoring, I created a new VM in Proxmox with Home Assistant OS, using the latest install image, and reloaded the backup file there. After a few minutes it had figured itself out and was back exactly as I&amp;rsquo;d left it, no need for the disk image from Xen Orchestra.&lt;/p&gt;
&lt;h2 id=&#34;the-final-verdict&#34;&gt;The Final Verdict&lt;/h2&gt;
&lt;p&gt;I liked XCP-NG and Xen Orchestra, but I needed better hardware support that Proxmox provides. I&amp;rsquo;m not sure which I&amp;rsquo;ll end up going with in my next homelab, but I&amp;rsquo;m certainly happy to get away from the console LXC commands of my current server. I&amp;rsquo;m not using the ZFS features on Proxmox since I already have a ZFS pool on the storage server, and I like the separation of compute from storage, since a lot of my storage is accessed directly, not via the VMs. In my mind, this will become an advantage as I scale up and the load on the storage part of the system increases, but in reality it&amp;rsquo;s still mostly just a fictional future load for a future homelab.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>My Experiences with a ZoneMinder Home Security Camera System</title>
      <link>https://www.apalrd.net/projects/2020/zoneminder_intro/</link>
      <pubDate>Sat, 04 Jul 2020 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2020/zoneminder_intro/</guid>
      <description>This project describes my process of building a home security camera system using Dahua PoE cameras and ZoneMinder. Overall the system is functional, but Zoneminder leaves a bit to be desired. I will revisit this project in the future.
The Beginnings of a Camera System The real OG camera system was installed by my dad a decade ago using analog &amp;lsquo;960H&amp;rsquo; cameras (which are grossly misleading in their advertising since they market the horizontal resolution instead of the usual vertical resolution, they are actually 480x960 at best).</description>
      <content>&lt;p&gt;This project describes my process of building a home security camera system using &lt;a href=&#34;https://www.dahuasecurity.com/&#34;&gt;Dahua&lt;/a&gt; PoE cameras and &lt;a href=&#34;https://zoneminder.com/&#34;&gt;ZoneMinder&lt;/a&gt;. Overall the system is functional, but Zoneminder leaves a bit to be desired. I will revisit this project in the future.&lt;/p&gt;
&lt;h2 id=&#34;the-beginnings-of-a-camera-system&#34;&gt;The Beginnings of a Camera System&lt;/h2&gt;
&lt;p&gt;The real OG camera system was installed by my dad a decade ago using analog &amp;lsquo;960H&amp;rsquo; cameras (which are grossly misleading in their advertising since they market the horizontal resolution instead of the usual vertical resolution, they are actually 480x960 at best). The system used a Chinese DVR which was limited to 8 cameras, and one after another they failed due mostly to poor quality cabling. The image quality was also awful. So, a new setup was desirable. We don&amp;rsquo;t live in a very dangerous area, but we like to look at the cameras to check on things when we go on vacation, and they can also be useful to keep track of deliveries and who&amp;rsquo;s home or away.&lt;/p&gt;
&lt;p&gt;For the &amp;lsquo;New&amp;rsquo; first camera system, I wanted to go all IP based, with plenty of room to upgrade in the future, and complete local control. I wanted to be free of any cloud services. I didn&amp;rsquo;t mind paying for licensed software when it&amp;rsquo;s the best option, but I&amp;rsquo;d prefer an open source solution and absolutely require Linux or BSD for servers. I already had a PoE managed network switch (&lt;a href=&#34;https://mikrotik.com/product/crs328_24p_4s_rm&#34;&gt;Mikrotik CRS328-24P-4S+RM&lt;/a&gt;), so the next choice was the cameras.&lt;/p&gt;
&lt;p&gt;Based on the camera review of &lt;a href=&#34;https://intermit.tech&#34;&gt;intermit.tech&lt;/a&gt;, I looked at Dahua, one of the two major Chinese camera OEMs (the other is Hikvision). I decided to try the DH-IPC-HDW2431TP (4MP/1440P &amp;lsquo;Lite&amp;rsquo; series) and DH-IPC-HDW5831RP-ZE (8MP/4K &amp;lsquo;Pro&amp;rsquo; series, the one he calls the &amp;lsquo;old champ&amp;rsquo; in a few videos). The Pro series cameras have a better build quality, higher resolution, and a varifocal lens that can be considerably sharper in certain scenarios. The Lite series cost 1/3 the price with a fixed focus lens, so you have to design around the focal range of the lens. I ran an Ethernet cable to my first location and setup the Pro for a week, followed by the  Lite, and compared the two. Based on this test, I decided that the Lite series was perfectly adequate for most of the views I wanted to capture. Most of the camera locations I wanted were near entry doors, so the fixed focus lens was a good match for close range imaging above each door. I then bought a 5-pack of the Lite cameras to build out the whole system (7 cameras in hand now).&lt;/p&gt;
&lt;h2 id=&#34;short-review-of-the-dahua-cameras&#34;&gt;Short Review of the Dahua Cameras&lt;/h2&gt;
&lt;p&gt;I highly recommend you review intermit.tech&amp;rsquo;s IP Camera series (&lt;a href=&#34;https://blog.quindorian.org/category/ip-camera/&#34;&gt;Blog Link&lt;/a&gt;)(&lt;a href=&#34;https://www.youtube.com/playlist?list=PL4b74vD-Uo-PMOUTsC2Yp5OXlDLAqWe6w&#34;&gt;YouTube Link&lt;/a&gt;). He&amp;rsquo;s done a good job at showing the features and visual comparisons of each camera. The right camera for you is very subjective. In my case, I was on a fairly low budget, and not trying to spot a license plate or face at the end of my driveway, especially not at night.&lt;/p&gt;
&lt;p&gt;In my case, here are my observations which may be useful to you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The software security of the cameras impressed me, given the my very low expectations based on the reputation of cheap IoT devices. When first connecting to the camera, it made me choose a new password, offered me the choice to enable or disable cloud services, and hasn&amp;rsquo;t made any attempt to call home as verified by my router. This is a professional product, albeit from China, and it&amp;rsquo;s software design shows some care has been given to security.&lt;/li&gt;
&lt;li&gt;The Web UI is a bit basic, but it&amp;rsquo;s functional to navitage and configure the camera. The cameras support both h.264 and h.265, although I operate them in h.264 mode to remove the need to transcode the recordings to view them (since no web browser other than Safari natively supports h.265 as of the writing of this).&lt;/li&gt;
&lt;li&gt;The Lite cameras support a main stream of up to 2560x1440x30fps (1440p) and a single sub stream of up to 704x480x30fps (D1). You can independently select the resolution, framerate, encoding mode (constant/variable bit rate), maximum bit rate, i-frame interval, and codec (h.264 or h.265) for each stream.&lt;/li&gt;
&lt;li&gt;The Pro cameras support three streams. The main stream supports up to 3840x2160x15fps (4K), and the two sub streams support up to 704x480x15fps (D1) for sub stream 1 and 1920x1080x15fps (1080p) for sub stream 2. All 3 streams can be enabled at once, and again have independent configuration of all parameters&lt;/li&gt;
&lt;li&gt;The cameras show up in &lt;a href=&#34;https://sourceforge.net/projects/onvifdm/&#34;&gt;ONVIF Device Manager&lt;/a&gt;, as they should, being advertised as ONVIF compliant. I don&amp;rsquo;t use an ONVIF compliant NVR, so I can&amp;rsquo;t test intgration with other hardware, but ONVIF Device Manager can help you identify the streams if you need help with that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When wiring the cameras, I bought Ubiquiti Toughcable, which has a black polyethylene (PE) jacket instead of the usual PVC, so it does not degrade in sunlight. It seems like they have discontinued this cable, but any outdoor rated cable, preferrably non gel filled, will work for outdoor wiring. I had to run some cameras 50&amp;rsquo; or more outdoors along a brick ledge between the first and second floor of the house, but for short runs of a few feet an indoor rated cable should be fine.&lt;/p&gt;
&lt;h2 id=&#34;the-great-nvr-test-campaign&#34;&gt;The Great NVR Test Campaign&lt;/h2&gt;
&lt;p&gt;I initially tried a number of open source NVRs in a virtual machine on my personal workstation using Virtualbox. The goal of these tests was to estimate the CPU and RAM requirements for a single camera (by limiting the VM to one core or less on my Ryzen Threadripper 1950X), test scalability with the 2 cameras I had installed at the time, and evaluate the installation process, maintenance, UI, and apps.&lt;/p&gt;
&lt;p&gt;The tests included the long-running open source project &lt;a href=&#34;https://zoneminder.com/&#34;&gt;ZoneMinder&lt;/a&gt;, &lt;a href=&#34;https://motion-project.github.io/index.html&#34;&gt;Motion&lt;/a&gt;, and &lt;a href=&#34;https://shinobi.video/&#34;&gt;Shinobi&lt;/a&gt;. ZoneMinder was functional but required a lot of menus to setup, but offered a ton of configuration of exactly how to extract the video (using ffmpeg internally) and manage the streams. Motion seemed to lack the comprehensive system feature set I wanted, and more focused on being lightweight. At the time of this review (2020), Shinobi&amp;rsquo;s setup did not function correctly in my Ubuntu virtual machine and overall it was a very painful process. Considering the recent age of the project it&amp;rsquo;s possible the developer has improved it.&lt;/p&gt;
&lt;p&gt;I also tried trial versions of a few commercial products including Xenoma and Blue Iris, but was dissatisfied with both. Xenoma licensing does not allow running personal licenses in a virtual machine, which would drastically raise the price for me running virtual machines at home. Blue Iris only supports Windows, and I&amp;rsquo;d like to avoid a Windows virtual machine just for this. My goal was to run this software in a LXC container on Ubuntu (18.04 Bionic Beaver), with the host running a ZFS pool for storage. At this point in the project, the NVR was expected to run on the existing storage server, which was not very powerful and the low overhead LXC container was preferrable over a paravirtualized Linux or hardware virtualized Windows virtual machine. My knowledge of virtual machines was also poor going in to this project.&lt;/p&gt;
&lt;h2 id=&#34;the-choice-of-zoneminder&#34;&gt;The Choice of Zoneminder&lt;/h2&gt;
&lt;p&gt;Zoneminder is very functional and reliable, as you would expect from a nearly 20 year project still in active development. However, it&amp;rsquo;s design age is showing. When the project was started, it was expected that analog cameras would be connected to a v4l capture card, and presented as a raw framebuffer for use by the processing tasks. It still somewhat operates this way internally, with the incoming camera stream decoded into a framebuffer for analysis. All detection is done purely by the CPU on raw decoded frames, and there is no native support for using lower resolution streams for motion detection and higher resolution streams for recording. The solution around this limitation is to setup two monitors, one with the low-res stream and one with the high-res stream, and have the low-res stream run detection and trigger the high-res camera so both record on motion. This results in twice as many recordings (one for each stream), although the low-res recordings are significantly smaller. It also means that analyzing and tweaking the motion analysis requires watching the low resolution 704x480 D1 resolution video to see the analysis results. After all of these negatives, I still liked the software and went forward with setting it up on the production server&lt;/p&gt;
&lt;h2 id=&#34;upgrading-to-new-hardware&#34;&gt;Upgrading to New Hardware&lt;/h2&gt;
&lt;p&gt;The production server at this point in time was an AMD Bulldozer family APU designed for mobile applications, but I bought it as an embedded mini-ITX board with a soldered CPU. This APU performed well running Ubuntu 18.04 Bionic Beaver, as well as ZFS on Linux for the data pool. Prior to the installation of Zoneminder, it was already hosting an LXC container for the first generation home automation system, which comprised of an MQTT broker, InfluxDB server, Grafana server, and Node-Red server, with all logic being done by Node-Red. The Bulldozer CPU was a quad-core, but the AMD construction equipment family (Bulldozer/Piledriver/Excavator) was famous for having tightly coupled core pairs sharing execution units more similar to hyperthreading than truly distinct cores. To attempt to simulate the performance of this low end CPU, I ran my Zoneminder virtual machine with 2 cores of the Threadripper and an execution cap of 1/2 each CPU. It ran adequately with the 2 cameras in my test setup, although it was certainly reaching the limit of that hardware. Installed on the Bulldozer, it was unable to run more than two cameras with low resolution motion detection.&lt;/p&gt;
&lt;p&gt;As it was unable to run the 2 cameras I already had installed and I still had 5 more cameras to install, a hardware upgrade was in order. I ended up replacing as few components as possible, resulting in the following hardware setup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AMD Ryzen 5 3400G APU (4c/8t)&lt;/li&gt;
&lt;li&gt;ASRock B450M Micro-ATX motherboard&lt;/li&gt;
&lt;li&gt;Intel X520-DA2 10G SFP+ network card (half-height)&lt;/li&gt;
&lt;li&gt;16Gb DDR4-3200 RAM in two sticks of 8gb each&lt;/li&gt;
&lt;li&gt;Existing 240Gb SSD boot drive and data storage pool were retained&lt;/li&gt;
&lt;li&gt;Existing 120W &lt;a href=&#34;https://www.mini-box.com/s.nl/it.A/id.417/.f&#34;&gt;PicoPSU&lt;/a&gt; was retained, along with the AC to DC converter, which was secured into the case with double sided foam tape.&lt;/li&gt;
&lt;li&gt;Existing 80mm case fans were upgraded to Noctua equivalents since the cheap Rosewill case was very loud&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the new hardware setup, I was able to install the Ubuntu HWE (HardWare Enablement) package to get the latest kernel graphics drivers and permit the LXC container to access the GPU for hardware accelerated h.264 decoding. I was also able to connect the server to the switch with a 10G SFP+ DAC cable, although at this point in time there are no clients which can use 10G anyway, so at best it currently just allows higher aggregate throughput for multiple clients, and in reality it&amp;rsquo;s just the start of a future expansion to a 10G backbone.&lt;/p&gt;
&lt;h2 id=&#34;final-verdict&#34;&gt;Final Verdict&lt;/h2&gt;
&lt;p&gt;ZoneMinder is currently functioning and has been for several months. I continuously tweak the motion zones and thresholds to reduce the false triggers due to swaying tree shadows, flies, and spiders making webs in front of the camera. The visible area from two cameras could be improved by tree trimming. The LXC container has a 1Tb ZFS quota, ensuring it doesn&amp;rsquo;t fill my entire storage pool with months of recordings. The mobile app (zmNinja) works well, when combined with my personal home VPN (direct from my phone to my home router).&lt;/p&gt;
&lt;p&gt;At a rate of approximately one per month, I installed 3 of the remaining 5 cameras around the house, leaving the last two as winter approached and I didn&amp;rsquo;t want to deal with running another conduit through brick to access the rear walkout of the house. But, there aren&amp;rsquo;t packages or cats waiting at that door, so it&amp;rsquo;s not high priority at this point in time.&lt;/p&gt;
&lt;h2 id=&#34;fall-2021-update&#34;&gt;Fall 2021 Update&lt;/h2&gt;
&lt;p&gt;The system described in this project was operational for 2 years without major issues. In the future, this setup was replaced with &lt;a href=&#34;https://www.apalrd.net/projects/2021/frigate_intro/&#34;&gt;Frigate NVR&lt;/a&gt;, but the cameras, wiring advice, and software testing listed here is still valid.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Installing a Whole-House Per Circuit Energy Meter</title>
      <link>https://www.apalrd.net/projects/2020/power_meter/</link>
      <pubDate>Thu, 04 Jun 2020 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2020/power_meter/</guid>
      <description>After setting up my 1-Wire Temperature Network, my next sensory target was my AC breaker panel. I watched reviews for products such as the Sense energy monitor, The Energy Detective, and a few others, and felt like none of them did what I wanted. I know that big loads in my house use a lot of power (duh), I want to know how much power specific people and rooms in the house use, so I can improve my home energy modeling skills.</description>
      <content>&lt;p&gt;After setting up my &lt;a href=&#34;https://www.apalrd.net/projects/2019/onewire/&#34;&gt;1-Wire Temperature Network&lt;/a&gt;, my next sensory target was my AC breaker panel. I watched reviews for products such as the Sense energy monitor, The Energy Detective, and a few others, and felt like none of them did what I wanted. I know that big loads in my house use a lot of power (duh), I want to know how much power specific people and rooms in the house use, so I can improve my home energy modeling skills. This, to me, required a sensor on each device or circuit, to directly measure as much as possible and not rely on &amp;lsquo;AI&amp;rsquo; buzz to pick out a few major appliances.&lt;/p&gt;
&lt;h2 id=&#34;the-brultech-greeneye-monitor&#34;&gt;The Brultech GreenEye Monitor&lt;/h2&gt;
&lt;p&gt;The energy monitor I chose is the &lt;a href=&#34;https://www.brultech.com/greeneye/&#34;&gt;Brultech GreenEye Monitor (GEM)&lt;/a&gt;. I chose this monitor because of the following attributes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Offers WiFi and hardwired Ethernet, with a well-documented and purely local API (no cloud required)&lt;/li&gt;
&lt;li&gt;Offers 32 channels of true power monitoring (although it only measures phase voltage on one phase of a split-phase North American supply, so there will be a very slight error on half of the channels). This is a lot of channels for one device&lt;/li&gt;
&lt;li&gt;Packages include donut CTs for regular circuits (40A or less) at an excellent price per circuit compared to anything else on the market&lt;/li&gt;
&lt;li&gt;It also has pulse and one-wire monitoring, but I already have a 1-wire network so I won&amp;rsquo;t be using either of those features&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I ended up buying the GEM+CT Package and getting 32x 40A donut CTs, plus buying an extra 3x 60A split CTs for really big circuits. Since the total number of circuits in my panel is 33 (including all double-pole circuits once), I left out the master bath jet pump circuit since it&amp;rsquo;s infrequently used and did not monitor the mains. I had a 20A and a 15A double pole circuit which I used with one 40A donut CT each (same as all the other 15A and 20A circuits), since they are for motors with no neutral. I had a 60A air conditioner which got a single Split-60, and a 50A stove and cooktop which got a pair of Split-60s wired electrically to the same channel on the GEM.&lt;/p&gt;
&lt;h2 id=&#34;installation-process&#34;&gt;Installation Process&lt;/h2&gt;
&lt;p&gt;Installing the CTs took awhile, and with the power off to the whole building, I didn&amp;rsquo;t get any pictures of the process. Before I turned off the power, I made heat-shrink labels for each CT with a number on them so I could keep track of the CTs. I turned off the main breaker, removed the cover, and planned the wiring route for the 33x CT wires. I mounted the GEM next to the breaker panel but close enough that I could route the wires around the side without crossing over a stud, and ran the wires through a plastic bushing in the bottom of the panel, through the wall, and into the GEM. Each 40A donut required me to unscrew the wire from the breaker, remove it, slip it through the CT, and screw it back in to the breaker. Every few circuits I zip-tied the CT wires together and neatly dressed them down both sides of the panel, across the bottom, and out. I went down one side with the CTs numbered 1-15, and then down the other side with the rest of the 40A donuts, and then did the 60A ones last. I knew I&amp;rsquo;d be able to count breakers later to match CT numbers to circuits. Once the GEM was installed, I planned on running a tap off an exsting 15A circuit to a new outlet box right at the panel (the nearest outlet is ~8&amp;rsquo; away), but I didn&amp;rsquo;t end up doing that. I closed the panel and power was restored, and there was much rejoicing.&lt;/p&gt;
&lt;p&gt;After physically installing the GEM, I pulled a new Cat5e wire from the patch panel into the GEM and crimped it with an RJ45 male. I ran a 6&amp;rsquo; 2-wire extension cord to the GEM to power both of the power supplies - the GEM needs an AC reference voltage which it gets from an AC wall-wart, plus a 5V DC supply to power itself.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;GEM installed&#34; src=&#34;https://www.apalrd.net/projects/2020/power_meter/gem.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;GEM installed, with PoE splitter attached to lid&lt;/div&gt;
&lt;h2 id=&#34;setting-up-the-software&#34;&gt;Setting up the Software&lt;/h2&gt;
&lt;p&gt;I had just finished setting up &lt;a href=&#34;https://www.apalrd.net/projects/2020/first_automation/&#34;&gt;Telstar&lt;/a&gt;, my automation server, and was eager to capture the data from the GEM in Node-Red. I ended up setting the GEM to do an HTTP request to a webserver at a fixed interval (5sec) with each value as a parameter. I setup Node-Red with an HTTP In node to capture this, then used some node-red commands to filter out and parse the strigns into floats (they all come in as strings, unfortunately), then I wrote some Function nodes to take the derivative of the energy totals and re-bundle everything into JSON to pass to MQTT. The Node-Red flow I used to do this is available below.&lt;/p&gt;
&lt;p&gt;Shortly after getting all of this working, I realized that I can&amp;rsquo;t tell the difference between power being out (actually out), something wrong with the GEM, or someone accidentally unplugging my 6&amp;rsquo; extension cord. To remedy this, I got a PoE splitter and taped it to the case of the GEM with double sided foam tape. It outputs the 5v that the GEM needs to power itself, and is powered by my PoE switch which is backed up by a UPS. Now, I can look at the voltage reported by the GEM (which should be around 120V) and tell if either the power is out or someone unplugged the potential transformer, and fix the situation, without losing connection to the GEM in the process. The PoE splitter I used is a TP-Link TL-POE10R.&lt;/p&gt;
&lt;p&gt;Using my brand new Grafana server, I started experimenting with the best way to view the data. I&amp;rsquo;m not ready to share the entire graph code, but I have a dashboard showing total power consumption today, current line voltage, and pie charts showing total energy usage for each floor of the house. I also have a few charts of &amp;rsquo;everything&amp;rsquo;, which are really difficult to view but are designed to be exported to a csv for analysis.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Graph showing totals and first floor data&#34; src=&#34;https://www.apalrd.net/projects/2020/power_meter/graphs.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Top of the Grafana page showing the daily totals and data from the first floor&lt;/div&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are links to the files and parts required to make this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.brultech.com/greeneye/&#34;&gt;Brultech GreenEye Monitor (GEM)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2020/power_meter/gem_parser.json&#34;&gt;Node-Red Flow to parse GEM packet into MQTT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.tp-link.com/us/business-networking/accessory/tl-poe10r/&#34;&gt;TP-Link TL-POE10R PoE splitter 802.3af&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;update-spring-2021&#34;&gt;Update Spring 2021&lt;/h2&gt;
&lt;p&gt;Someone tripped over the AC reference supply and broke it, since I never finished wiring the outlet right at the breaker panel. I emailed Brultech, since I was unable to find a power supply with a 3.5mm jack. I provided my serial number, and they sent me a new one for just the cost of shipping (from Canada). The new transformer arrived and power measurement is working again. Happy with the customer support from this company.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Air Particle Measurement</title>
      <link>https://www.apalrd.net/projects/2020/air_quality_sensor/</link>
      <pubDate>Mon, 11 May 2020 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2020/air_quality_sensor/</guid>
      <description>Inspired by Jonathan Oxer&amp;rsquo;s Air Quality project, I decided to build my own, but with my own twist and my own software. This project was an adventure bridging my long-held Arduino skills with modern Ethernet microcontrollers, object-oriented programming, and a lesson in how important mechanical design is.
Concept Design Jon&amp;rsquo;s sensor uses a Plantower PMS5003, and later adds a Bosch BME680 air quality sensor. I decided to use the similar Plantower PMS7003, Bosch BME680, and also a CCS811 environmental sensor which measures eCO2 for comparison to the BME680.</description>
      <content>&lt;p&gt;Inspired by &lt;a href=&#34;https://www.superhouse.tv/38-diy-air-quality-sensor-part-1-basic-model/&#34;&gt;Jonathan Oxer&amp;rsquo;s Air Quality project&lt;/a&gt;, I decided to build my own, but with my own twist and my own software. This project was an adventure bridging my long-held Arduino skills with modern Ethernet microcontrollers, object-oriented programming, and a lesson in how important mechanical design is.&lt;/p&gt;
&lt;h2 id=&#34;concept-design&#34;&gt;Concept Design&lt;/h2&gt;
&lt;p&gt;Jon&amp;rsquo;s sensor uses a Plantower PMS5003, and later adds a Bosch BME680 air quality sensor. I decided to use the similar Plantower PMS7003, Bosch BME680, and also a CCS811 environmental sensor which measures eCO2 for comparison to the BME680.&lt;/p&gt;
&lt;p&gt;I decided to try a new microcontroller, the Espressif ESP32. I&amp;rsquo;ve used the older ESP8266 in the past for a few WiFi enabled projects in college, using the Arduino IDE. For this project, I wanted the sensor to be a permanent fixture in the house, and WiFi isn&amp;rsquo;t ideal for that, so I found an ESP32 development board with wired Ethernet - the &lt;a href=&#34;https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware&#34;&gt;Olimex ESP32-PoE&lt;/a&gt;. The ESP32 has a native Ethernet MAC built-in, so it just needs a dev board that includes a PHY, but that&amp;rsquo;s easier said than done. Again, I used the Arduino IDE for this project, based on my familiarity with it and the ESP8266.&lt;/p&gt;
&lt;h2 id=&#34;building-the-node&#34;&gt;Building the Node&lt;/h2&gt;
&lt;p&gt;Unlike the PMS5003 that Jon uses, the PMS7003 has a connector designed to be PCB mounted instead of crimped to flying leads. This made it significantly more difficult to work with. I soldered and heat-shrunk small wires to the 4 required pins (VCC, Gnd, TX, RX) on the sensor, but the small pins were very fragile. For the BME680 and CCS811, both use the I2C bus, so I soldered the two PCBs together with heat shrink covering the wires between them. I then soldered this whole mess to the ESP32-PoE board, completing the sensor node. This open-concept design would never come back to haunt me.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Completed sensor node&#34; src=&#34;https://www.apalrd.net/projects/2020/air_quality_sensor/sensor1.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Completed Sensor Node&lt;/div&gt;
&lt;h2 id=&#34;designing-the-software&#34;&gt;Designing the software&lt;/h2&gt;
&lt;p&gt;For the software, I had grand aspirations of building a cool universal sensor node firmware that I could configure with #defines and flash onto whatever target I wanted. I quickly found out that this was easier said than done. Arduino is C++ based, although it&amp;rsquo;s largely bogged down with hacks done back when the Atmel AVR processors didn&amp;rsquo;t have enough memory to run any real code. For example, printf() and stdout are not implemented, instead there are a series of print functions which print a single type of item (string literal, integer, hexadecimal, float) and you must call them in sequence to print the whole thing. In addition, the Arduino port for the Espressif microcontrollers is backed by the ESP-IDF library from Espressif, which provides many of its own useful functions already.&lt;/p&gt;
&lt;p&gt;With all of that out of the way, I eventually cobbled together external libraries from Adafruit and others to get all of my sensors working, and merged them with my own code to poll them and publish the results to MQTT. The only function I never got to work was the BME680, since the Bosch official library (which is required for eCO2 measurement) is distributed in binary-only form. It does have a version for ESP32, but it requires the user to store a binary blob of data between resets which contains data the library has learned about the individual calibration of the sensor. I did not get this storage to work right, and as a result the BME680 library continuously reports an eCO2 error. I still get temperature and humidity, so I guess that&amp;rsquo;s something useful, right?&lt;/p&gt;
&lt;p&gt;The code is a bit of a mess, but you can still feel free to &lt;a href=&#34;https://github.com/apalrd/PalNode&#34;&gt;browse the code on github.&lt;/a&gt;. Going forward, I am going to find an alternative to Arduino for these microcontrollers.&lt;/p&gt;
&lt;h2 id=&#34;late-2020-update&#34;&gt;Late 2020 Update&lt;/h2&gt;
&lt;p&gt;As expected, the tiny wire connections to the PMS7003 eventually failed. The sensor continues to operate with just the BME680 and CCS811, and those are still reporting data.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Dipping My Toes into Home Automation</title>
      <link>https://www.apalrd.net/projects/2020/first_automation/</link>
      <pubDate>Wed, 08 Apr 2020 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2020/first_automation/</guid>
      <description>I&amp;rsquo;ve long followed the videos and episodes of Jonathan Oxer of SuperHouse, and decided to design my first true automation system around his design ideas. This project describes the basic setup of the automation system I setup and explored, and replaces the dabblings I&amp;rsquo;ve had with EmonCMS in the past (See the One-wire Project).
Software Stack Jon is big on the use of MQTT for transport, having developed a lot of his own hardware before it was easily available (especially so in Australia where he is located) and standardizing on the protocol for its general and flexible nature.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve long followed the videos and episodes of &lt;a href=&#34;https://www.superhouse.tv/&#34;&gt;Jonathan Oxer of SuperHouse&lt;/a&gt;, and decided to design my first true automation system around his design ideas. This project describes the basic setup of the automation system I setup and explored, and replaces the dabblings I&amp;rsquo;ve had with EmonCMS in the past (&lt;a href=&#34;https://www.apalrd.net/projects/2019/onewire/&#34;&gt;See the One-wire Project&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&#34;software-stack&#34;&gt;Software Stack&lt;/h2&gt;
&lt;p&gt;Jon is big on the use of MQTT for transport, having developed a lot of his own hardware before it was easily available (especially so in Australia where he is located) and standardizing on the protocol for its general and flexible nature. I wanted to base my system around MQTT as well, using Node-Red to perform logic and bridge sensor inputs with command outputs. The complete software stack that I ended up choosing is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://mosquitto.org/&#34;&gt;Mosquitto MQTT broker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nodered.org/&#34;&gt;Node-Red Automation Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.influxdata.com/&#34;&gt;InfluxDB 1.8 Timeseries Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://grafana.com/&#34;&gt;Grafana Visualization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.influxdata.com/time-series-platform/telegraf/&#34;&gt;Telegraf Data Collector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;testing-the-software&#34;&gt;Testing the Software&lt;/h2&gt;
&lt;p&gt;I started off with a virtual machine running Ubuntu 18.04 Bionic in VirtualBox on my workstation. This let me experiment with setup of the integration between all of the components, get them talking to each other, etc. with easy roll back ability in VirtualBox. VirtualBox is the only virtualization platform I&amp;rsquo;ve used as of yet, since my former FreeNAS server (now running bare Ubuntu 18.04) is not powerful enough to run something like Proxmox with decent performance in the VMs.&lt;/p&gt;
&lt;p&gt;I settled on a number of design decisions overall:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All data goes through MQTT at some point&lt;/li&gt;
&lt;li&gt;Data direct from sensors (unprocessed) goes into the /raw topic header (which is not logged into Influx)&lt;/li&gt;
&lt;li&gt;Data which has been processed goes into a better topic like /climate or /energy&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t have any outputs yet, other than email notifications, so there are no topics for output yet&lt;/li&gt;
&lt;li&gt;Node-Red transforms data by subscribing to MQTT topics or reading the data directly and writing the data to MQTT for use by other flows&lt;/li&gt;
&lt;li&gt;Telegraf captures all &amp;lsquo;good&amp;rsquo; MQTT data and logs it to InfluxDB&lt;/li&gt;
&lt;li&gt;Grafana reads all data from the InfluxDB captured via the MQTT collector and displays it&lt;/li&gt;
&lt;li&gt;I thought that Node-Red could potentially have reliability issues, and wanted to make sure that the setup would work with just Mosquitto, although I quickly found out that Node-Red is in fact very reliable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;installing-the-software&#34;&gt;Installing the Software&lt;/h2&gt;
&lt;p&gt;Once I had tested the software, I started learning how to use Linux Containers. I spun up an Ubuntu 18.04 VM and tried my hand at creating, destroying, and managing containers using LXC. Most of the way through this process, I finally learned the difference between LXC and LXD (&amp;rsquo;new&amp;rsquo; Linux Containers), but stuck with &amp;lsquo;old&amp;rsquo; LXC since I&amp;rsquo;d picked it up already by this point.&lt;/p&gt;
&lt;p&gt;On my very low power AMD Bulldozer-based file server, I created my first &amp;lsquo;production&amp;rsquo; container on the ZFS pool, named &amp;lsquo;&lt;a href=&#34;https://en.wikipedia.org/wiki/Telstar&#34;&gt;Telstar&lt;/a&gt;&amp;rsquo; after the first communication satellite in space. In many ways, MQTT is like Telstar, in that it takes signals beamned to it and sends them right back out witout interacting with the payload.&lt;/p&gt;
&lt;h2 id=&#34;update-summer-2021&#34;&gt;Update Summer 2021&lt;/h2&gt;
&lt;p&gt;At this point, Telstar has been very reliable and collected data for over a year. As I start to transition from Telstar to Home Assistant, I continue to keep critical infrastructure in Telstar, including Mosquitto. I am not sure if I will ever completely migrate off Telstar, although it may be required when I eventually migrate off bare Ubuntu back to TrueNAS for the storage server. It&amp;rsquo;s extremely difficult to migrate years of data stored in Influx to a new naming convention, so I may have to backup the data and start fresh, and I&amp;rsquo;m not looking forward to that. I&amp;rsquo;ll update this page again if anything new happens with Telstar.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Simple Multi-Room Temperature Monitoring with Dallas One-Wire</title>
      <link>https://www.apalrd.net/projects/2019/onewire/</link>
      <pubDate>Sat, 26 Jan 2019 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2019/onewire/</guid>
      <description>This project is my entry into data collection at home. I learned a lot about what not to do, but I got a decent sensor network out of it, which continues to be (mostly) reliable to this day.
Dallas One-Wire Sensors See the Wikipedia Article on the subject for a brief overview. I started this project with the goal of proving that my bedroom (located on the southeast corner of the house) was notably colder in the winter than other rooms.</description>
      <content>&lt;p&gt;This project is my entry into data collection at home. I learned a lot about what not to do, but I got a decent sensor network out of it, which continues to be (mostly) reliable to this day.&lt;/p&gt;
&lt;h2 id=&#34;dallas-one-wire-sensors&#34;&gt;Dallas One-Wire Sensors&lt;/h2&gt;
&lt;p&gt;See the &lt;a href=&#34;https://en.wikipedia.org/wiki/1-Wire&#34;&gt;Wikipedia Article on the subject&lt;/a&gt; for a brief overview. I started this project with the goal of proving that my bedroom (located on the southeast corner of the house) was notably colder in the winter than other rooms. The Dallas DS18S20 one-wire sensors are super cheap (~$2 each from Digikey), the USB master isn&amp;rsquo;t crazy expensive, and they can deal with a star topology bus at decently short lengths using the Cat5 wire already in the walls. I just had to wire it all up.&lt;/p&gt;
&lt;p&gt;To wire the sensors to the existing RJ45 jacks, I bought a huge spool of low cost 4 conductor phone wire (flat, not twisted pair) and RJ11 phone jacks. Only the center pins (normally used for a single telephone line) are used in parasite power mode, with one pin for ground and one pin for power+data. I crimped the RJ11 to a 6&amp;quot; piece of phone wire and soldered the other end to the TO-92 sensor, heat shrinking the connectors. I plugged each one in to my LinkUSB connected to my Mac and listed the bus contents, labeling the sensor with the unique portion of its ID.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Orignal sensor using phone wire&#34; src=&#34;https://www.apalrd.net/projects/2019/onewire/sensor1.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;The First sensor model, carefully labeled with its unique address&lt;/div&gt;
&lt;p&gt;After making a few of these, I found the cheap stranded phone wire too difficult to strip and solder. It was fine to crimp to the RJ11&amp;rsquo;s, but soldering it was not fun. For the future, I pulled a single pair out of a Cat5e bundle (which contains 4 pairs), crimped the pair to the center pins of an RJ11, and soldered them to the TO-92 sensor. I didn&amp;rsquo;t take the time to label these, I watched the whole network to see which device was new each time I plugged one in.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Updated sensor with Cat5e twisted pair&#34; src=&#34;https://www.apalrd.net/projects/2019/onewire/sensor2.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;The Second sensor model, not labeled at all&lt;/div&gt;
&lt;h2 id=&#34;one-wire-bus-mastering&#34;&gt;One Wire Bus Mastering&lt;/h2&gt;
&lt;p&gt;To master the one-wire bus, I chose the &lt;a href=&#34;https://www.ibuttonlink.com/products/linkusb?_pos=2&amp;_sid=188165adb&amp;_ss=r&amp;variant=227160674&#34;&gt;iButtonLink LinkUSB&lt;/a&gt;. I initially bought one, and used it with my Macbook to identify sensors using &lt;a href=&#34;https://owfs.org/&#34;&gt;OWFS&lt;/a&gt;&amp;rsquo;s built in webserver mode. After getting the network setup, I moved it to my FreeNAS server. I created a jail in the FreeNAS server to host &lt;a href=&#34;https://emoncms.org/&#34;&gt;EmonCMS&lt;/a&gt;. I won&amp;rsquo;t go into detail on how to set this up, I&amp;rsquo;m not an expert on FreeNAS, FreeBSD, or jails. To publish data to EmonCMS from the one-wire bus, I installed owfs in the jail, passed the USB to serial adapter in the LinkUSB into the jail, and wrote a small program that launched as a daemon to read the bus using the one-wire C API and push the resulting data to EmonCMS via it&amp;rsquo;s HTTP endpoint. &lt;a href=&#34;https://github.com/apalrd/ow2emon&#34;&gt;The code is available on Github.&lt;/a&gt; As all Cat5 runs in the house are home-run to the patch panel, I made short phone cords and used cheap phone splitters to make up the 1-wire master splitter in the basement.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Splitter network&#34; src=&#34;https://www.apalrd.net/projects/2019/onewire/splitter.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Gray phone wiring is for the 1-wire network&lt;/div&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project (Updated 2021/09 with MAXIM replacement)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.digikey.com/en/products/detail/maxim-integrated/DS18B20-PAR/1197285&#34;&gt;Dallas DS1B20&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.digikey.com/en/products/detail/maxim-integrated/MAX31820MCR-T/4271349&#34;&gt;Maxim MAX31820&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ibuttonlink.com/products/linkusb?_pos=2&amp;_sid=188165adb&amp;_ss=r&amp;variant=227160674&#34;&gt;iButtonLink LinkUSB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apalrd/ow2emon&#34;&gt;Source Code on Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;summer-2020-update&#34;&gt;Summer 2020 Update&lt;/h2&gt;
&lt;p&gt;As of Summer 2020, the FreeNAS server was replaced with bare Linux (Ubuntu 18.04 Bionic), and the EmonCMS jail was replaced with an LXC container running Node-Red. The LinkUSB was moved to a nearby Raspberry Pi, which hosts an owserver which is polled by Node-Red periodically to push data to InfluxDB for visualization in Grafana (&lt;a href=&#34;https://www.apalrd.net/projects/2020/first_automation/&#34;&gt;Project Here&lt;/a&gt;). The network has been expanded to include the garage and an outdoor sensor, and a second LinkUSB to split the network in half due to the wiring length and difficulty reading some sensors with so many splits.&lt;/p&gt;
&lt;h2 id=&#34;summer-2021-update&#34;&gt;Summer 2021 Update&lt;/h2&gt;
&lt;p&gt;As of Summer 2021, the original automation sustem project is being slowly migrated to Home Assistant. The owserver is still in use and is being polled by both Node-Red and Home Assistant at this time. The outdoor sensor failed due to corrosion of the wires where the heat shrink meets the TO-92 package, in the future outdoor sensors should be hot glued or potted for better protection. No indoor sensors have failed yet.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>2018 SAE Clean Snowmobile Challenge</title>
      <link>https://www.apalrd.net/projects/2018/cleansnow/</link>
      <pubDate>Mon, 12 Mar 2018 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2018/cleansnow/</guid>
      <description>The 2018 SAE Clean Snowmobile Challenge was the final collegiate event in which I competed, as I graduated several days after returning and started working full-time. For the 2018 Challenge, Kettering brought two vehicles - one competing in the &amp;lsquo;Internal Combustion&amp;rsquo; class and one in the &amp;lsquo;Diesel Utility&amp;rsquo; class. The Diesel vehicle was based on an improved version of my 2017 Diesel Control Capstone using the Mercedes OM660 &amp;lsquo;Smart CDI&amp;rsquo; engine, and a Ski-Doo Tundra chassis.</description>
      <content>&lt;p&gt;The 2018 SAE Clean Snowmobile Challenge was the final collegiate event in which I competed, as I graduated several days after returning and started working full-time. For the 2018 Challenge, Kettering brought two vehicles - one competing in the &amp;lsquo;Internal Combustion&amp;rsquo; class and one in the &amp;lsquo;Diesel Utility&amp;rsquo; class. The Diesel vehicle was based on an improved version of my &lt;a href=&#34;https://www.apalrd.net/projects/2017/csc17crd/&#34;&gt;2017 Diesel Control Capstone&lt;/a&gt; using the Mercedes OM660 &amp;lsquo;Smart CDI&amp;rsquo; engine, and a Ski-Doo Tundra chassis. The IC (Spark Ignition) vehicle was based on a Rotax 600 ACE engine, naturally aspirated, with a custom control system.&lt;/p&gt;
&lt;p&gt;These design papers and presentations were previously published by the competition, however, they are archived here for reference.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2018/cleansnow/2018Diesel_RevE.pdf&#34;&gt;Design Paper - 2018 Kettering Diesel&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2018/cleansnow/2018ACE_RevE.pdf&#34;&gt;Design Paper - 2018 Kettering Gas&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2018/cleansnow/CSC_Diesel_RevB.pdf&#34;&gt;Design Presentation - 2018 Kettering Diesel&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2018/cleansnow/CSC_Gas_RevA.pdf&#34;&gt;Design Presentation - 2018 Kettering Gas&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Undergraduate Capstone - Common Rail Diesel Control System</title>
      <link>https://www.apalrd.net/projects/2017/csc17crd/</link>
      <pubDate>Sat, 16 Dec 2017 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2017/csc17crd/</guid>
      <description>My 2017 student capstone was done as an indepdent study project sponsored by Dr. Greg Davis, to implement an engine control system for a Common Rail Diesel engine for the 2017 SAE Clean Snowmobile Challenge. Kettering&amp;rsquo;s culminating undegratuate experience is not the capstone, but rather the undergraduate thesis. My undergraduate thesis was company sponsored and restricted due to trade secrets, but my capstone can be published here. To archive the data for future use, I have published it here.</description>
      <content>&lt;p&gt;My 2017 student capstone was done as an indepdent study project sponsored by Dr. Greg Davis, to implement an engine control system for a Common Rail Diesel engine for the 2017 SAE Clean Snowmobile Challenge. Kettering&amp;rsquo;s culminating undegratuate experience is not the capstone, but rather the undergraduate thesis. My undergraduate thesis was company sponsored and restricted due to trade secrets, but my capstone can be published here. To archive the data for future use, I have published it here. As part of my agreement to do an independent study capstone, I produced a written report and oral presentation. The presentation was not designed to be read, but rather performed, and as such some information is not included. The written report contains more thorough information.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2017/csc17crd/CE499_Report_RevD.pdf&#34;&gt;Capstone Paper&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2017/csc17crd/CE490_Pres_RevE.pdf&#34;&gt;Capstone Presentation&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Controlling an Engineered Septic Pump with a PLC</title>
      <link>https://www.apalrd.net/projects/2016/septic_plc/</link>
      <pubDate>Mon, 28 Nov 2016 12:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/projects/2016/septic_plc/</guid>
      <description>While visiting my parents shortly before Thanksgiving weekend, the septic pump stopped working, resulting in a very slight ingress of fluid through the basement drain. My parents have an engineered septic system which unfortunately required the leach field to be located at a higher elevation than the septic tank behind the house. As we all know, shit flows down hill, and a pump is required to make it flow up hill.</description>
      <content>&lt;p&gt;While visiting my parents shortly before Thanksgiving weekend, the septic pump stopped working, resulting in a very slight ingress of fluid through the basement drain. My parents have an engineered septic system which unfortunately required the leach field to be located at a higher elevation than the septic tank behind the house. As we all know, shit flows down hill, and a pump is required to make it flow up hill. Due to a comedy of electrical engineering errors, not only did this pump fail, but the monitoring system purpose built and sold to sound an alarm also failed to sound. In this project, I remedy the poor failure modes of the previous system by using a programmable logic controller to control and monitor the septic pump.&lt;/p&gt;
&lt;h2 id=&#34;system-design&#34;&gt;System Design&lt;/h2&gt;
&lt;p&gt;The system consists of primarily a pump and three float switches located in a dedicated pump tank. The highest float switch sounds the alarm, indicating that the level in the tank is higher than it should be. The middle float turns on the pump, latching the pump on. The lower float turns off the pump, latching the pump off. This causes the pump to evacuate roughly half of the volume of the tank, the span between the middle and lower float, at a frequency of approximately once per week.&lt;/p&gt;
&lt;h2 id=&#34;the-failed-alarm&#34;&gt;The Failed Alarm&lt;/h2&gt;
&lt;p&gt;The original control system was very primitavely wired. The main control of the pump was via a dual latching float, in which the latching relay was contained within one of the float switches. A 240V circuit dedicated to the pump was run out to the tank, and the float switches and pump were wired in a junction box next to the tank. This functioned perfectly adequately.&lt;/p&gt;
&lt;p&gt;The original alarm system was also very primitivaly wired. The alarm was fed by a separate 120V circuit, so any electrical faults in the pump circuit would not cause a silent alarm failure. However, the alarm used a 120V float switch protected by the same fuse which protected the sounder, so any electrical fault in the alarm circuit &lt;strong&gt;would&lt;/strong&gt; cause a silent alarm failure, blowing the fuse for the entire alarm system. In addition, the alarm float was normally open, so any electrical fault resulting an open circuit would also result in a silent alarm failure. Clearly, the designers of this commercially built septic alarm did not really consider any failure modes.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Original alarm board&#34; src=&#34;https://www.apalrd.net/projects/2016/septic_plc/oldalarm.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Original Alarm PCB&lt;/div&gt;
&lt;h2 id=&#34;design-requirements&#34;&gt;Design Requirements&lt;/h2&gt;
&lt;p&gt;The new design replaces the mix of line voltage and latching float switches with three identical low voltage dual-contact switches, which have both a normally open (NO) and normally closed (NC) output, along with a programmable logic controller implementing a fairly simple program to validate the inputs and detect failures.&lt;/p&gt;
&lt;p&gt;The following failure modes were considered in the design:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Failure of power to the pump circuit due to a tripped circuit breaker&lt;/li&gt;
&lt;li&gt;Failure of the pump itself or the wiring leading up to it&lt;/li&gt;
&lt;li&gt;Open-circuit failure of any float switch wire including the common&lt;/li&gt;
&lt;li&gt;Short-circuit failure of any float switch wire to the common&lt;/li&gt;
&lt;li&gt;Failure of the PLC to load and execute the program&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The failure of power to the PLC is not detectable, as the alarm sounder requires 120V power to operate. However, the PLC is fed by a basement lighting circuit, so the chance of a tripped breaker being undetected is low.&lt;/p&gt;
&lt;p&gt;Due to the minimal IO requirements, an Automation Direct Click PLC was selected, and the IO integrated with the PLC was sufficient to implement the entire project without any expansion modules. For ease of programming and monitoring, I splurged for an Ethernet model.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Parts arrive and are sorted&#34; src=&#34;https://www.apalrd.net/projects/2016/septic_plc/parts.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Parts Arrive&lt;/div&gt;
&lt;h2 id=&#34;the-design&#34;&gt;The Design&lt;/h2&gt;
&lt;p&gt;The new design is implemented in a control box containing the PLC, a 24VDC power supply for the logic, 24VDC double pole pump relay, 240VAC pump power detection relay, and 24VDC alarm relay. The alarm consists of a 120VAC sounder, 120VAC red &amp;lsquo;hard fault&amp;rsquo; lamp, 24VDC &amp;lsquo;soft fault&amp;rsquo; lamp, and a 3-position AUTO/OFF/ON switch for the pump.&lt;/p&gt;
&lt;p&gt;The PLC is powered via the 24VDC supply. The three float switches are connected to the 24VDC return, so a short of any pump wiring will not short the 24DC supply. As the float switches have both a NO and NC contact, the PLC reads each contact separately. The PLC also reads the reset pushbutton and 240VAC pump power detection via a relay, and outputs the pump enable signal, orange soft fault lamp, and a logically inverted output to the 120VAC alarm relay which activates the red hard fault lamp and the sounder. As the alarm relay is logically inverted, the PLC must load and execute the program and activate the alarm output to turn the alarm off, resulting in an alarm activation if there is any PLC failure.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Laying out the parts before mounting in the box&#34; src=&#34;https://www.apalrd.net/projects/2016/septic_plc/layout.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Layout of the parts before mounting&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Mounting parts on the DIN rail in the box&#34; src=&#34;https://www.apalrd.net/projects/2016/septic_plc/mounting.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Mounting the parts on the DIN rail&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Testing the wired box on the bench&#34; src=&#34;https://www.apalrd.net/projects/2016/septic_plc/wiring.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Wiring and Software Testing on the bench&lt;/div&gt;
&lt;h2 id=&#34;the-logic&#34;&gt;The Logic&lt;/h2&gt;
&lt;p&gt;As the PLC reads both an NO and NC contact for each float switch, the logic first determines if any of the float switches are activated based on the status of either the NO or NC contact indicating activation. The logic also determines if any float switches are split (reading of the NO and NC contact disagree), triggering a soft fault.&lt;/p&gt;
&lt;p&gt;The pump is toggled on when the ON float is triggered, and OFF when the OFF float trigger is released. Failure of pump power triggers a soft fault, but failure of pump power when the pump is commanded on triggers a hard fault. In addition, the pump being active for more than 15 minutes triggers a hard fault.&lt;/p&gt;
&lt;p&gt;The activation of the alarm float triggers a hard fault and additionally turns the pump on as long as the float remains triggered.&lt;/p&gt;
&lt;p&gt;Soft faults automatically clear the soft fault lamp when the fault condition clears. Hard faults latch and the alarm remains active until reset by pushing the reset button. If the condition has not cleared, the alarm will not reset.&lt;/p&gt;
&lt;p&gt;The PLC program is available at the bottom of this page&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Cat watching me program&#34; src=&#34;https://www.apalrd.net/projects/2016/septic_plc/supervisor.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Programming monitored by the lead supervisor&lt;/div&gt;
&lt;h2 id=&#34;the-finished-proeuct&#34;&gt;The Finished Proeuct&lt;/h2&gt;
&lt;p&gt;The PLC was installed on the basement wall where the conduit leading to the tank enters the house. The system was tested using a pole with a hook to raise each float switch, and additionally by monitoring the performance of the system for the first pumping cycle. Logic was confirmed to work correctly.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Mounted and wired PLC enclosure&#34; src=&#34;https://www.apalrd.net/projects/2016/septic_plc/finished.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;Mounted and Wired PLC Enclosure&lt;/div&gt;
&lt;p&gt;&lt;img alt=&#34;Enclosure closed and labeled fully&#34; src=&#34;https://www.apalrd.net/projects/2016/septic_plc/labeled.jpg&#34;&gt;&lt;/p&gt;
&lt;div style=&#34;text-align: center;&#34;&gt;I definitely did not wait 2 whole years to label the enclosure properly&lt;/div&gt;
&lt;h2 id=&#34;update-winter-2019&#34;&gt;Update Winter 2019&lt;/h2&gt;
&lt;p&gt;As the PLC provides data access via Modbus TCP, I wrote a small program to capture the relevant control signals and log them in EmonCMS (the same system used by &lt;a href=&#34;https://www.apalrd.net/projects/2019/onewire/&#34;&gt;OneWire&lt;/a&gt;). plc2emon is the program, Github link below. PLC has had no issues yet.&lt;/p&gt;
&lt;h2 id=&#34;update-summer-2020&#34;&gt;Update Summer 2020&lt;/h2&gt;
&lt;p&gt;As I switched away from EmonCMS to &lt;a href=&#34;https://www.apalrd.net/projects/2020/first_automation/&#34;&gt;Telstar&lt;/a&gt;, I wrote a Node-Red flow to capture the same data via Modbus TCP and push it to MQTT for logging. The node-red flow is linked below. Again, the PLC has had no issues still.&lt;/p&gt;
&lt;h2 id=&#34;the-project-files-and-parts-list&#34;&gt;The Project Files and Parts List&lt;/h2&gt;
&lt;p&gt;Here are all of the files and parts required to replicate this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.automationdirect.com/adc/shopping/catalog/programmable_controllers/click_series_plcs/click_plcs_(stackable_micro_brick)/plc_units/c0-10dd1e-d&#34;&gt;CLICK PLC - Ethernet Basic, 8 DC Input, 6 DC Sinking Output&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.automationdirect.com/adc/shopping/catalog/process_control_-a-_measurement/level_sensors_-a-_controllers/float_level_switches/fls-ht-100&#34;&gt;Float Switch, SPDT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2016/septic_plc/SepticPLC_RvA.ckp&#34;&gt;Program File for CLICK Software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apalrd/plc2emon&#34;&gt;plc2emon program used for monitoring (OUTDATED)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2016/septic_plc/septic_flow.json&#34;&gt;Node-Red flow used for monitoring&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title></title>
      <link>https://www.apalrd.net/posts/2022/pi_ups/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2022/pi_ups/</guid>
      <description>Waveshare UPS board:</description>
      <content>&lt;p&gt;Waveshare UPS board:&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title></title>
      <link>https://www.apalrd.net/posts/2023/cluster_case/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/cluster_case/</guid>
      <description>FIX LIST
Holes for fan screws need to accept the self-threaded screws that the fans come with (TBD size) and there is very little marging on them Fan bracket should be stiffened somehow behind the big open hole </description>
      <content>&lt;p&gt;FIX LIST&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Holes for fan screws need to accept the self-threaded screws that the fans come with (TBD size) and there is very little marging on them&lt;/li&gt;
&lt;li&gt;Fan bracket should be stiffened somehow behind the big open hole&lt;/li&gt;
&lt;/ol&gt;
</content>
    </item>
    
    <item>
      <title></title>
      <link>https://www.apalrd.net/posts/2023/net_sonic/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2023/net_sonic/</guid>
      <description>wget &amp;#34;https://sonic-build.azurewebsites.net/api/sonic/artifacts?branchName=master&amp;amp;platform=vs&amp;amp;target=target%2Fsonic-vs.img.gz mv *.img.gz sonic-vs.img.gz gzip -d -v sonic-vs.img.gz qm create 534 --name &amp;#34;sonic&amp;#34; --ostype l26 qm set 534 --net0 virtio,bridge=vmbr0 qm set 534 --serial0 socket --vga serial0 qm set 534 --memory 2048 --cores 4 --cpu host qm set 534 --scsi0 local-zfs:0,import-from=&amp;#34;/root/sonic-vs.img&amp;#34;,discard=on qm set 534 --boot order=scsi0 --scsihw virtio-scsi-single </description>
      <content>&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://sonic-build.azurewebsites.net/api/sonic/artifacts?branchName=master&amp;amp;platform=vs&amp;amp;target=target%2Fsonic-vs.img.gz
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;mv *.img.gz sonic-vs.img.gz
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;gzip -d -v sonic-vs.img.gz
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;qm create 534 --name &amp;#34;&lt;/span&gt;sonic&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; --ostype l26
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;qm set 534 --net0 virtio,bridge=vmbr0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;qm set 534 --serial0 socket --vga serial0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;qm set 534 --memory 2048 --cores 4 --cpu host
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;qm set 534 --scsi0 local-zfs:0,import-from=&amp;#34;&lt;/span&gt;/root/sonic-vs.img&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;,discard=on
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;qm set 534 --boot order=scsi0 --scsihw virtio-scsi-single
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title></title>
      <link>https://www.apalrd.net/posts/2024/network_v6cost/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2024/network_v6cost/</guid>
      <description>How much does it cost to not transition to v6?</description>
      <content>&lt;p&gt;How much does it cost to not transition to v6?&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title></title>
      <link>https://www.apalrd.net/posts/2025/ultimate_gns3/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/posts/2025/ultimate_gns3/</guid>
      <description>Import GNS3 VM into PVE:
Start from VMWare ESXI image (ova / zip) Copy to a location on the Proxmox system (i.e. a network share or /root) cd to the directory the ova is in # Extract zip it came in unzip GNS3*.zip # Resulting file in my case was called `GNS3 VM.ova&amp;#39; (with a space in the name!) # Extract OVA (this is itself a zip) tar -xvf &amp;#39;GNS3 VM.</description>
      <content>&lt;p&gt;Import GNS3 VM into PVE:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start from VMWare ESXI image (ova / zip)&lt;/li&gt;
&lt;li&gt;Copy to a location on the Proxmox system (i.e. a network share or /root)&lt;/li&gt;
&lt;li&gt;cd to the directory the ova is in&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Extract zip it came in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;unzip GNS3*.zip
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Resulting file in my case was called `GNS3 VM.ova&amp;#39; (with a space in the name!)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Extract OVA (this is itself a zip)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar -xvf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;GNS3 VM.ova&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Import to VM ID 590 in Proxmox (just an example)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qm importovf &lt;span style=&#34;color:#ae81ff&#34;&gt;590&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GNS3 VM.ovf&amp;#34;&lt;/span&gt; local-zfs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>404 Error</title>
      <link>https://www.apalrd.net/error/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/error/</guid>
      <description>Oops! Looks like you&amp;rsquo;ve gotten somewhere you shouldn&amp;rsquo;t. That&amp;rsquo;s okay. No big deal. Maybe head back to the home page and try again?</description>
      <content>&lt;h1 id=&#34;oops-looks-like-youve-gotten-somewhere-you-shouldnt&#34;&gt;Oops! Looks like you&amp;rsquo;ve gotten somewhere you shouldn&amp;rsquo;t.&lt;/h1&gt;
&lt;p&gt;That&amp;rsquo;s okay. No big deal.
&lt;a href=&#34;https://www.apalrd.net/&#34;&gt;Maybe head back to the home page and try again?&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>About</title>
      <link>https://www.apalrd.net/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/about/</guid>
      <description>About Me I&amp;rsquo;m a software developer starting on a new web adventure. I enjoy tinkering and making, and hope to document as many of my past and future projects as possible on this site.</description>
      <content>&lt;h1 id=&#34;about-me&#34;&gt;About Me&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;m a software developer starting on a new web adventure. I enjoy tinkering and making, and hope to document as many of my past and future projects as possible on this site.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Resume</title>
      <link>https://www.apalrd.net/resume/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/resume/</guid>
      <description>Work Experience Williams International Employment: 2015-2017 (Co-Op), 2018-2021
Software Development for airborne engine control algorithms to RTCA/DO-178C DAL-A standards including FAA software certification from process development through final validation testing and type approval Developed software methodology for model-based future airbore engine control application to RTCA/DO-178C DAL A standards incorporating DO-331 guidance based on ANSYS SCADE high-integrity model based design suite Developed software platform for new microcontroller family, including build environment, toolchain (GCC) and startup assembly code, and successfully launched the software platform on a production product Developed real-time electric motor control software for brushless DC motors Assisted with full-authority digital engine control (FADEC) hardware design, with a focus on microcontroller and FPGA integration circuitry and electromagnetic compatibility, including lightning induced transient susceptibility Developed production test equipment for FADEC, utilizing NI LabVIEW and TestStand Performed DO-160 electromagnetic compatibility and lightning induced transient testing of airborne electronic components for FAA certification Chrysler Employment: 2012-2015 (Co-Op)</description>
      <content>&lt;h1 id=&#34;work-experience&#34;&gt;Work Experience&lt;/h1&gt;
&lt;h3 id=&#34;williams-international&#34;&gt;Williams International&lt;/h3&gt;
&lt;p&gt;Employment: 2015-2017 (Co-Op), 2018-2021&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Software Development for airborne engine control algorithms to RTCA/DO-178C DAL-A standards including FAA software certification from process development through final validation testing and type approval&lt;/li&gt;
&lt;li&gt;Developed software methodology for model-based future airbore engine control application to RTCA/DO-178C DAL A standards incorporating DO-331 guidance based on ANSYS SCADE high-integrity model based design suite&lt;/li&gt;
&lt;li&gt;Developed software platform for new microcontroller family, including build environment, toolchain (GCC) and startup assembly code, and successfully launched the software platform on a production product&lt;/li&gt;
&lt;li&gt;Developed real-time electric motor control software for brushless DC motors&lt;/li&gt;
&lt;li&gt;Assisted with full-authority digital engine control (FADEC) hardware design, with a focus on microcontroller and FPGA integration circuitry and electromagnetic compatibility, including lightning induced transient susceptibility&lt;/li&gt;
&lt;li&gt;Developed production test equipment for FADEC, utilizing NI LabVIEW and TestStand&lt;/li&gt;
&lt;li&gt;Performed DO-160 electromagnetic compatibility and lightning induced transient testing of airborne electronic components for FAA certification&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;chrysler&#34;&gt;Chrysler&lt;/h3&gt;
&lt;p&gt;Employment: 2012-2015 (Co-Op)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Powertrain Controls Co-Op&lt;/li&gt;
&lt;li&gt;Calibration of Gasoline and Diesel engines using ETAS INCA&lt;/li&gt;
&lt;li&gt;Powertrain control system development using Mathworks Simulink&lt;/li&gt;
&lt;li&gt;In-depth knowledge of engine combustion, air control, and torque control systems&lt;/li&gt;
&lt;li&gt;Embedded C programming, including low-level software development&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;pi-shurlok&#34;&gt;Pi Shurlok&lt;/h3&gt;
&lt;p&gt;Employment: 2011 (Intern)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Systems Engineer Intern&lt;/li&gt;
&lt;li&gt;Assisted on brake control project (ABS/TCS/ESC), including Simulink&lt;/li&gt;
&lt;li&gt;Maintained ABS/TCS/ESC hydraulic test buck and performed software testing using test buck&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;professional-and-student-activities&#34;&gt;Professional and Student Activities&lt;/h1&gt;
&lt;h3 id=&#34;kettering-university-formula-sae-fsae&#34;&gt;Kettering University Formula SAE (FSAE)&lt;/h3&gt;
&lt;p&gt;Student: 2013-2017 Seasons&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Powertrain system lead 2015-2017&lt;/li&gt;
&lt;li&gt;Electrical system lead 2016-2017&lt;/li&gt;
&lt;li&gt;Engine control system software development in Mathworks Simulink - Developed control models for rapid-prototype ECU from first principles&lt;/li&gt;
&lt;li&gt;Engine calibrator including electronic throttle control using ATI VISION&lt;/li&gt;
&lt;li&gt;Winner 1st place Fuel Efficiency (2013 2x, 2014)&lt;/li&gt;
&lt;li&gt;Top 10 overall finish (2013, 2014)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;kettering-university-sae-clean-snowmobile-challenge-csc&#34;&gt;Kettering University SAE Clean Snowmobile Challenge (CSC)&lt;/h3&gt;
&lt;p&gt;Student: 2013-2018 Seasons&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Powertrain system lead 2015-2018&lt;/li&gt;
&lt;li&gt;Diesel advanced development lead 2016-2018&lt;/li&gt;
&lt;li&gt;Engine control system software development for both gasoline and Diesel engines in Mathworks Simulink - Developed 3 complete control models for rapid-prototype ECU from first principles&lt;/li&gt;
&lt;li&gt;Engine calibrator for gasoline engines, including lean low-NOx combustion strategies and fuel-based toqrue management with electronic throttle control&lt;/li&gt;
&lt;li&gt;Engine calibrator for Diesel Common Rail engines, including combustion, torque, and emissions strategies (&lt;a href=&#34;https://www.apalrd.net/projects/2017/csc17crd/&#34;&gt;Link to Design Materials&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Engine calibration using ATI VISION&lt;/li&gt;
&lt;li&gt;Winner Spark Ignited class (2014, 2018)&lt;/li&gt;
&lt;li&gt;Second Place Spark Ignited class (2013, 2015)&lt;/li&gt;
&lt;li&gt;Second Place Compression Ignition class (2018)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.apalrd.net/projects/2018/cleansnow/&#34;&gt;Link to 2018 Design Presentations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;first-robotics-competition-frc&#34;&gt;FIRST Robotics Competition (FRC)&lt;/h3&gt;
&lt;p&gt;Student: 2009-2012 Seasons
&lt;br&gt;
Team #33, The Killer Bees&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lead Programmer (2010-2012)&lt;/li&gt;
&lt;li&gt;Driver (2012)&lt;/li&gt;
&lt;li&gt;Developed team&amp;rsquo;s code in LabVIEW Real-Time&lt;/li&gt;
&lt;li&gt;2010 and 2011 Most Valuable Player awards&lt;/li&gt;
&lt;li&gt;2012 Senior Excellence award&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;skills&#34;&gt;Skills&lt;/h1&gt;
&lt;h3 id=&#34;general-computer-skills&#34;&gt;General Computer Skills&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Proficient in Microsoft Office applications and equivalents&lt;/li&gt;
&lt;li&gt;Proficient in Unix-like (Linux, macOS, BSD) terminal and system management&lt;/li&gt;
&lt;li&gt;Proficient in version control system usage including Git and Subversion&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;programming&#34;&gt;Programming&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Proficient in C programming, with a focus on embedded systems programming&lt;/li&gt;
&lt;li&gt;Proficient in LabVIEW programming, including LabVIEW Real-Time, LabVIEW FPGA, and NI TestStand&lt;/li&gt;
&lt;li&gt;Proficient in Mathworks MATLAB and Simulink programming, with a focus on embedded controls development (Simulink Coder/Embedded Coder) and co-simulation of control and plant (Simscape)&lt;/li&gt;
&lt;li&gt;Experience in C++, Python, Javascript, Ada, Make, and FORTRAN programming&lt;/li&gt;
&lt;li&gt;Experience in VHDL complex electronic hardware design&lt;/li&gt;
&lt;li&gt;Proficient in assembly for PowerPC, ARM 32-bit, MIPS 32-bit, 68K&lt;/li&gt;
&lt;li&gt;Experience in assembly for HCS12, x86/x64&lt;/li&gt;
&lt;li&gt;Proficient with GNU Compiler Collection (GCC) for Linux/Unix and embedded applications&lt;/li&gt;
&lt;li&gt;Proficient in NXP eTPU peripheral programming&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;specialized-software&#34;&gt;Specialized Software&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Proficient in Lauterbach Trace32 Debugger for embedded systems, including PowerTrace program flow tracing and measurement functions and PRACTICE automation scripting language&lt;/li&gt;
&lt;li&gt;Experience in IDA Interactive Disassembler for binary analysis&lt;/li&gt;
&lt;li&gt;Proficient in ETAS INCA for embedded systems calibration&lt;/li&gt;
&lt;li&gt;Proficient in ATI VISION for embedded systems calibration&lt;/li&gt;
&lt;li&gt;Experience in Vector CANape for embedded systems calibration&lt;/li&gt;
&lt;li&gt;Proficient in ANSYS / Estrel Technologies SCADE for high-integrity embedded systems model based design, including code generation and DO-178C compliance&lt;/li&gt;
&lt;li&gt;Proficient in IBM Rational DOORS object-oriented requirements management system&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;professional-standards&#34;&gt;Professional Standards&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Proficient in RTCA/DO-187C Software Considerations in Airborne Systems and Equipment Certification&lt;/li&gt;
&lt;li&gt;Experience in RTCA/DO-254 Design Assurance Guidance for Airborne Electronic Hardware&lt;/li&gt;
&lt;li&gt;Proficient in RTCA/DO-330 Software Tool Qualification Considerations&lt;/li&gt;
&lt;li&gt;Proficient in RTCA/DO-331 Model Based Development and Verification Supplement to DO-178C and DO-278A&lt;/li&gt;
&lt;li&gt;Proficient in RTCA/DO-160 Environmental Conditions and Test Procedures for Airborne Electronic/Electrical Equipment and Instruments - Sections covering electromagnetic compatibility and lightning induced transients only&lt;/li&gt;
&lt;li&gt;Experience in 40 CFR § 1065 Engine Emissions Testing Procedures&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;education&#34;&gt;Education&lt;/h1&gt;
&lt;h3 id=&#34;kettering-university&#34;&gt;Kettering University&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Graduated 2018&lt;/li&gt;
&lt;li&gt;BSCE - Computer Engineering&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;notre-dame-preparatory-high-school&#34;&gt;Notre Dame Preparatory High School&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Graduated 2012&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;volunteering&#34;&gt;Volunteering&lt;/h1&gt;
&lt;h3 id=&#34;vex-robotics&#34;&gt;VEX Robotics&lt;/h3&gt;
&lt;p&gt;Mentor: 2016-Present
&lt;br&gt;
Event Partner: 2015-Present&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Taught programming skills to elementary through high school aged students using Python, C, and Scratch-like visual programming environments&lt;/li&gt;
&lt;li&gt;Provided strategic guideance and driving skills training to students&lt;/li&gt;
&lt;li&gt;Managed tournament computer timing and scorekeeping systems for VEX IQ Michigan State Championship (2017, 2018), as well as many local level competitions for both VEX IQ Challenge and VEX Robotics Competition&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;first-robotics&#34;&gt;FIRST Robotics&lt;/h3&gt;
&lt;p&gt;Assistant: 2013-2014
&lt;br&gt;
Mentor: 2018-2019&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Taught programming skills to high school aged students using LabVIEW Real-Time&lt;/li&gt;
&lt;li&gt;Managed student development team, including code review and design assistance&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>What Is My IP?</title>
      <link>https://www.apalrd.net/myip/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/myip/</guid>
      <description>This page will do a bunch of queries to my backend (and no third-party services!) to identify how you are connected to my site and my content delivery network.
Progress Bar Goes Here Your IP Address This queries my backend via an ipv4-only and ipv6-only DNS record, on both the standard (80, 443) and nonstandard (42069) ports, to identify what your public IP address is, and if your (CG)NAT is utilizing different routing for non-standard ports.</description>
      <content>&lt;p&gt;This page will do a bunch of queries to my backend (and no third-party services!) to identify how you are connected to my site and my content delivery network.&lt;/p&gt;
&lt;div id=&#34;progress&#34;&gt;Progress Bar Goes Here&lt;/div&gt;
&lt;h1 id=&#34;your-ip-address&#34;&gt;Your IP Address&lt;/h1&gt;
&lt;p&gt;This queries my backend via an ipv4-only and ipv6-only DNS record, on both the standard (80, 443) and nonstandard (42069) ports, to identify what your public IP address is, and if your (CG)NAT is utilizing different routing for non-standard ports. Some mobile ISPs do dirty tricks with your web traffic, so if these are different, your ISP may be doing something shady.&lt;/p&gt;
&lt;p&gt;This doesn&amp;rsquo;t mean your ISP is definitely doing something shady, and your ISP could still be doing something shady if these match, this is just an indicator.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Port&lt;/th&gt;
&lt;th&gt;IPv6&lt;/th&gt;
&lt;th&gt;IPv4&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;443&lt;/td&gt;
&lt;td&gt;&lt;div id=&#34;ip6-norm&#34;&gt;Loading&amp;hellip;&lt;/div&gt;&lt;/td&gt;
&lt;td&gt;&lt;div id=&#34;ip4-norm&#34;&gt;Loading&amp;hellip;&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;42069&lt;/td&gt;
&lt;td&gt;&lt;div id=&#34;ip6-alt&#34;&gt;Loading&amp;hellip;&lt;/div&gt;&lt;/td&gt;
&lt;td&gt;&lt;div id=&#34;ip4-alt&#34;&gt;Loading&amp;hellip;&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id=&#34;content-delivery-network&#34;&gt;Content Delivery Network&lt;/h1&gt;
&lt;p&gt;Since I&amp;rsquo;m playing with traffic engineering on my CDN, here are some metrics on which CDN endpoint you have reached, and the round-trip time you see, using different traffic engineering methods.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;Latency (ms)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DNS&lt;/td&gt;
&lt;td&gt;&lt;div id=&#34;dns-host&#34;&gt;Loading&amp;hellip;&lt;/div&gt;&lt;/td&gt;
&lt;td&gt;&lt;div id=&#34;dns-latency&#34;&gt;Loading&amp;hellip;&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BGP&lt;/td&gt;
&lt;td&gt;&lt;div id=&#34;bgp-host&#34;&gt;Loading&amp;hellip;&lt;/div&gt;&lt;/td&gt;
&lt;td&gt;&lt;div id=&#34;bgp-latency&#34;&gt;Loading&amp;hellip;&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id=&#34;dns-query-information&#34;&gt;DNS Query Information&lt;/h1&gt;
&lt;p&gt;The following block is loaded from my DNS server, which provides information on your DNS query.&lt;/p&gt;
&lt;pre&gt;&lt;div id=&#34;geodns&#34;&gt;Loading...&lt;/div&gt;&lt;/pre&gt;
&lt;script&gt;
//Function to measure RTT to the ping endpoints and compare them
async function queryRTT(id,samples,endpoint) {
  console.log(&#34;New RTT Request for &#34;+endpoint);
  //Warm-up request
  await fetch(endpoint, { cache: &#39;no-store&#39; });
  updateProgressBar(1)

  //Subsequent requests
  let total = 0;
  for (let i = 0; i &lt; samples; i++) {
    const start = performance.now();
    try {
      // Send a fetch request  with cache disabled
      await fetch(endpoint, { cache: &#39;no-store&#39; });
      const end = performance.now();
      total += (end - start);
      updateProgressBar(1)
    } catch (err) {
      console.error(&#39;Fetch error:&#39;, err);
      document.getElementById(id).textContent = &#39;Error measuring RTT&#39;;
      updateProgressBar(1)
      return;
    }
  }
  const resultEl = document.getElementById(id);
  const avgRTT = total / samples;
  resultEl.textContent = `${avgRTT.toFixed(2)}`;
  updateProgressBar(1)
}

// Function to load remote text
function queryText(id,endpoint) {
  /* Make an HTTP request and fill in the div tag with this value */
  console.log(&#34;New HTTP Request for &#34;+endpoint);
  xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4) {
      const resultEl = document.getElementById(id);
      console.log(&#34;Got result for &#34;+endpoint+&#34; status &#34;+this.status+&#34; type &#34;+this.responseType+&#34; res [&#34;+this.response+&#34;]&#34;);
      if (this.status == 200) {
        resultEl.innerHTML = this.response;
      } else if (this.status == 404) {
        resultEl.textContent = &#34;Page not found.&#34;;
      } else {
        resultEl.textContent = &#34;Unknown error code &#34;+this.status;
      }
      updateProgressBar(1)
    }
  }
  xhttp.open(&#34;GET&#34;, endpoint, true);
  xhttp.send();
}
//function to update the progress bar with a bigger dick
function updateProgressBar(segs) {
  const progBar = document.getElementById(&#34;progress&#34;);
  //update global progress
  window.progress += segs
  progBar.textContent = &#34;8&#34;+&#34;=&#34;.repeat(window.progress)+&#34;o&#34;;

  //when we reach the end (all bar elements have loaded), submit the data
  console.log(&#34;Progress bar is at: &#34;+window.progress)

  if (window.progress &gt;= 52) {
    dns_host = document.getElementById(&#34;dns-host&#34;).textContent;
    bgp_host = document.getElementById(&#34;bgp-host&#34;).textContent;
    dns_latency = document.getElementById(&#34;dns-latency&#34;).textContent;
    bgp_latency = document.getElementById(&#34;bgp-latency&#34;).textContent;
    const data = new URLSearchParams({ dns_host, dns_latency,bgp_host, bgp_latency});

    fetch(&#34;https://geo.apalrd.net/stats&#34;, {
      method: &#34;POST&#34;,
      body: data,
    });
  }
}

// call all the populate functions
var progress = 0
updateProgressBar(0)
queryText(&#34;ip6-norm&#34;,&#34;https://ip6.apalrd.net/&#34;);
queryText(&#34;ip6-alt&#34;,&#34;https://ip6.apalrd.net:42069/&#34;);
queryText(&#34;ip4-norm&#34;,&#34;https://ip4.apalrd.net/&#34;);
queryText(&#34;ip4-alt&#34;,&#34;https://ip4.apalrd.net:42069/&#34;);
queryText(&#34;dns-host&#34;,&#34;https://geo.apalrd.net/host&#34;);
queryText(&#34;bgp-host&#34;,&#34;https://any.apalrd.net/host&#34;);
queryRTT(&#34;dns-latency&#34;,20,&#34;https://geo.apalrd.net/host&#34;);
queryRTT(&#34;bgp-latency&#34;,20,&#34;https://any.apalrd.net/host&#34;);
queryText(&#34;geodns&#34;,&#34;https://geo.apalrd.net/data&#34;);
updateProgressBar(1)
&lt;/script&gt; </content>
    </item>
    
    <item>
      <title>Wishlist</title>
      <link>https://www.apalrd.net/wishlist/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.apalrd.net/wishlist/</guid>
      <description>I have a lot of project ideas that I haven&amp;rsquo;t prioritized enough to spend money on. So, here are some thing I&amp;rsquo;d like to experiment with. Also, if you have any leads on where I can find some of these products, it would help too.
ISP Hardware (vintage / but not too vintage) I&amp;rsquo;d love to build a homelab ISP. I&amp;rsquo;m probably going to make some videos on this in the future, as I&amp;rsquo;m working on a WAN Simulator to play with map-t / 464xlat / dslite and friends.</description>
      <content>&lt;p&gt;I have a lot of project ideas that I haven&amp;rsquo;t prioritized enough to spend money on. So, here are some thing I&amp;rsquo;d like to experiment with. Also, if you have any leads on where I can find some of these products, it would help too.&lt;/p&gt;
&lt;h2 id=&#34;isp-hardware-vintage--but-not-too-vintage&#34;&gt;ISP Hardware (vintage / but not too vintage)&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;d love to build a homelab ISP. I&amp;rsquo;m probably going to make some videos on this in the future, as I&amp;rsquo;m working on a WAN Simulator to play with map-t / 464xlat / dslite and friends. In particular, gear which was new during the dot-com bubble is probably too old.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dial-up is too old&lt;/li&gt;
&lt;li&gt;ISDN BRI / PRI is also too old&lt;/li&gt;
&lt;li&gt;DSLAM / any DSL gear would be fun (this was more tail-end of the dot-com bubble except in Germany)&lt;/li&gt;
&lt;li&gt;DOCSIS gear (this is still actively deployed by some shitty ISPs in the US!)&lt;/li&gt;
&lt;li&gt;PON gear (this is what should be deployed in 2025)&lt;/li&gt;
&lt;li&gt;Switches which support SONIC&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;apalrds-fiber-lab&#34;&gt;Apalrd&amp;rsquo;s Fiber LAb&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m also slowly accumulating fiber equipment, starting with basic 1310nm optics. I&amp;rsquo;d like to work my way into a WDM test setup, maybe something like an ISP fiber ring with a wavelength add/drop at each node.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any WDM optics (CWDM or DWDM) in 10G or faster, even single un-paired optics&lt;/li&gt;
&lt;li&gt;Passive optical components (cwdm muxes, dwdm add/drop muxes, filter splitters)
I don&amp;rsquo;t think I am ready for active optical components like amps and ROADMs since my distances are so short. But msg me!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;wireless-gear&#34;&gt;Wireless Gear&lt;/h2&gt;
&lt;p&gt;Similar to the Homelab ISP idea, any sort of wireless gear would be fun. I do love to setup networks for the fun of setting them up, and then not use them once it works, so don&amp;rsquo;t expect a long-running test platform&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GSM (as long as it works with Osmocom)&lt;/li&gt;
&lt;li&gt;WiMax&lt;/li&gt;
&lt;li&gt;WiFi HaLow (900Mhz)&lt;/li&gt;
&lt;li&gt;LiFi&lt;/li&gt;
&lt;li&gt;Any other point to (multi)point setup would be cool&lt;/li&gt;
&lt;li&gt;Anything optical (as long as it&amp;rsquo;s a pair!)&lt;/li&gt;
&lt;li&gt;LTE&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;computer-hardware&#34;&gt;Computer Hardware&lt;/h2&gt;
&lt;p&gt;I do love computers! Here are some things I&amp;rsquo;m particularly interested in, the more unique the better!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Obscure but still usable storage hardware (PCIe cache cards, etc.)&lt;/li&gt;
&lt;li&gt;Mid 90s UNIX workstations (they are so beautiful) - even if they don&amp;rsquo;t work, I will 100% put them on my next filming set&lt;/li&gt;
&lt;li&gt;If you have any other unique hardware you think might fit with the channel, feel free to email or message on Discord!&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
  </channel>
</rss>
