<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" >

  <title>Erik L. Arneson — Writer and Software Developer</title>
  <subtitle>Erik L. Arneson is a freelance writer and software developer with WordPress experience. He is located in Portland, Oregon.</subtitle>
  <generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator>
  <link href="https://arnesonium.com/feeds/yaml.xml" rel="self" type="application/atom+xml" />
  <link href="https://arnesonium.com/" rel="alternate" type="text/html" />
  <updated>2026-06-18T15:03:10+00:00</updated>
  <id>https://arnesonium.com/feeds/yaml.xml</id>
  <author>
    <name>Erik L. Arneson</name>
  </author>
      <entry>
        
        <title>A Poor-Man&apos;s Dynamic DNS with Ansible and Amazon Route53</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2016/07/a-poor-mans-dynamic-dns-with-ansible-and-amazon-route53/" rel="alternate" type="text/html" title="A Poor-Man's Dynamic DNS with Ansible and Amazon Route53" />
        <updated>2016-07-21T16:33:45+00:00</updated>
        <id>https://arnesonium.com/2016/07/a-poor-mans-dynamic-dns-with-ansible-and-amazon-route53</id>
          <category term="amazon-web-services" />
        
          <category term="ansible" />
        
          <category term="aws" />
        
          <category term="devops" />
        
          <category term="networking" />
        
          <category term="route53" />
        
          <category term="yaml" />
        <content type="html" xml:base="https://arnesonium.com/2016/07/a-poor-mans-dynamic-dns-with-ansible-and-amazon-route53/">&lt;p&gt;I wanted to be able to configure a DNS hostname dynamically, but couldn’t find an easy-to-use dynamic DNS client that suited my needs. Using &lt;a href=&quot;http://ansible.com/&quot;&gt;Ansible&lt;/a&gt; and &lt;a href=&quot;https://aws.amazon.com/route53/&quot;&gt;Amazon Route53&lt;/a&gt;, I put together a quick, effective solution.
&lt;!--more--&gt;&lt;/p&gt;

&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;/h2&gt;

&lt;p&gt;First, you need an AWS account with a Route53 DNS zone. I followed &lt;a href=&quot;https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/CreatingNewSubdomain.html&quot;&gt;these directions to create a subdomain&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, you need a remote host that accessible via SSH. On that host, install Python and the &lt;a href=&quot;https://github.com/boto/boto&quot;&gt;Boto library&lt;/a&gt;. Make sure that Boto is configured with sufficient AWS credentials to access and change your Route53 zone.&lt;/p&gt;

&lt;h2 id=&quot;ansible-configuration&quot;&gt;Ansible Configuration&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This section was updated on 2016-11-29 to reflect improvements I’ve made in the Ansible playbook.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ansible made this task simple. In fact, the playbook below is mostly based on example recipes from the &lt;a href=&quot;https://docs.ansible.com/ansible/route53_module.html&quot;&gt;Ansible Route53 module documentation&lt;/a&gt;. The YAML playbook should look like the example below. Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YOUR-ROUTE53-ZONE&lt;/code&gt; with the zone you configured in Route53. Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YOUR-FULL-DYNAMIC-HOSTNAME&lt;/code&gt; with the fully-qualified domain name that you’ll use for dynamic DNS.&lt;/p&gt;

&lt;p&gt;Note that this uses the &lt;a href=&quot;https://docs.ansible.com/ansible/ipify_facts_module.html&quot;&gt;ipify_facts Ansible module&lt;/a&gt;. You can use the default value or pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api_url&lt;/code&gt; like I’m doing in this example.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Update Dynamic IP&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;localhost&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dyn_zone&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;YOUR-ROUTE53-ZONE&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dyn_hostname&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;YOUR-FULL-DYNAMIC-HOSTNAME&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Get public IP&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;ipify_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;api_url=https://arnesonium.com/api/yourip.php&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;local&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Get existing host information&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dynip&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;route53&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;get&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;zone&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;A&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Delete existing host information&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ipify_public_ip != dynip.set.value&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;route53&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;delete&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;zone&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Create new host record&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ipify_public_ip != dynip.set.value&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;route53&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;create&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;zone&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;A&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;600&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;running-your-playbook&quot;&gt;Running Your Playbook&lt;/h2&gt;

&lt;p&gt;I named my playbook &lt;strong&gt;dyndns.yml&lt;/strong&gt;, so I run it with this shell command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ansible-playbook &lt;span class=&quot;nt&quot;&gt;-vv&lt;/span&gt; dyndns.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-vv&lt;/code&gt; increases the verbosity so you can see what’s going on.&lt;/p&gt;

&lt;h2 id=&quot;the-next-step&quot;&gt;The Next Step&lt;/h2&gt;

&lt;p&gt;Next, I need to convince this script to run every time my laptop’s network comes back online. I’m sure there’s a good way to do that, but I haven’t spent much time looking into it.&lt;/p&gt;

&lt;p&gt;Did this playbook work for you? Let me know! I’d love to get feedback on it.&lt;/p&gt;</content>
      </entry>
    
</feed>
