<?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/aws.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/aws.xml</id>
  <author>
    <name>Erik L. Arneson</name>
  </author>
      <entry>
        
        <title>Using Amazon S3 as a Nette Service</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2016/10/using-amazon-s3-as-a-nette-service/" rel="alternate" type="text/html" title="Using Amazon S3 as a Nette Service" />
        <updated>2016-10-26T22:17:16+00:00</updated>
        <id>https://arnesonium.com/2016/10/using-amazon-s3-as-a-nette-service</id>
          <category term="aws" />
        
          <category term="nette" />
        
          <category term="php" />
        
          <category term="programming" />
        
          <category term="s3" />
        
          <category term="web-development" />
        <content type="html" xml:base="https://arnesonium.com/2016/10/using-amazon-s3-as-a-nette-service/">&lt;p&gt;&lt;a href=&quot;https://nette.org/&quot;&gt;Nette&lt;/a&gt; is a popular web application framework for PHP. It is mostly pretty well documented and easy to use. Recently, I needed to upload media from a Nette application to &lt;a href=&quot;https://aws.amazon.com/s3/&quot;&gt;Amazon S3&lt;/a&gt;. This is how I created an S3 service for my Nette application. You will need to be familiar with Nette and have an existing Nette application to follow along.
&lt;!--more--&gt;&lt;/p&gt;

&lt;h1 id=&quot;installing-the-amazon-web-services-sdk&quot;&gt;Installing the Amazon Web Services SDK&lt;/h1&gt;

&lt;p&gt;Before anything will work, you will need to install the AWS SDK using Composer. Run the following command from your Nette project directory.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;php composer.phar require aws/aws-sdk-php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;the-s3uploader-service&quot;&gt;The S3Uploader Service&lt;/h1&gt;

&lt;p&gt;Next, create the file &lt;strong&gt;app/model/S3Uploader.php&lt;/strong&gt; and edit it to look like the following. You can also download my version &lt;a href=&quot;https://gist.github.com/pymander/a027523a7b9152660fac8e7bb4801c91&quot;&gt;from this link&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-php 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;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;App\Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Nette&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Aws\S3\S3Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;S3Uploader&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/** @var \Aws\S3\S3Client */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$s3client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/** @var string */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$accessKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$secretKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;putenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;AWS_ACCESS_KEY_ID=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$accessKey&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;putenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;AWS_SECRET_ACCESS_KEY=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$secretKey&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;\Aws\S3\S3Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;version&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;latest&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;region&apos;&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;us-west-2&apos;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * Upload a file to an S3 bucket
     *
     * @param string $key The key used for the uploaded object
     * @param string $file The filename to be uploaded
     * @param string $contentType The file&apos;s content type. This defaults to &quot;application/octet-stream&quot;
     *
     * @return string A URL to access the file publically.
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uploadPublic&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$contentType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;application/octet-stream&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;putObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;Bucket&apos;&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;Key&apos;&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;SourceFile&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;ContentType&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;ACL&apos;&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;public-read&apos;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getObjectUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getClient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getBucket&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;configuring-the-configurator&quot;&gt;Configuring the Configurator&lt;/h1&gt;

&lt;p&gt;Finally, the tricky part. You need to configure the &lt;a href=&quot;https://doc.nette.org/en/2.4/configuring&quot;&gt;Nette Configurator&lt;/a&gt; so it knows about your new service. Follow these directions.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Open &lt;strong&gt;app/config/config.neon&lt;/strong&gt; with your favorite text editor. At the end of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;services:&lt;/code&gt; section, add the following line.&lt;/p&gt;

    &lt;div class=&quot;language-conf 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;n&quot;&gt;s3client&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;App&lt;/span&gt;\&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;\&lt;span class=&quot;n&quot;&gt;S3Uploader&lt;/span&gt;(%&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;%, %&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;access_key&lt;/span&gt;%, %&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;secret_key&lt;/span&gt;%)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Open &lt;strong&gt;app/config/config.local.neon&lt;/strong&gt;. Find the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parameters:&lt;/code&gt; section and add this block to it. Replace “ACCESS_KEY” with your AWS access key, and “SECRET_KEY” with your AWS secret key. Set “BUCKET_NAME” to the bucket you’ll be using for your uploads.&lt;/p&gt;

    &lt;div class=&quot;language-conf 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;n&quot;&gt;s3client&lt;/span&gt;:
   &lt;span class=&quot;n&quot;&gt;access_key&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;ACCESS_KEY&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;secret_key&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;SECRET_KEY&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;BUCKET_NAME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;using-s3uploader&quot;&gt;Using S3Uploader&lt;/h1&gt;

&lt;p&gt;Open up the presenter file that will be using the S3Uploader service. You just need to add a few new lines.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Near the top of the file where you’re loading libraries, add this line.&lt;/p&gt;

    &lt;div class=&quot;language-php 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;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;App\Model\S3Uploader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You will need to change your constructor definition to include S3Uploader. Assuming you haven’t changed your constructor function too much, it will probably look like the following.&lt;/p&gt;

    &lt;div class=&quot;language-php 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;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Nette&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;\Database\Context&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$database&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;S3Uploader&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Finally, you can call the S3Uploader with a simple method call.&lt;/p&gt;

    &lt;div class=&quot;language-php 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;nv&quot;&gt;$objectUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$s3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;uploadPublic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$objectKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$filePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Good luck with S3Uploader. Please let me know in the comments how it is working for you. Note that this is an example and the finished product will probably be more sophisticated. However, this should get you started with using Amazon S3 in your Nette applications.&lt;/p&gt;</content>
      </entry>
    
      <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>
