Jekyll2020-05-06T00:16:09-04:00http://nickperanzi.com/feed.xmlnperanziPersonal website for my random thoughts and musings, along with tutorials that I hope will prove useful to someone!Nick PeranziDynamic DNS with Cloudflare API Tokens2019-05-05T22:03:00-04:002019-05-05T22:03:00-04:00http://nickperanzi.com/blog/cloudflare-ddns-with-token<p>When deploying <a href="https://www.wireguard.com/">WireGuard VPN</a> endpoints on Raspberry Pis at the various networks I need to access remotely, I needed a Dynamic DNS / DDNS solution to ensure I could reliably access these endpoints even if ISPs issued new WAN IP addresses. I stumbled across <a href="https://letswp.io/cloudflare-as-dynamic-dns-raspberry-pi/">this excellent tutorial</a> on letswp.io about using Cloudflare for a DDNS back-end; while it covered most of what I needed, I was a bit leery about exposing my Cloudflare Global API key to a script. So, I adapted their solution to use an API token instead. This should work on any *Nix-based machine, not just RPis.</p>
<p>You can find the full tutorial below, or get started right away by cloning the <a href="https://github.com/nperanzi/cloudflare-ddns">associated GitHub repo</a>.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before executing any steps below, you will need the following:</p>
<ol>
<li>A domain name that you own using cloudflare for DNS resolution (see <a href="https://support.cloudflare.com/hc/en-us/articles/201720164-Creating-a-Cloudflare-account-and-adding-a-website">this guide</a> for a quick how-to)</li>
<li>A <a href="https://www.raspberrypi.org/products/">Raspberry Pi</a> or other machine that will serve as the destination for any DDNS traffic. I use a Raspberry Pi 4 Model B, but there are numerous hardware variations that will work</li>
</ol>
<h2 id="getting-started">Getting Started</h2>
<p>You’ll want to create a directory where the script will be saved. You can place the script in any directory; this tutorial will assume you use <code class="language-plaintext highlighter-rouge">/opt/cloudflare-ddns/</code> as the root directory for the script and files. If you wish to use this directory, you can run the following commands as a user with <code class="language-plaintext highlighter-rouge">sudo</code> permissions (replace <code class="language-plaintext highlighter-rouge">nick</code> with your username):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> /opt
<span class="nb">sudo mkdir </span>cloudflare-ddns
<span class="nb">sudo chown </span>nick:nick cloudflare-ddns
</code></pre></div></div>
<p>You’ll also need to download the script itself; the easiest way to do this is to clone the GitHub repo associated with this tutorial (note: instructions assume you use GitHub over SSH). You will also need to make the script executable.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone git@github.com:nperanzi/cloudflare-ddns.git
<span class="nb">chmod</span> +x cloudflare-ddns/cloudflare-ddns.sh
</code></pre></div></div>
<h2 id="create-dns-records-and-api-token">Create DNS records and API Token</h2>
<p>Select a subdomain you wish to use to reach your server. For this tutorial, I will use <code class="language-plaintext highlighter-rouge">vpn.yourdomain.com</code> as the subdomain; in all code, replace this with your actual subdomain.</p>
<h3 id="create-a-dns-record-for-your-subdomain">Create a DNS record for your subdomain</h3>
<ol>
<li>On your <a href="https://dash.cloudflare.com/">Cloudflare Dashboard</a>, select the domain under which the subdomain will reside. In our example, you would select <code class="language-plaintext highlighter-rouge">yourdomain.com</code></li>
<li>Click on the DNS icon, which should bring you to the DNS Management page</li>
<li>If you do not already have an “A” record for <code class="language-plaintext highlighter-rouge">vpn.yourdomain.com</code>, create one now:
<ol>
<li>Click Add Record</li>
<li>Set Type to “A”, Name to <code class="language-plaintext highlighter-rouge">vpn</code> (or whatever you have chosen as your subdomain), IPv4 Address to anything (e.g., <code class="language-plaintext highlighter-rouge">123.456.789.10</code>), and TTL to Auto</li>
<li>Click the orange cloud under Proxy Status; your record should now look like this:
<img src="/assets/images/subdomain-setup.png" alt="Subdomain Setup" /></li>
<li>Click Save</li>
</ol>
</li>
</ol>
<h3 id="create-an-api-token">Create an API Token</h3>
<p>We’ll create an API token that only has access to edit DNS records for this site; this helps ensure you are using the least-permissive API token for this task and provides some protection if the token is compromised.</p>
<ol>
<li>Return to the Cloudflare dashboard</li>
<li>Click the dopdown under My Profile, then click My Profile</li>
<li>Click the API tokens tab</li>
<li>Click the Create Token button</li>
<li>Click Get Started, then fill out the following fields:
<ul>
<li>Token name: <code class="language-plaintext highlighter-rouge">yourdomain-DDNS</code></li>
<li>Permissions: Zone -> Zone -> Read and Zone -> DNS -> Edit</li>
<li>Zone Resources: Include -> Specific Zone -> yourdomain.com</li>
</ul>
</li>
<li>Make sure all settings match below (with yourdomain.com selected under Zone Resources), then click Continue to summary.
<img src="/assets/images/API-token.png" alt="API Token Setup" /></li>
<li>Click Create Token</li>
<li>Copy the API token and change <code class="language-plaintext highlighter-rouge">paste-api-token-here</code> on line 9 of <code class="language-plaintext highlighter-rouge">cloudflare-ddns.sh</code> to your API token</li>
</ol>
<h2 id="change-the-other-script-parameters">Change the other script parameters</h2>
<h3 id="zone-id">Zone ID</h3>
<p>You’ll need to get the id that Cloudflare assigns to your domain and pass this parameter to the script. Fortunately, this is pretty straightforward:</p>
<ol>
<li>Return to the Cloudflare dashboard</li>
<li>Select the domain you’re using for DDNS (e.g., <code class="language-plaintext highlighter-rouge">yourdomain.com</code>)</li>
<li>Scroll down to the API section and you should see a link for Zone ID; copy this alphanumeric string (either directly or by clicking <code class="language-plaintext highlighter-rouge">Click to copy</code>) and change <code class="language-plaintext highlighter-rouge">paste-zone-id-here</code> on line 10 of <code class="language-plaintext highlighter-rouge">cloudflare-ddns.sh</code> to your Zone ID</li>
</ol>
<h3 id="record-name">Record Name</h3>
<p>Change <code class="language-plaintext highlighter-rouge">vpn.yourdomain.com</code> on line 11 of <code class="language-plaintext highlighter-rouge">cloudflare-ddns.sh</code> to your desired subdomain</p>
<h2 id="run-the-script">Run the script</h2>
<p>First, verify that all three setup parameters have been updated. Lines 9-11 of <code class="language-plaintext highlighter-rouge">cloudflare-ddns.sh</code> should NOT look like this anymore:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">auth_token</span><span class="o">=</span><span class="s2">"paste-api-token-here"</span>
<span class="nv">zone_id</span><span class="o">=</span><span class="s2">"paste-zone-id-here"</span>
<span class="nv">record_name</span><span class="o">=</span><span class="s2">"vpn.yourdomain.com"</span>
</code></pre></div></div>
<p>For example, these lines could look like:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">auth_token</span><span class="o">=</span><span class="s2">"gnR31pakO-yzKXuyOZfNhq-ptIviqUTWm2Ux4uLb"</span>
<span class="nv">zone_id</span><span class="o">=</span><span class="s2">"4adfa8d58a9c23e82edb1192f2a4c2d5"</span>
<span class="nv">record_name</span><span class="o">=</span><span class="s2">"vpn.myawesomedomain.io"</span>
</code></pre></div></div>
<p>If all paramters have been updated, run the script: <code class="language-plaintext highlighter-rouge">./cloudflare-ddns/cloudflare-ddns.sh</code>; if all goes well, you will see output like:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">IP changed to: 123.456.789.10
</span></code></pre></div></div>
<p>Check the DNS record for <code class="language-plaintext highlighter-rouge">vpn.yourdomain.com</code> on Cloudflare; the “A” record for <code class="language-plaintext highlighter-rouge">vpn</code> should now show your server IP under Content.
<em>Note: running the script again should produce no output to the console, because the IP is only updated when it differs from the current machine’s IP. This is normal.</em></p>
<h2 id="set-up-cron-to-run-the-script-at-regular-intervals">Set up cron to run the script at regular intervals</h2>
<p>Once the script runs as planned and updates the IP correctly, you’ll want to automate this so you don’t have to manually run it each time your IP changes.
Create a new cron job to run this automatically by running the below command in the terminal:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>crontab <span class="nt">-e</span>
</code></pre></div></div>
<p>Add a new line that looks something like the below:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 <span class="k">*</span>/6 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /bin/bash /opt/cloudflare-ddns/cloudflare-ddns.sh
</code></pre></div></div>
<p>The exact line above will run the script every 6 hours; if you’d like to customize this, check out <a href="https://www.ostechnix.com/a-beginners-guide-to-cron-jobs/">this tutorial</a> on cron.</p>
<p>That it! You now have dynamic DNS set up through Cloudflare, with no need to manually update your server’s public IP.</p>Nick PeranziUse Cloudflare for DDNS without using your Global API key.