<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: St. John Johnson</title>
    <description>The latest articles on DEV Community by St. John Johnson (@stjohnjohnson).</description>
    <link>https://dev.to/stjohnjohnson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F340350%2Fa2f7c020-1510-48a9-93d3-2e9145bfc3d6.png</url>
      <title>DEV Community: St. John Johnson</title>
      <link>https://dev.to/stjohnjohnson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stjohnjohnson"/>
    <language>en</language>
    <item>
      <title>Animated Gifs for Text-Based UIs</title>
      <dc:creator>St. John Johnson</dc:creator>
      <pubDate>Tue, 03 Mar 2020 07:44:48 +0000</pubDate>
      <link>https://dev.to/stjohnjohnson/animated-gifs-for-text-based-uis-2g76</link>
      <guid>https://dev.to/stjohnjohnson/animated-gifs-for-text-based-uis-2g76</guid>
      <description>&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;In my spare time, I've been working on a simple text-based game for my 4 year old to play.  He found my 10 year old Linux laptop and has been having a blast with the terminal.&lt;/p&gt;

&lt;p&gt;When I started writing the game, I picked GoLang as the language and researched a variety of TUI (text user interface) libraries.  After some quick prototypes, I settled with &lt;a href="https://github.com/rivo/tview"&gt;&lt;code&gt;tview&lt;/code&gt;&lt;/a&gt; for the solid primitives and ease of keyboard interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Objective
&lt;/h2&gt;

&lt;p&gt;During development, I realized it could use more feedback when getting an answer right or wrong.  The way I wanted to solve that was by adding simple animations (e.g. happy vs sad cat).  Nothing in &lt;code&gt;tview&lt;/code&gt; (or the other libraries) had anything readily available.&lt;/p&gt;

&lt;p&gt;The following is the process I went through to build a new &lt;code&gt;tview&lt;/code&gt; object that supported displaying animated gifs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse the image frames and timing information&lt;/li&gt;
&lt;li&gt;Display the frames on the screens&lt;/li&gt;
&lt;li&gt;Scale for multiple animations&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1. Parsing Gifs
&lt;/h2&gt;

&lt;p&gt;GoLang has a simple built in Gif library &lt;a href="https://golang.org/pkg/image/gif/"&gt;&lt;code&gt;image/gif&lt;/code&gt;&lt;/a&gt;.  After decoding the file, you are left with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set of frames as &lt;code&gt;image.Paletted&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set of delays between frames as &lt;code&gt;int&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Step 2. Image to Text
&lt;/h2&gt;

&lt;p&gt;I stumbled across &lt;a href="https://github.com/Omnikron13/pixelview"&gt;&lt;code&gt;pixelview&lt;/code&gt;&lt;/a&gt; which converts images into formatted text for &lt;code&gt;tview&lt;/code&gt; by using colored half-block unicode characters (&lt;code&gt;▀&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It also accepts the &lt;code&gt;image.Image&lt;/code&gt; interface (which is what &lt;code&gt;image.Paletted&lt;/code&gt; above uses).&lt;/p&gt;

&lt;p&gt;Now I can display each of those Gif frames into a &lt;code&gt;tview&lt;/code&gt; box.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Step 3. Optimizing
&lt;/h2&gt;

&lt;p&gt;The above prototype wouldn't &lt;em&gt;really&lt;/em&gt; work.  Besides the single-threaded iteratation through a single gif (which prevents us from adding multiple gifs), there are performance issues to take into account.  Depending on the speed and the number of frames, you would see CPU load during quick rendering and constant conversion of image objects.  Additionally, the use of &lt;code&gt;TextView&lt;/code&gt; and the added features (scrolling and highlighting) slows down rendering.&lt;/p&gt;

&lt;p&gt;To reduce that impact and support multiple images, I switched to my own &lt;code&gt;Box&lt;/code&gt; class and made some important changes.&lt;/p&gt;

&lt;p&gt;First, I switched the animation to be on-demand.  That way, whenever the view &lt;em&gt;needed&lt;/em&gt; to be re-drawn it would calculate the current frame it &lt;em&gt;should&lt;/em&gt; be on and render that.&lt;/p&gt;

&lt;p&gt;I did that by recording the start time of the view and iterating on each frame delay until we knew where we were.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Second, I removed our usage of &lt;code&gt;TextView&lt;/code&gt; and made my own stripped down version of the &lt;code&gt;TextView&lt;/code&gt; draw function.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Finally, I triggered a global re-draw on a periodic basis.  That way all Gifs would be animated consistently (although not as smooth).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Final Product
&lt;/h2&gt;

&lt;p&gt;In the end, I created a library that allowed me to add basic animated gifs into my son's game using a single interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/stjohnjohnson/gifview"&gt;Here&lt;/a&gt; is the library as well as the &lt;a href="https://pkg.go.dev/github.com/stjohnjohnson/gifview"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And this is a simple example (dancing banana not included):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UvxnlmXz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/622065/75753122-e7392b00-5cde-11ea-869b-e0ea21806ddd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UvxnlmXz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/622065/75753122-e7392b00-5cde-11ea-869b-e0ea21806ddd.gif" alt="working-demo"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>tui</category>
      <category>gif</category>
      <category>tview</category>
    </item>
    <item>
      <title>Internal Domains with DNSMasq and Pi-Hole</title>
      <dc:creator>St. John Johnson</dc:creator>
      <pubDate>Sat, 29 Feb 2020 07:37:55 +0000</pubDate>
      <link>https://dev.to/stjohnjohnson/internal-domains-with-dnsmasq-and-pi-hole-4cof</link>
      <guid>https://dev.to/stjohnjohnson/internal-domains-with-dnsmasq-and-pi-hole-4cof</guid>
      <description>&lt;p&gt;Running services inside your own household is an absolute blast.  It usually starts with some application you need to keep running after you close your laptop.  Before you know it, you have a Raspberry Pi in every room, at least one Intel NUC, and a small server rack in your Amazon shopping cart.&lt;/p&gt;

&lt;p&gt;When going down this path myself, I noticed an interesting problem arose after I introduced the second server.  Talking to one machine is easy, just memorize the static IP.  But once you start to introduce multiple machines or multiple services on the same machine, it becomes a game of "what IP, what port, what path."  And for the other people in the household, it's impossible to understand.&lt;/p&gt;

&lt;p&gt;For me to continue, I needed my own DNS server.  Luckily, I already introduced one into my ecosystem when I starting running Pi-Hole (for blocking tracking/ads).&lt;/p&gt;

&lt;p&gt;In the next section, I'm going to show you how to quickly augment Pi-Hole to serve internal domains as well as block those pesky external domains.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. DNSMasq
&lt;/h2&gt;

&lt;p&gt;Pi-Hole, under the hood, is running DNSMasq.  So we want to provide it with some additional hosts to resolve.&lt;/p&gt;

&lt;p&gt;First is the additional configuration to run &lt;em&gt;after&lt;/em&gt; Pi-Hole:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Second is the list of hosts and their static IPs:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  2. File Placement
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;.conf&lt;/code&gt; file should be placed in the &lt;code&gt;/etc/dnsmasq.d/&lt;/code&gt; folder.  And the &lt;code&gt;.list&lt;/code&gt; file should be placed in the &lt;code&gt;/etc/pihole/&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;For this demonstration, we're going to manage Pi-Hole locally in a Docker container.  Here is my &lt;code&gt;docker-compose&lt;/code&gt; file that mounts those files correctly:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  3. Validating
&lt;/h2&gt;

&lt;p&gt;If we run Pi-Hole with those settings, we can validate they are accepted by using &lt;code&gt;dig&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dig @127.0.0.1 haas.example.com +short
10.0.0.205
&lt;span class="nv"&gt;$ &lt;/span&gt;dig @127.0.0.1 pihole.example.com +short
10.0.0.205
&lt;span class="nv"&gt;$ &lt;/span&gt;dig @127.0.0.1 plex.example.com +short
10.0.0.210
&lt;span class="nv"&gt;$ &lt;/span&gt;dig @127.0.0.1 go +short
10.0.0.215
&lt;span class="nv"&gt;$ &lt;/span&gt;dig @127.0.0.1 modem +short
192.168.100.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that external domains are still routed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dig @127.0.0.1 google.com +short
172.217.5.206
&lt;span class="nv"&gt;$ &lt;/span&gt;dig @127.0.0.1 github.com +short
192.30.255.113
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Appendix
&lt;/h2&gt;

&lt;p&gt;All of the steps and configurations you saw in this guide are available to checkout from &lt;a href="https://gist.github.com/stjohnjohnson/d441e26e4d77a975fd3ebb4e6f19e3d6"&gt;my GitHub Gist&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://gist.github.com/d441e26e4d77a975fd3ebb4e6f19e3d6.git
...
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;d441e26e4d77a975fd3ebb4e6f19e3d6
&lt;span class="nv"&gt;$ &lt;/span&gt;make
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>dnsmasq</category>
      <category>pihole</category>
      <category>docker</category>
      <category>dns</category>
    </item>
    <item>
      <title>Bring Your Own Certificate Authority</title>
      <dc:creator>St. John Johnson</dc:creator>
      <pubDate>Mon, 24 Feb 2020 05:17:22 +0000</pubDate>
      <link>https://dev.to/stjohnjohnson/bring-your-own-certificate-authority-3gle</link>
      <guid>https://dev.to/stjohnjohnson/bring-your-own-certificate-authority-3gle</guid>
      <description>&lt;p&gt;Over the past few years, I've been running a number of internal services for my household. These include automation tools with Home Assistant, anti-tracking with Pi-Hole, and media management with Plex.&lt;/p&gt;

&lt;p&gt;Even in my home network, I still want these services to all use TLS. Until last week, I was doing this via a single complicated Nginx server using path proxying to the internal services. That service had a single (obfuscated) domain name that I used Let's Encrypt (ever 90 days) with DNS validation.&lt;br&gt;
This was quite complicated to manage, share with the family, and not all the services I wanted to use supported alternative paths.&lt;/p&gt;

&lt;p&gt;This all changed last week when my friend told me his household has their own Root Certificate! It immediately clicked, I could have all the subdomains I want with valid TLS certificates and not have to expose any information to the internet! Brilliant!&lt;/p&gt;

&lt;p&gt;In this article, I'm going to walk through creating your own root certificate for your domain, generating server certificates, configuring your servers, and installing the CA on your client machines.&lt;/p&gt;


&lt;h2&gt;
  
  
  0. Know your Environment
&lt;/h2&gt;

&lt;p&gt;My target systems were going to be a variety of OSX, iOS, and Windows devices. After doing some research (e.g. trial and error), I found that OSX/iOS has some &lt;a href="https://support.apple.com/en-us/HT210176"&gt;new limitations&lt;/a&gt; on certificates that affect the work we need to do. The quick summary is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RSA keys must use key sizes greater than or equal to 2048 bits&lt;/li&gt;
&lt;li&gt;DNS name of the server must be in the Subject Alternative Name (SAN)&lt;/li&gt;
&lt;li&gt;Server certificates must contain "serverAuth" ExtendedKeyUsage (EKU)&lt;/li&gt;
&lt;li&gt;Server certificates must be valid for 825 days or fewer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And for me to make the certificates, I wanted the process to be quite repeatable (as I'll be adding new services over time) and I needed it to support sane future defaults. For those reasons, I ended up using &lt;a href="https://github.com/cloudflare/cfssl"&gt;cfssl by CloudFlare&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;cfssl
...
🍺  /usr/local/Cellar/cfssl/1.4.1: 5 files, 44.2MB

&lt;span class="nv"&gt;$ &lt;/span&gt;cfssl version
Version: 1.4.1
Runtime: go1.13.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;All of the steps and configurations you will see in this guide are available to checkout from &lt;a href="https://gist.github.com/stjohnjohnson/77c5515720954a97f2b9866bc6ab85e0"&gt;my GitHub Gist&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://gist.github.com/77c5515720954a97f2b9866bc6ab85e0.git
...
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;77c5515720954a97f2b9866bc6ab85e0
&lt;span class="nv"&gt;$ &lt;/span&gt;make
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  1. Generating your Root Certificate
&lt;/h2&gt;

&lt;p&gt;We need to start by generate our CA (Certificate Authority). To do this, we need to provide a config to &lt;code&gt;cfssl&lt;/code&gt; about our new root domain.  Here is my &lt;code&gt;ca-csr.json&lt;/code&gt;.  You can also see the defaults via &lt;code&gt;cfssl print-defaults csr&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pay close attention to the RSA/2048 as that is required for OSX/iOS.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we use the &lt;code&gt;gencert&lt;/code&gt; command to create our new CA.  Piping the command to the &lt;code&gt;cfssljson&lt;/code&gt; command converts the &lt;code&gt;cfssl&lt;/code&gt; JSON output into files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;cfssl gencert &lt;span class="nt"&gt;-initca&lt;/span&gt; ca-csr.json | cfssljson &lt;span class="nt"&gt;-bare&lt;/span&gt; ca
2020/02/23 00:21:49 &lt;span class="o"&gt;[&lt;/span&gt;INFO] generating a new CA key and certificate from CSR
2020/02/23 00:21:49 &lt;span class="o"&gt;[&lt;/span&gt;INFO] generate received request
2020/02/23 00:21:49 &lt;span class="o"&gt;[&lt;/span&gt;INFO] received CSR
2020/02/23 00:21:49 &lt;span class="o"&gt;[&lt;/span&gt;INFO] generating key: rsa-2048
2020/02/23 00:21:49 &lt;span class="o"&gt;[&lt;/span&gt;INFO] encoded CSR
2020/02/23 00:21:49 &lt;span class="o"&gt;[&lt;/span&gt;INFO] signed certificate with serial number 505123895045664503620591058435184552164152724476
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That will give you your new CA (&lt;code&gt;ca.pem&lt;/code&gt;) and private key (&lt;code&gt;ca-key.pem&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Generating a Server Certificate
&lt;/h2&gt;

&lt;p&gt;With that new CA, we can now mint a certificate for our first service (pi-hole).  Generating a certificate requires two configs, one for the CA config and another CSR for the server itself.&lt;/p&gt;

&lt;p&gt;Here is my &lt;code&gt;ca-config.json&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pay close attention to the 1 year expiration and &lt;code&gt;"server auth"&lt;/code&gt; being listed in the usages section (i.e. EKU).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here is my &lt;code&gt;server-csr.json&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;Key is RSA/2048 again and we also put the DNS entry in &lt;code&gt;hosts&lt;/code&gt; (i.e. SAN)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that we have our configs, we can generate our certificate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;cfssl gencert &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-ca&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ca.pem &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-ca-key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ca-key.pem &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ca-config.json &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;web-servers &lt;span class="se"&gt;\&lt;/span&gt;
    server-csr.json | cfssljson &lt;span class="nt"&gt;-bare&lt;/span&gt; server
2020/02/23 09:16:46 &lt;span class="o"&gt;[&lt;/span&gt;INFO] generate received request
2020/02/23 09:16:46 &lt;span class="o"&gt;[&lt;/span&gt;INFO] received CSR
2020/02/23 09:16:46 &lt;span class="o"&gt;[&lt;/span&gt;INFO] generating key: rsa-2048
2020/02/23 09:16:46 &lt;span class="o"&gt;[&lt;/span&gt;INFO] encoded CSR
2020/02/23 09:16:46 &lt;span class="o"&gt;[&lt;/span&gt;INFO] signed certificate with serial number 380799927774623048949672171568330922769086552071
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now you have a server certificate for &lt;code&gt;pihole.stj.me&lt;/code&gt; with (&lt;code&gt;server.pem&lt;/code&gt;) and private key (&lt;code&gt;server-key.pem&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We can quickly verify it with openssl:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;openssl verify &lt;span class="nt"&gt;-CAfile&lt;/span&gt; ca.pem server.pem
server.pem: OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  3. Configuring a NGinx Server
&lt;/h2&gt;

&lt;p&gt;Our NGinx server needs to perform three actions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Serve &lt;code&gt;ca.pem&lt;/code&gt; over &lt;code&gt;80&lt;/code&gt; so our clients can install the certificate.&lt;/li&gt;
&lt;li&gt;Redirect &lt;code&gt;pihole.stj.me&lt;/code&gt; from &lt;code&gt;80&lt;/code&gt; to &lt;code&gt;443/ssl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Serve &lt;code&gt;pihole.stj.me&lt;/code&gt; over &lt;code&gt;443/ssl&lt;/code&gt; with the server keys we generated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;To serve Pi-Hole, I'm using a docker container that is on the same virtual network via docker-compose (see below).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here is my &lt;code&gt;nginx.conf&lt;/code&gt; file that supports those actions.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;As I said above, I've put everything in Docker-Machine with the two containers to make it easier to demonstrate here (&lt;code&gt;docker-compose.yml&lt;/code&gt;):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With all this, we can get the service running using a simple command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker-compose up nginx
Starting 77c5515720954a97f2b9866bc6ab85e0_pihole_1 ... &lt;span class="k"&gt;done
&lt;/span&gt;Starting 77c5515720954a97f2b9866bc6ab85e0_nginx_1 ... &lt;span class="k"&gt;done
&lt;/span&gt;Attaching to 77c5515720954a97f2b9866bc6ab85e0_pihole_1, 77c5515720954a97f2b9866bc6ab85e0_nginx_1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to augment your &lt;code&gt;/etc/hosts&lt;/code&gt; with the new subdomain (until we put it in dnsmasq):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"127.0.0.1 pihole.stj.me"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/hosts
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;grep &lt;/span&gt;stj.me /etc/hosts
127.0.0.1 pihole.stj.me
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can now verify that the actions work as expected:&lt;/p&gt;

&lt;p&gt;Serving the certificate over port 80:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl http://localhost/ca.pem
&lt;span class="nt"&gt;-----BEGIN&lt;/span&gt; CERTIFICATE-----
...
&lt;span class="nt"&gt;----------END&lt;/span&gt; CERTIFICATE-----
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redirecting to https:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://pihole.stj.me/admin/
HTTP/1.1 301 Moved Permanently
Server: nginx/1.17.8
Date: Mon, 24 Feb 2020 03:50:40 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://pihole.stj.me/admin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Serving pi-hole with our server certificates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://pihole.stj.me/admin/
curl: &lt;span class="o"&gt;(&lt;/span&gt;60&lt;span class="o"&gt;)&lt;/span&gt; SSL certificate problem: unable to get &lt;span class="nb"&gt;local &lt;/span&gt;issuer certificate

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; &lt;span class="nt"&gt;--cacert&lt;/span&gt; ca.pem https://pihole.stj.me/admin/
HTTP/1.1 200 OK
Server: nginx/1.17.8
Date: Mon, 24 Feb 2020 03:52:28 GMT
Content-Type: text/html&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;UTF-8
Connection: keep-alive
X-Pi-hole: The Pi-hole Web interface is working!
X-Frame-Options: DENY
Set-Cookie: &lt;span class="nv"&gt;PHPSESSID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fvj75itvvq3e8pel87gkl7gdk2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Installing the Clients
&lt;/h2&gt;

&lt;p&gt;Great, we have a working service, time to make sure your clients can talk to your services without having to pass the CA around (or &lt;code&gt;--insecure&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For the rest of this guide, we're going to assume this is running on a server in the network with the IP &lt;code&gt;10.0.0.100&lt;/code&gt;.  That means from whatever device in your trusted network, you should be able to access &lt;code&gt;http://10.0.0.100/ca.pem&lt;/code&gt;.  Additionally, you have already configured &lt;code&gt;pihole.stj.me&lt;/code&gt; to point to &lt;code&gt;10.0.0.100&lt;/code&gt; via DNSMasq or something else on your network.&lt;/p&gt;

&lt;h3&gt;
  
  
  OSX
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Download the &lt;code&gt;ca.pem&lt;/code&gt; from your server via the URL above&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;Keychain Access.app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go to the &lt;code&gt;System&lt;/code&gt; keychain&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;File &amp;gt; Import Items&lt;/code&gt; or use &lt;code&gt;shift+cmd+I&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Double-click on your certificate&lt;/li&gt;
&lt;li&gt;Expand the &lt;code&gt;Trust&lt;/code&gt; section and select &lt;code&gt;Always Trust&lt;/code&gt; for &lt;code&gt;When using this certificate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Close &lt;code&gt;Keychain Access.app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Visit &lt;code&gt;https://pihole.stj.me/admin/&lt;/code&gt; successfully!&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  IOS
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Visit the &lt;code&gt;ca.pem&lt;/code&gt; URL above in Safari&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Allow&lt;/code&gt; when prompted about downloading a &lt;code&gt;configuration profile&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go to the &lt;code&gt;Settings&lt;/code&gt; app&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;Profile Downloaded&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Install&lt;/code&gt;, enter your passcode, click &lt;code&gt;Install&lt;/code&gt;, and click &lt;code&gt;Install&lt;/code&gt; again&lt;/li&gt;
&lt;li&gt;Go back to the &lt;code&gt;Settings&lt;/code&gt; app&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;General &amp;gt; About &amp;gt; Certificate Trust Settings&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enable &lt;code&gt;Full Trust&lt;/code&gt; for your Root Certificate&lt;/li&gt;
&lt;li&gt;Visit &lt;code&gt;https://pihole.stj.me/admin/&lt;/code&gt; successfully!&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Windows 10
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Download the &lt;code&gt;ca.pem&lt;/code&gt; from your server via the URL above&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;Microsoft Management Console&lt;/code&gt; via &lt;code&gt;Start &amp;gt; Run &amp;gt; mmc.exe&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;File &amp;gt; Add/Remove Snap-in&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;Certificates&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;Computer Account&lt;/code&gt; and &lt;code&gt;Local computer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;OK&lt;/code&gt; to close the dialog&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;Trusted Root Certification Authorities&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Right-click and select &lt;code&gt;All Tasks &amp;gt; Import&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Follow the wizard and select the &lt;code&gt;ca.pem&lt;/code&gt; file you downloaded&lt;/li&gt;
&lt;li&gt;Visit &lt;code&gt;https://pihole.stj.me/admin/&lt;/code&gt; successfully!&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>ssl</category>
      <category>nginx</category>
      <category>certificates</category>
      <category>pihole</category>
    </item>
  </channel>
</rss>
