<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feeds.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://chameth.com/">
    <title>Chameth.com - posts like docker-automatic-nginx-proxy, why-you-should-be-using-https but not debugging-beyond-the-debugger, g15-ram-upgrade, intro-to-containers, tailscale-docker-gotcha</title>
    <subtitle>Personal homepage of Chris Smith</subtitle>
    <link href="https://chameth.com/feeds/posts/like/docker-automatic-nginx-proxy,why-you-should-be-using-https/unlike/debugging-beyond-the-debugger,g15-ram-upgrade,intro-to-containers,tailscale-docker-gotcha/" rel="self"/>
    <link href="https://chameth.com/"/>
    <icon>https://chameth.com/favicon.png</icon>
    <updated>2022-12-06T00:00:00Z</updated>
    <id>https://chameth.com/</id>
    <author>
        <name>Chris Smith</name>
    </author>
    <entry>
        <title>Docker reverse proxying, redux</title>
        <link href="https://chameth.com/docker-proxying-redux/"/>
        <updated>2022-12-06T00:00:00Z</updated>
        <id>https://chameth.com/docker-proxying-redux/</id>
        <content xml:lang="en" type="html">&lt;p&gt;Six years ago, &lt;a href=&#34;https://chameth.com/docker-automatic-nginx-proxy/&#34;&gt;I described&lt;/a&gt;
my system for configuring a reverse proxy for docker containers.
It involved six containers including a key-value store and a webserver.
Nothing in that system has persisted to this day. Don’t get me wrong – it
worked – but there were a lot of rough edges and areas for improvement.&lt;/p&gt;
&lt;h3 id=&#34;microservices-and-their-limitations&#34;&gt;Microservices and their limitations&lt;/h3&gt;
&lt;p&gt;My goal was to follow the UNIX philosophy of “do one thing and do it well”.
Unfortunately, that doesn’t really work when applied to network services that
have to interact with one and other. UNIX tools are built upon a common file
system and simple data passed over STDIN. Microservices don’t have that
shared foundation. You could make one:
companies that use microservices in anger often have a team that deals with
the “developer experience” of creating and using
microservices. But as a solo developer that’s not something I wanted to
spend my time doing.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;This became very apparent when trying to debug issues. In the UNIX world,
if your series of commands piped together does something strange you can simply
echo the data at various stages. Not so much when that data is flying around
on a network, going into and out of things like etcd. Trying to figure out why
a certificate hadn’t been acquired was a case of searching through logs from
four containers, none of which had particularly good logging.
There are many ways to get insight into what’s
happening with microservices but, again, that’s not something I wanted to do myself.&lt;/p&gt;
&lt;p&gt;Over time, and with experience in other projects, I came to realise that
microservices only really make sense if you’re unable to deploy a monolith.
For tech companies this naturally happens when different teams
contribute to the same service: splitting it out into smaller services that
are wholly owned by individual teams makes sense. For solo developers,
that never happens. You can still gain the other benefits
of microservices – such as code separation and having clearly defined APIs –
by sticking to certain coding standards.&lt;/p&gt;
&lt;h3 id=&#34;proxy-inconveniences&#34;&gt;Proxy inconveniences&lt;/h3&gt;
&lt;p&gt;As well as being unhappy with the microservice nature of the solution,
I wasn’t pleased with nginx. If you requested an unknown domain, nginx
would use the first server block in its config to serve a response, instead
of sending an “unrecognised name” alert as I wanted. It was a minor issue, but
it irked me.&lt;/p&gt;
&lt;p&gt;So from nginx I switched to haproxy. It has a &lt;code&gt;strict-sni&lt;/code&gt; option when configuring
TLS connections which makes it behave properly. It also performs a lot better for
this type of workload than nginx. All was well for a while, but then I started getting alerts
that requests were occasionally failing. I couldn’t reproduce the issue, but
my nightly jobs to build and push containers managed to hit it nearly every
night, causing them to fail.&lt;/p&gt;
&lt;p&gt;After some investigation, I found that the haproxy developers had refactored
the header parsing code, and
neglected to properly reset flags when multiple requests were sent over the same
connection. There was a patch, but it wasn’t released. No problem, I thought,
I’ll just cherry-pick it onto the last release… Except that haproxy use
Git in the most convoluted manner I’ve ever seen – they have one
repository per release. This makes it harder to patch, but it also made me question
whether I trusted them to ship stable software: there were no tests for
the header parsing code (which is both fundamental and finicky,
the perfect target for tests), the source code management was weird, and they didn’t
seem in any rush to patch this bug.&lt;/p&gt;
&lt;p&gt;Not long after that issue, &lt;a href=&#34;https://greg.holmes.name/&#34;&gt;Greg&lt;/a&gt; managed to
encounter another bug where haproxy returned a 500 error whenever the
upstream server replied with a particular, perfectly valid, header.
The die was cast – it was time to move to something else.&lt;/p&gt;
&lt;h3 id=&#34;not-invented-here-syndrome&#34;&gt;Not Invented Here syndrome&lt;/h3&gt;
&lt;p&gt;Looking for a new solution, there were many more options than
back in 2016. I’m still convinced, however, that anything
exposed to the Internet should not have access to run docker containers.
It’s the modern equivalent of running a CGI script as root. That
single requirement eliminates most off-the-shelf solutions.
What do you do when nothing quite meets
your specific requirements? You make something yourself! My new solution has two
components: &lt;a href=&#34;https://github.com/csmith/dotege&#34;&gt;Dotege&lt;/a&gt; and
&lt;a href=&#34;https://github.com/csmith/centauri&#34;&gt;Centauri&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dotege is a replacement for the
microservices that monitored containers and obtained certificates. It’s fundamentally
a templating engine - whenever the containers change, it evaluates a
template and saves the result to disk. The template has access to details about
the containers, their labels, ports, and so on. Dotege can also obtain certificates
from Let’s Encrypt, and raise a signal against another
process whenever the template or certificates change. I used this to generate
the configuration and certificates used by haproxy for a while, and more recently
changed the template so that it works for Centauri.&lt;/p&gt;
&lt;p&gt;Centauri is my own reverse proxy. It’s configured using a simple text file
and can also obtain certificates from an ACME provider. It doesn’t serve static
content, has no knowledge about docker, and avoids the other bells and
whistles that adorn most reverse proxies. It also has good test
coverage to ensure that I don’t, say, accidentally break header parsing.&lt;/p&gt;
&lt;p&gt;As a software engineer I enjoy writing software, but I also enjoy running
simple, easy to understand software. That’s what I’ve achieved here: it’s
very easy to identify where the problem is if anything goes wrong, both are small
Go programs rather than vast sprawling C
monstrosities, and their interaction is primarily through a file written to disk
that can be inspected or edited as needed.&lt;/p&gt;
</content>
    </entry>
    <entry>
        <title>Why you should be using HTTPS</title>
        <link href="https://chameth.com/why-you-should-be-using-https/"/>
        <updated>2016-06-17T00:00:00Z</updated>
        <id>https://chameth.com/why-you-should-be-using-https/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/why-you-should-be-using-https/https-everywhere.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/why-you-should-be-using-https/https-everywhere.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/why-you-should-be-using-https/https-everywhere.jpg&#34; alt=&#34;The EFF&amp;#39;s HTTPS Everywhere logo&#34; loading=&#34;lazy&#34; width=&#34;300&#34; height=&#34;260&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;The EFF’s HTTPS Everywhere logo&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;One of my favourite hobbyhorses recently has been the use of HTTPS, or lack thereof. HTTPS is the
thing that makes the little padlock appear in your browser, and has existed for over 20 years.
In the past, that little padlock was the exclusive preserve of banks and other ‘high security’
establishments; over time its use has gradually expanded to most (but not all) websites
that handle user information, and the time is now right for it to become ubiquitous.&lt;/p&gt;
&lt;h3 id=&#34;why-use-https&#34;&gt;Why use HTTPS?&lt;/h3&gt;
&lt;p&gt;There are numerous advantages to using HTTPS, both for the users of a website and for the
operator:&lt;/p&gt;
&lt;h4 id=&#34;privacy&#34;&gt;Privacy&lt;/h4&gt;
&lt;p&gt;The most obvious advantage is that HTTPS gives your users additional privacy. An insecure (HTTP)
request can potentially be read by anyone on the same network, or the network operators, or anyone
who happens to operate a network along the path between the user and the server.&lt;/p&gt;
&lt;p&gt;Users on shared WiFi networks (such as those in coffee shops, hotels, or offices) are particularly
vulnerable to passive sniffing by anyone else on that network. If the network is open (as is
frequently the case) then anyone in radio range can see exactly what the user is up to.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h4 id=&#34;integrity&#34;&gt;Integrity&lt;/h4&gt;
&lt;p&gt;HTTPS also helps to maintain the integrity of your site. With a plain HTTP request, there’s nothing
to stop anyone in between the server and the user from modifying the content of the request or the
response. This is a frequent tactic used by annoying WiFi gateways (such as the ones &lt;a href=&#34;http://justinsomnia.org/2012/04/hotel-wifi-javascript-injection/&#34;&gt;you’d find in
a hotel&lt;/a&gt;), dubious ISPs who want
to serve you extra adverts, or just plain old nefarious attackers.&lt;/p&gt;
&lt;p&gt;If you’re trying to convey some kind of information to users (and if you aren’t, why exactly are
you running a website again?) it seems beneficial to both you and them if the information arrives
as you intended, rather than in a modified form due to someone or something tampering with it.&lt;/p&gt;
&lt;h4 id=&#34;security&#34;&gt;Security&lt;/h4&gt;
&lt;p&gt;If your website has any kind of authentication, or session identifiers, it becomes extremely
vulnerable to an attacker monitoring the traffic and stealing the credentials. This was
starkly demonstrated in 2010 when &lt;a href=&#34;https://en.wikipedia.org/wiki/Firesheep&#34;&gt;Firesheep&lt;/a&gt; was
released. This tool allowed anyone to quickly and automatically hijack social media accounts of
anyone on the same network who was using HTTP to access them.&lt;/p&gt;
&lt;p&gt;Even if your login pages are served over HTTPS, if you send a single session ID cookie over HTTP
(such as a page you decided wasn’t particularly ‘important’) then an attacker can probably spoof
the user’s session and gain full access to their account.  Again, in the case of open WiFi networks
that could be anyone in radio range.&lt;/p&gt;
&lt;h4 id=&#34;search-engine-rankings&#34;&gt;Search engine rankings&lt;/h4&gt;
&lt;p&gt;Some search engines use HTTPS as a signal in their ranking algorithms. &lt;a href=&#34;https://security.googleblog.com/2014/08/https-as-ranking-signal_6.html&#34;&gt;Google announced in
2004&lt;/a&gt; that it was using
the presence of HTTPS as a small positive signal, but that it may strengthen that signal over time
as more and more websites switch to using a secure transport. It’s not unthinkable that at some
point in the future there will be HTTPS-only search engines.&lt;/p&gt;
&lt;h3 id=&#34;but-but-but&#34;&gt;But… But… But…&lt;/h3&gt;
&lt;p&gt;There are lots of excuses for not implementing HTTPS. Most of them are either misguided or outdated.&lt;/p&gt;
&lt;h4 id=&#34;its-too-expensive-andor-complicated&#34;&gt;It’s too expensive and/or complicated&lt;/h4&gt;
&lt;p&gt;In the past, getting HTTPS certificates was a pain. A number of free suppliers have existed for
a while but the process for getting their certificates wasn’t particularly straight forward, and
many imposed arbitrary restrictions on the certificate parameters. Even once you had the
certificate, you had to fiddle about with your HTTP server configuration to make it work, remember
to manually get a new certificate when the old one expired, and lots of other annoying busywork.&lt;/p&gt;
&lt;p&gt;With the arrival of &lt;a href=&#34;https://letsencrypt.org/&#34;&gt;Let’s Encrypt&lt;/a&gt;, all that changed. You can retrieve
and deploy a free HTTPS certificate with two or three commands. Renewal can be handled completely
automatically with a single command executed by cron.&lt;/p&gt;
&lt;h4 id=&#34;theres-no-point-nothing-on-my-site-is-sensitive&#34;&gt;There’s no point; nothing on my site is sensitive&lt;/h4&gt;
&lt;p&gt;You might not think your content warrants privacy, but can you speak for everyone who accesses it?
Even content that seems mundane to you — such as travel advice, or technical writing — could be
used to build up a profile of a user. If an attacker is monitoring traffic in a coffee shop and
sees a user looking at travel advice and weather forecasts for a foreign country, he could use that
information to plan a burglary knowing that the user will be away. Similarly, some content which
is perfectly mundane to you may actually be very sensitive in other countries with repressive
governments. HTTPS makes it much harder for these people to snoop on traffic.&lt;/p&gt;
&lt;p&gt;From another angle, if you’re offering any kind of information, instructions, or especially file
downloads, there’s a severe risk to users if the content is modified on its way to them. An evil
sysadmin could rewrite your travel advice to suggest visiting the local drug dealer’s hangout, or
replace your download with a malware-infested version.&lt;/p&gt;
&lt;h4 id=&#34;https-is-slower-uses-more-resources-etc&#34;&gt;HTTPS is slower, uses more resources, etc&lt;/h4&gt;
&lt;p&gt;Back in 1995 this might have been a valid argument. Enabling HTTPS on a modern server will make
an almost negligible difference to performance. If you also enable HTTP/2 (which most
implementations only support over HTTPS), it’s likely to actually use fewer resources, and result
in a faster, smoother experience for your users. HTTP/2 was designed to work with HTTPS, and
designed with modern requirements and networking techniques in mind.&lt;/p&gt;
&lt;p&gt;CloudFlare have an &lt;a href=&#34;https://www.cloudflare.com/http2/&#34;&gt;excellent demonstration&lt;/a&gt; of the benefits of
HTTP/2, and it can show speed improvements of 2-3x in a typical environment. On top of being faster,
HTTP/2 uses fewer connections which results in less resource overhead on both the server and the
client.&lt;/p&gt;
&lt;h3 id=&#34;so-what-are-you-waiting-for&#34;&gt;So what are you waiting for?&lt;/h3&gt;
&lt;p&gt;If you run a website and aren’t using HTTPS, &lt;a href=&#34;https://certbot.eff.org/&#34;&gt;give it a try&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    <entry>
        <title>Automatic reverse proxying with Docker and nginx</title>
        <link href="https://chameth.com/docker-automatic-nginx-proxy/"/>
        <updated>2016-05-21T00:00:00Z</updated>
        <id>https://chameth.com/docker-automatic-nginx-proxy/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/docker-automatic-nginx-proxy/logo.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/docker-automatic-nginx-proxy/logo.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/docker-automatic-nginx-proxy/logo.png&#34; alt=&#34;The Docker project logo&#34; loading=&#34;lazy&#34; width=&#34;271&#34; height=&#34;242&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;The Docker project logo&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Over the past few weeks I’ve gradually been migrating services from running in LXC containers to
Docker containers. It takes a while to get into the right mindset for Docker - thinking of
containers as basically immutable - especially when you’re coming from a background of running
things without containers, or in “full” VM-like containers. Once you’ve got your head around that,
though, it opens up a lot of opportunities: Docker doesn’t just provide a container platform, it
turns software into discrete units with a defined interface.&lt;/p&gt;
&lt;p&gt;With all of your software suddenly having a common interface, it becomes trivial to automate a lot
of things that would be tedious or complicated otherwise. You don’t need to manage port forwards
because the containers just declare their ports, for example. You can also apply labels to the
application containers, and then query the labels through Docker’s API.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h3 id=&#34;reverse-proxying-and-ssl-termination-with-nginx-and-lets-encrypt&#34;&gt;Reverse proxying and SSL termination with Nginx and Let’s Encrypt&lt;/h3&gt;
&lt;p&gt;A fairly significant chunk of the software I run has a web interface. I don’t really want to
expose and remember dozens of non-standard ports, so I configure an nginx instance as a reverse
proxy. I’m of the opinion that &lt;a href=&#34;https://www.eff.org/encrypt-the-web&#34;&gt;all web traffic should be encrypted&lt;/a&gt;,
so I also have to provide nginx with trusted certificates to use for each site it reverse proxies.
&lt;a href=&#34;https://letsencrypt.org/&#34;&gt;Let’s Encrypt&lt;/a&gt; makes the process of obtaining free, trusted certificates
approximately a thousand times easier than it was previously, but my workflow still ends up looking
like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new config file from a template and save it in &lt;code&gt;/etc/nginx/sites-available&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Temporarily disable SSL for the site as there’s no valid certificate yet&lt;/li&gt;
&lt;li&gt;Enable the site by symlinking to it from &lt;code&gt;/etc/nginx/sites-enabled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Reload nginx&lt;/li&gt;
&lt;li&gt;Run the Let’s Encrypt client to obtain certificates&lt;/li&gt;
&lt;li&gt;Enable SSL and for the site&lt;/li&gt;
&lt;li&gt;Reload nginx&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;… And that’s not including the extra steps when I miss a semi-colon, accidentally skip a step and
have to spend time figuring out why it’s not working, or any of the other human-induced problems
that creep in.&lt;/p&gt;
&lt;p&gt;I’d been toying with making a script to run through these steps manually for me, if I gave it a
domain name and a reverse proxy target, but I never got around to it. Now I’m moving things to
Docker, though, there’s an opportunity to automate the entire thing with no human interaction at
all.&lt;/p&gt;
&lt;h3 id=&#34;existing-solutions&#34;&gt;Existing solutions&lt;/h3&gt;
&lt;p&gt;It seemed like this probably wasn’t a unique idea, so I had a look around for existing solutions.
The most popular by far seems to be &lt;a href=&#34;https://github.com/jwilder/nginx-proxy&#34;&gt;nginx-proxy&lt;/a&gt; by
Jason Wilder. This is based on his &lt;a href=&#34;https://github.com/jwilder/docker-gen&#34;&gt;docker-gen&lt;/a&gt; project
that takes a template and populates values from docker containers.&lt;/p&gt;
&lt;p&gt;It’s a good solution, but there were a few bits I didn’t like. Firstly, templates don’t really lend
themselves well to every step of the process: to request Let’s Encrypt certificates, the
container uses a template to create a shell script which it then sources. Each container that
generates a template also needs access to the Docker socket. Both of those cause an itch in the
back of my head and make me want to say phrases like “attack surface”. I don’t think there’s
actually a problem, but it doesn’t really sit well with me.&lt;/p&gt;
&lt;p&gt;Secondly, the whole system seems slightly too tightly coupled for my liking. The Let’s Encrypt
component needs to modify the nginx config in order to obtain the certificate, while the main
nginx component is also making different changes to add and remove sites. It feels like if it
doesn’t just work, it’s going to be difficult to debug and pry apart the different components.&lt;/p&gt;
&lt;p&gt;Another potential solution is &lt;a href=&#34;http://rancher.com/&#34;&gt;Rancher&lt;/a&gt;. This is a complete platform for
managing containers, and I’m fairly sure if configured right it can grab certificates from
Let’s Encrypt and do SSL termination using haproxy. I tried it for a bit but the whole platform
seemed a bit overkill for my purposes, and I didn’t want to invest the time I’d need to fully
understand it all.&lt;/p&gt;
&lt;h3 id=&#34;rolling-my-own&#34;&gt;Rolling my own&lt;/h3&gt;
&lt;p&gt;In the end I decided to roll my own solution. Here’s a high-level overview of how it all works:&lt;/p&gt;
&lt;figure class=&#34;image full&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/docker-automatic-nginx-proxy/reverse-proxy.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/docker-automatic-nginx-proxy/reverse-proxy.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/docker-automatic-nginx-proxy/reverse-proxy.png&#34; alt=&#34;Diagram showing components of a reverse proxy implementation&#34; loading=&#34;lazy&#34; width=&#34;961&#34; height=&#34;821&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Diagram showing components of a reverse proxy implementation&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As you probably noticed, there are quite a few containers involved. Each one performs a small,
well-defined task, and its output can easily be inspected in either a volume or a database. I
think there’s some similarity to piping commands together on a command line — it’s a lot
easier to reason about simpler commands like &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;cut&lt;/code&gt; and &lt;code&gt;tr&lt;/code&gt; than it would be one giant
command that combined them. And, if it does go wrong, you can inspect the pipe at each stage to
see where the problem is happening.&lt;/p&gt;
&lt;h4 id=&#34;service-reporter-and-etcd&#34;&gt;service-reporter and etcd&lt;/h4&gt;
&lt;p&gt;The first part of the chain is my &lt;a href=&#34;https://github.com/csmith/docker-service-reporter&#34;&gt;service-reporter&lt;/a&gt;
container. This uses the Docker API to get a list of containers, and store information about them
in etcd. Etcd is a distributed key-value store (similar in some ways to redis or memcached).
The container also watches for containers that are added and removed, and keeps etcd updated
appropriately.&lt;/p&gt;
&lt;p&gt;As the service metadata is stored in a database, no other part of the system needs to interact
with Docker. If the Docker API changes, or the host configuration changes, then only this container
has to be updated.&lt;/p&gt;
&lt;h4 id=&#34;service-letsencrypt-and-letsencrypt-lexicon&#34;&gt;service-letsencrypt and letsencrypt-lexicon&lt;/h4&gt;
&lt;p&gt;The left fork of the diagram deals with obtaining SSL certificates. To keep it separate from the
nginx configuration, it uses DNS-based challenge to prove that we control the domains. It does this
by plumbing together two great open source projects:
&lt;a href=&#34;https://github.com/lukas2511/letsencrypt.sh&#34;&gt;letsencrypt.sh&lt;/a&gt;, a Let’s Encrypt client implemented
in bash with support for the dns-01 challenge type, and
&lt;a href=&#34;https://github.com/AnalogJ/lexicon&#34;&gt;Lexicon&lt;/a&gt;, a python library for updating DNS records using a
variety of providers.&lt;/p&gt;
&lt;p&gt;My &lt;a href=&#34;https://github.com/csmith/docker-service-letsencrypt&#34;&gt;service-letsencrypt&lt;/a&gt; container connects
to etcd and pulls a list of containers that have a label with the key &lt;code&gt;com.chameth.vhost&lt;/code&gt;. It uses
this to build a plain text list of certificates we require (in a format understood by
letsencrypt.sh), and then monitors etcd for changes and repeats as necessary.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/csmith/docker-letsencrypt-lexicon&#34;&gt;letsencrypt-lexicon&lt;/a&gt; container runs
letsencrypt.sh, using Lexicon to perform the required DNS updates, and produces certificates.
The nice thing about this is that it can be used in a completely standalone fashion (you can just
write a domains.txt yourself). It uses &lt;code&gt;iowait&lt;/code&gt; to watch the domains text file for updates, and
automatically reruns when there are changes. It also runs once a day to renew any certs that are
coming up for expiry.&lt;/p&gt;
&lt;h4 id=&#34;service-nginx-and-nginx&#34;&gt;service-nginx and nginx&lt;/h4&gt;
&lt;p&gt;The right fork of the diagram is concerned with nginx. My
&lt;a href=&#34;https://github.com/csmith/docker-service-nginx&#34;&gt;service-nginx&lt;/a&gt; container again connects to etcd
and pulls a list of containers. It uses a couple of labels to determine the vhost, proxy port,
and proxy protocol. It then feeds these values into a template to create a &lt;code&gt;server&lt;/code&gt; block for
each site, configured with SSL certificates and a reverse proxy setup. The template covers only
the very minimal settings, with the expectation that everything else will be done in the global
config (things such as SSL ciphers, redirection from HTTP, etc).&lt;/p&gt;
&lt;p&gt;This container works completely independently of the Let’s Encrypt side. You &lt;em&gt;can&lt;/em&gt; use the
Let’s Encrypt containers and mount the certificate volume, or you could just provide your own
certificates. It doesn’t really make any difference.&lt;/p&gt;
&lt;h3 id=&#34;putting-it-all-together&#34;&gt;Putting it all together&lt;/h3&gt;
&lt;p&gt;The only downside to having many small containers is that it’s a bit of a nuisance to get them
all set up. Fortunately, Docker has a solution for this in the form of
&lt;a href=&#34;https://docs.docker.com/compose/&#34;&gt;Docker compose&lt;/a&gt;. This allows you to write a YAML file defining
all of the services you want to run, and bring them up or down in one go. It can handle volumes,
dependencies, networking, etc. I’ll be publishing a docker-compose.yml file to get this entire
stack up and running soon.&lt;/p&gt;
</content>
    </entry>
</feed>
