<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Joe Nyland</title>
    <description>I&apos;m a developer, geek, mountain biker and dog lover from Northwich, UK and this is my site!</description>
    <link>https://joe.nyland.io</link>
    <atom:link href="https://joe.nyland.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 16 Dec 2025 10:54:36 +0000</pubDate>
    <lastBuildDate>Tue, 16 Dec 2025 10:54:36 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Send mail from Postfix on a BT Home broadband connection</title>
        <excerpt>How to send mail from Postfix on a BT Home broadband connection via their smarthost</excerpt>
        <description>&lt;p&gt;In order to send email out from a BT Home Broadband connection, you must use the smarthost that BT provide. Failure to
use this usually means that mail is rejected on the receiving mail server(s) as BT’s dynamic IP address ranges are
blacklisted.&lt;/p&gt;

&lt;p&gt;Postfix is my MTA of choice and I recently needed to setup a new box to send email out from my broadband connection.
Unfortunately, it took longer than necessary to piece together all the bits of info I needed to successfully send email
out, so I thought I would document it here.&lt;/p&gt;

&lt;p&gt;First, you need to ensure that you have setup a BT Email account.
&lt;a href=&quot;https://www.bt.com/appsconsumeraccount/secure/manageEmailAccounts.do&quot; data-proofer-ignore=&quot;&quot;&gt;Click here&lt;/a&gt; and
create yourself an email address, if you’ve not already got one in your BT account. You need to make sure that you
record a copy of the email and password that you create as this will be used by Postfix to authenticate with the BT
smarthost.&lt;/p&gt;

&lt;p&gt;The following steps have been tested on CentOS 7 and Ubuntu 14.04 LTS so they should be pretty portable. I will assume
that you have Postfix installed on your system. If you need to install Postfix, Google it :blush:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Run all of the following commands as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo -i&lt;/code&gt;)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Let’s export some variables that will be used in the config. Replace the values below with the email address and
password you just created above:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BT_EMAIL_ADDRESS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;my_bt_email_username@btinternet.com
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BT_EMAIL_PASSWORD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;my_bt_email_password&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Next we configure Postfix to use the BT smarthost and how it should authenticate with it:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;postconf &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relayhost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[mail.btinternet.com]:587&quot;&lt;/span&gt;
postconf &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;smtp_sasl_auth_enable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;yes
&lt;/span&gt;postconf &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;smtp_sasl_password_maps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hash:/etc/postfix/sasl_passwd&quot;&lt;/span&gt;
postconf &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;smtp_sasl_security_options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;noanonymous&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Next up, we create or append to a password file which we will contain the credentials needed to authenticate
with the smart host:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/postfix/sasl_passwd &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
[mail.btinternet.com]:587 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BT_EMAIL_ADDRESS&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BT_EMAIL_PASSWORD&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chown &lt;/span&gt;root:root /etc/postfix/sasl_passwd  &lt;span class=&quot;c&quot;&gt;# For security, root should own this file&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;chmod &lt;/span&gt;0600 /etc/postfix/sasl_passwd       &lt;span class=&quot;c&quot;&gt;# Only allow owner read+write&lt;/span&gt;
postmap /etc/postfix/sasl_passwd          &lt;span class=&quot;c&quot;&gt;# Generate the hash DB that Postfix expects&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Optional: &lt;strong&gt;Running CentOS?&lt;/strong&gt; You will need to install an additional package:&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;yum &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;cyrus-sasl-plain &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Apply the changes to Postfix:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;service postfix start&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; postfix reload&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Test! (Replace with your email at the end)&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hi! This is a test from Postfix via BT.&quot;&lt;/span&gt; | sendmail some_external_email@example.com&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you don’t receive the test email, check &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mailq&lt;/code&gt; and the mail log file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /var/log/mail.log &lt;span class=&quot;c&quot;&gt;# Ubuntu/Debian&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /var/log/maillog  &lt;span class=&quot;c&quot;&gt;# CentOS&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
        <pubDate>Wed, 14 Dec 2016 00:00:00 +0000</pubDate>
        <link>https://joe.nyland.io/blog/send-mail-from-postfix-on-a-bt-home-broadband-connection/</link>
        <guid isPermaLink="true">https://joe.nyland.io/blog/send-mail-from-postfix-on-a-bt-home-broadband-connection/</guid>
        
        
      </item>
    
      <item>
        <title>Debug a PHP app in a Docker container with Xdebug</title>
        <excerpt>Docker is awesome, but this was a pain to setup!</excerpt>
        <description>&lt;p&gt;Recently, I decided that I was going to learn more about &lt;a href=&quot;https://www.docker.com&quot;&gt;Docker&lt;/a&gt;. I’ve heard so many good things about
Docker over the past year or so, I figured I best take a look and decide for myself whether it was something I should
integrate into my workflow. In the past 6 months, &lt;a href=&quot;https://blog.docker.com/2016/07/docker-for-mac-and-windows-production-ready/&quot;&gt;Docker for Mac has been released&lt;/a&gt; too,
so this really sparked my interest.&lt;/p&gt;

&lt;p&gt;I was pleasantly surprised by how easy it was to get started with Docker. It felt very much like starting to learn Git.
It was so easy in fact, I began containerising all of my local development environments in order to expose myself to
Docker more, allowing me to learn more as I went along.&lt;/p&gt;

&lt;p&gt;In next to no time, I’d containerised most of the apps that I work on and I’d even built several multi-container
environments with Docker Compose, which is a really cool tool! Unfortunately, I faced a small but annoying complication
with Docker when I wanted to containerise a PHP app.&lt;/p&gt;

&lt;p&gt;I’m a big fan of the &lt;a href=&quot;https://www.jetbrains.com/products.html?fromMenu#type=ide&quot;&gt;JetBrains IDEs&lt;/a&gt;, so my IDE of choice when working with PHP apps is
&lt;a href=&quot;https://www.jetbrains.com/phpstorm/&quot;&gt;PhpStorm&lt;/a&gt;. One of the features of PhpStorm is the integrated debugger, allowing you to debug your apps
right from within the code base.&lt;/p&gt;

&lt;p&gt;Usually, when setting a up a LAMP development environment, I’ll setup &lt;a href=&quot;https://xdebug.org&quot;&gt;Xdebug&lt;/a&gt; too. Xdebug uses the DBGp
protocol to provide interactive debug sessions. For a PHP web app, roughly speaking the process is this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Browser submits a request to the server (sometimes including a special GET parameter in the query string to start
 the debugging session)&lt;/li&gt;
  &lt;li&gt;The server (running PHP with the Xdebug module loaded) attempts to connect to the host running the IDE (usually port
 9000 TCP) where an Xdebug client is listening for connections.&lt;/li&gt;
  &lt;li&gt;The IDE responds with commands that instruct Xdebug to continue execution of the code and commands to interrupt the
 execution of code at predefined breakpoints which are easily set my the developer right inside the editor window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The configuration required for Xdebug is something like this:&lt;/p&gt;

&lt;div class=&quot;language-ini 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;[xdebug]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;xdebug.remote_enable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;On&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;xdebug.remote_autostart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;On&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Usually when developing, the LAMP stack is running in a local environment on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost&lt;/code&gt;. This means that when the
request is received by the web server (we’ll assume Apache here), Xdebug can simply connect back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost&lt;/code&gt; to the
Xdebug client in the IDE.&lt;/p&gt;

&lt;p&gt;When the LAMP stack is running in a container though, &lt;a href=&quot;https://docs.docker.com/engine/userguide/networking/&quot;&gt;Docker’s network stack&lt;/a&gt; sits between the running processes inside
the container and the host machine that’s running Docker Machine. This means that when I run a web server in a
container, then open that site in my browser, the web server inside the container will see that the request originated
from a host with an IP like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.17.0.1&lt;/code&gt; which is the IP address of the host (Mac in my case) on the virtual network
stack that Docker runs on the host.&lt;/p&gt;

&lt;p&gt;If we look back up to how Xdebug works, the Xdebug module will need to connect back to the IDE on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.17.0.1&lt;/code&gt;,
using port 9000. Sadly, Docker for Mac doesn’t currently allow access to the host on this IP address from within the
container. This appears to be a known issue, mentioned &lt;a href=&quot;https://docs.docker.com/docker-for-mac/networking/#/known-limitations-use-cases-and-workarounds&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Run a simple demo app in a container:&lt;/li&gt;
&lt;/ul&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;docker run &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; php-demo &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 8080:80 php-web-app-debug-demo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;AH00558: apache2: Could not reliably determine the server&apos;s fully qualified domain name, using 172.17.0.2. Set the &apos;ServerName&apos; directive globally to suppress this message
AH00558: apache2: Could not reliably determine the server&apos;s fully qualified domain name, using 172.17.0.2. Set the &apos;ServerName&apos; directive globally to suppress this message
[Sun Oct 16 11:16:37.528569 2016] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.10 (Debian) PHP/5.6.26 configured -- resuming normal operations
[Sun Oct 16 11:16:37.528660 2016] [core:notice] [pid 1] AH00094: Command line: &apos;apache2 -D FOREGROUND&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Then try to access it:&lt;/li&gt;
&lt;/ul&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;curl localhost:8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;We see the request logged from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.17.0.1&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;172.17.0.1 - - [16/Oct/2016:11:26:25 +0000] &quot;GET / HTTP/1.1&quot; 200 321 &quot;-&quot; &quot;curl/7.49.1&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;If we try and connect back to the host running the IDE with Xdebug client from inside the container:&lt;/li&gt;
&lt;/ul&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;telnet 172.17.0.1 9000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Trying 172.17.0.1...
telnet: Unable to connect to remote host: Connection refused
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’re left in a sticky situation: we need to connect back to the IDE running on the Docker host from Xdebug running
inside the container, but there doesn’t seem to be a way to access it. There are a couple of networking options that
are available for running a container under, but none of them seem to alleviate this issue.&lt;/p&gt;

&lt;p&gt;I was able to find that whilst Docker containers are unable to connect back to the host through the NATed interface
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.17.x.x&lt;/code&gt;), they are able to communicate with the host using the LAN IP of the host, which is usually a DHCP
address issued by your home or office router/network infrastructure. For example, my Mac is running on my home network
and my router has issued it the address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.66&lt;/code&gt;. From within a container, I can connect back to PhpStorm running
the Xdebug client on port 9000 just fine!&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;telnet 192.168.1.66 9000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Trying 192.168.1.66...
Connected to 192.168.1.66.
Escape character is &apos;^]&apos;.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, this isn’t ideal. The address above is different for everyone and in order for Xdebug inside the container to
work, it needs to be told to connect back to the same IP that the request originated from, or it needs to be explicitly
told what address to connect to. This configuration will be baked into the image but if I enter my current IP address,
next time I launch a container from this instance I might have a different IP or someone else might launch a container
from the same image and Xdebug won’t work for them until they find out their IP, drop into a shell in the container and
change the Xdebug configuration, etc. This all detracts from one of the biggest advantages to using Docker: portability.&lt;/p&gt;

&lt;p&gt;So far, the best solution I have been able to find is to use an arbitrary hostname in the Xdebug configuration and
provide the value to this hostname on launching the container. This can be achieved using the following Xdebug configuration:&lt;/p&gt;

&lt;div class=&quot;language-ini 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;[xdebug]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;xdebug.remote_enable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;On&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;xdebug.remote_autostart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;On&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;xdebug.remote_connect_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Off&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;xdebug.remote_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;docker_host&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Rebuild the image with the above config included, then launch the container like so:&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;&lt;span class=&quot;c&quot;&gt;# Replace 192.168.1.66 with your actual LAN IP address&lt;/span&gt;
docker run &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; php-demo &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 8080:80 &lt;span class=&quot;nt&quot;&gt;--add-host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;docker_host:192.168.1.66&quot;&lt;/span&gt; php-web-app-debug-demo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With that in place, you should be able to set some breakpoints in yur PHP code, tell PhpStorm to listen for debug
connections, then request the site in your browser and be good to go!&lt;/p&gt;

&lt;p&gt;I’ve thrown together a quick demo of this. The repo holding the source can be found &lt;a href=&quot;https://github.com/JoeNyland/docker-php-web-app-debug-demo&quot;&gt;here&lt;/a&gt; and you can pull a Docker image containing a working Xdebug setup from the &lt;a href=&quot;https://hub.docker.com/r/joenyland/php-web-app-debug-demo/&quot;&gt;Docker Hub&lt;/a&gt; like so:&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;docker pull joenyland/php-web-app-debug-demo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;update&quot;&gt;Update&lt;/h3&gt;

&lt;p&gt;Since writing this post, I’ve found that the issue around connecting back to the Docker host isn’t possible out of the
box.&lt;/p&gt;

&lt;p&gt;The issue with the above workaround is that it’s dependent on a potentially ever changing IP address. Another issue is
that you may not have LAN IP address, for example you’re not connected to any networks and are working offline.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://docs.docker.com/docker-for-mac/networking/#/use-cases-and-workarounds&quot;&gt;Docker for Mac network notes&lt;/a&gt; mention the known issues with Docker for Mac and in there, there’s a suggestion to add
an alias address to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lo0&lt;/code&gt; interface on your Mac. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lo0&lt;/code&gt; is a loopback interface that’s always available on your Mac,
regardless of whether or not you’re connected to a WiFi network. If you’re not connected to a network, you can use the
above workaround I’ve talked about, but instead of using the LAN address, use a new loopback alias address, which is
created like so:&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;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;ifconfig lo0 &lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;10.200.10.1/24
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then create a container, passing in the new IP address you just added to the loopback interface:&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;docker run &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; php-demo &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 8080:80 &lt;span class=&quot;nt&quot;&gt;--add-host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;docker_host:10.200.10.1&quot;&lt;/span&gt; joenyland/php-web-app-debug-demo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s still annoying that we can’t just use the &lt;a href=&quot;https://xdebug.org/docs/all_settings#remote_connect_back&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xdebug.remote_connect_back&lt;/code&gt;&lt;/a&gt;, but it seems to be
a known issue to the Docker for Mac team, so hopefully there may be a better solution in the future when the Docker
networking implementation on Macs improves.&lt;/p&gt;

</description>
        <pubDate>Sun, 16 Oct 2016 00:00:00 +0000</pubDate>
        <link>https://joe.nyland.io/blog/debug-a-php-app-in-a-docker-container-using-xdebug/</link>
        <guid isPermaLink="true">https://joe.nyland.io/blog/debug-a-php-app-in-a-docker-container-using-xdebug/</guid>
        
        
      </item>
    
      <item>
        <title>How to install a Ruby Gem from a custom source via Puppet</title>
        <excerpt>Recently, I needed to install a Ruby gem from a custom source via Puppet and here&apos;s how to do it.</excerpt>
        <description>&lt;p&gt;Here’s the situation: You’ve written a &lt;a href=&quot;https://github.com/JoeNyland/cautious-potato&quot;&gt;Ruby gem&lt;/a&gt; that you want to install on a server, but you don’t really have any
need to share the gem with the world via &lt;a href=&quot;https://rubygems.org&quot;&gt;RubyGems.org&lt;/a&gt;. It’s a custom gem with bespoke code
that no one would benefit from. You’ve pushed the gem to your Gem server and you use Puppet to manage your
servers.&lt;/p&gt;

&lt;p&gt;Here’s a simple, example Puppet manifest, showing how to install gem via Puppet from a custom source:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-puppet&quot; data-lang=&quot;puppet&quot;&gt;&lt;span class=&quot;c&quot;&gt;# manifest.pp
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;cautious-potato&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;gem&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;http://mygemserver.com&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;0.1.0&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then apply that manifest:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;puppet apply &lt;span class=&quot;nt&quot;&gt;--test&lt;/span&gt; manifest.pp&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;…and you should see version 0.1.0 of the gem installed from your own Gem server!&lt;/p&gt;

&lt;p&gt;It took me a while to figure this out and I only worked out how to do it whilst reading through the
&lt;a href=&quot;https://github.com/puppetlabs/puppet/blob/master/lib/puppet/provider/package/gem.rb&quot;&gt;source of the Gem Package provider in Puppet&lt;/a&gt;. I hope this saves others from wasting too much time
on working out how to do this, like I did!&lt;/p&gt;

</description>
        <pubDate>Fri, 20 May 2016 00:00:00 +0000</pubDate>
        <link>https://joe.nyland.io/blog/how-to-install-a-ruby-gem-from-git-repo-via-puppet/</link>
        <guid isPermaLink="true">https://joe.nyland.io/blog/how-to-install-a-ruby-gem-from-git-repo-via-puppet/</guid>
        
        
      </item>
    
      <item>
        <title>GitHub Pages may soon support SSL!</title>
        <excerpt>Looks like GitHub are testing SSL support of GitHub Pages.</excerpt>
        <description>&lt;p&gt;I was checking out some settings on my GitHub account today and I noticed in the
&lt;a href=&quot;https://github.com/settings/security&quot;&gt;Security section&lt;/a&gt;, several messages like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/posts/github-pages-may-soon-support-ssl/security_log.png&quot; alt=&quot;Security log screenshot&quot; class=&quot;security-log-screenshot center img-responsive img-rounded&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Hmm… &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repo.pages_https_redirect_disabled&lt;/code&gt; …I don’t remember changing that setting. I don’t even know where that
setting is! I reached out to the awesome GitHub support team and they tell me that they’ve been working on an
“experimental” feature: :grinning:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Sorry for the audit log noise! An experimental feature was accidentally enabled for your repository…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, it looks like we &lt;em&gt;may&lt;/em&gt; be seeing SSL on GitHub Pages sometime soon!&lt;/p&gt;
</description>
        <pubDate>Wed, 18 May 2016 00:00:00 +0000</pubDate>
        <link>https://joe.nyland.io/blog/github-pages-may-soon-support-ssl/</link>
        <guid isPermaLink="true">https://joe.nyland.io/blog/github-pages-may-soon-support-ssl/</guid>
        
        
      </item>
    
      <item>
        <title>I&apos;m doing the Manchester to Blackpool charity bike ride</title>
        <excerpt>What better way to raise money for charity?</excerpt>
        <description>&lt;p&gt;Recently, I’ve been trying to get back into my mountain biking. It’s been tough, because I’ve been
out of it for around 12 months now. I gave up cycling all together last year, following a rough patch with my
depression. I completely gave it up: sold all by gear, all my bikes and vowed that I would never cycle again …and I
didn’t. Fast forward 10 months and I was managing my depression and the hunger to ride was building once again!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/posts/manchester-to-blackpool-charity-bike-ride/leeds-ride.jpg&quot; alt=&quot;Joe mountain biking near Leeds&quot; class=&quot;joe-leeds-ride center img-responsive img-rounded&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A week or so ago, an email was sent around the office at work asking if anyone was interested in doing the Manchester
to Blackpool charity bike ride. I’m not a massively confident person and I have terrible trouble with my head telling me
a million reasons why I wouldn’t be able to overcome a challenge, but I’ve got really good at managing that thought now.
18-24 months ago I would never have said that I’d have the courage to ride from Manchester to Blackpool; the negative
thoughts would creep in and talk me out of it well before I managed to sign up for a ride like that. Now, though, I’ve
been able to battle through that and sign myself up to the do the ride!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.christie.nhs.uk/the-christie-charity&quot; target=&quot;_blank&quot;&gt;&lt;image src=&quot;http://www.christie.nhs.uk/Content/img/global/charity-logo-full.png&quot; alt=&quot;The Christie Charity&quot; class=&quot;center img-responsive the-christie-charity&quot;&gt;&lt;/image&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The bike ride is in aid of &lt;a href=&quot;http://www.christie.nhs.uk/the-christie-charity&quot;&gt;The Christie Charity&lt;/a&gt; and is a 60 mile ride from the Imperial War
Museum in Trafford, Manchester to the South Promenade, Blackpool. Those 60 miles will take us through Leigh, Wigan,
Preston, Warton and into Blackpool. Admittedly, I’m apprehensive, but I’m actually quite looking forward to it. It will
be a challenge, but I’m looking forward to overcoming it and raising some money for
&lt;a href=&quot;http://www.christie.nhs.uk/the-christie-charity&quot;&gt;The Christie Charity&lt;/a&gt; along the way! I will be joining “The Greenhouse” team from
&lt;a href=&quot;http://www.mediacityuk.co.uk&quot;&gt;MediaCityUK&lt;/a&gt; who will be raising money for the charity too!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/posts/manchester-to-blackpool-charity-bike-ride/map.png&quot; alt=&quot;A map of the route&quot; class=&quot;map-of-route center img-responsive img-rounded&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Please sponsor me!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.justgiving.com/JoeNyland&quot; title=&quot;JustGiving - Sponsor me now!&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.justgiving.com/App_Themes/JustGiving/images/badges/badge10.gif&quot; width=&quot;270&quot; height=&quot;50&quot; alt=&quot;JustGiving - Sponsor me now!&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All donations will go straight to &lt;a href=&quot;http://www.christie.nhs.uk/the-christie-charity&quot;&gt;The Christie Charity&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;update-10072016-tada-dancer-confetti_ball&quot;&gt;Update 10/07/2016 :tada: :dancer: :confetti_ball:&lt;/h3&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;I&amp;#39;ve done it!!! 💪🚴😅 &lt;a href=&quot;https://t.co/Al4tHR0Lu6&quot;&gt;pic.twitter.com/Al4tHR0Lu6&lt;/a&gt;&lt;/p&gt;&amp;mdash; Joe Nyland (@JoeNyland) &lt;a href=&quot;https://twitter.com/JoeNyland/status/752111514564395008&quot;&gt;July 10, 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;I completed the ride today! I raised £175 for &lt;a href=&quot;http://www.christie.nhs.uk/the-christie-charity&quot;&gt;The Christie Charity&lt;/a&gt;, which is well above the
£50 target I set myself when I signed up for the ride. Thank you to everyone who donated. The money you have donated
will all go to a good cause.&lt;/p&gt;

</description>
        <pubDate>Fri, 13 May 2016 00:00:00 +0000</pubDate>
        <link>https://joe.nyland.io/blog/i-m-doing-the-manchester-to-blackpool-charity-bike-ride/</link>
        <guid isPermaLink="true">https://joe.nyland.io/blog/i-m-doing-the-manchester-to-blackpool-charity-bike-ride/</guid>
        
        
      </item>
    
      <item>
        <title>Homesick Bash completion</title>
        <excerpt>I decided to write my own Bash completion script for Homesick.</excerpt>
        <description>&lt;p&gt;Your dotfiles hold a lot of stuff in them: You’ve most probably spent a while accumulating handy Bash functions,
config and variables and that all gets stored in lots of hidden files that live in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$HOME&lt;/code&gt; directory. If you change
machines maybe between home and work or you like to keep everything version controlled for peace of mind, or you just
:heart: Git (like me), I recommend you check out &lt;a href=&quot;https://github.com/technicalpickles/homesick&quot;&gt;Homesick&lt;/a&gt; by &lt;a href=&quot;https://github.com/technicalpickles&quot;&gt;Josh Nicols&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I use it a hell of a lot for all of &lt;a href=&quot;https://github.com/JoeNyland/dotfiles&quot;&gt;my dotfiles&lt;/a&gt;, but one thing that I feel it’s missing out-of-the-box
is Bash completion. I &lt;em&gt;mash&lt;/em&gt; my tab button all day and all night and when a command doesn’t respond to my furious
tabbing, it makes me feel sad that I’m going to have to use a whole lotta energy to think what parameters I want to
give a command and the path to a file, etc. It really is awful :wink:&lt;/p&gt;

&lt;p&gt;So, I thought: “I use Homebrew all the time and it’s never cost me a penny, so why not give something back and write
my own Bash completion?” That’s just what I did!&lt;/p&gt;

&lt;p&gt;You can install with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;brew tap homebrew/completions &lt;span class=&quot;c&quot;&gt;# Tap the homebrew-completions repo&lt;/span&gt;
brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;homesick-completion&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is my first Bash completion script that I’ve written. Previous to this, I had no idea how packages allowed you to
tab complete stuff so this was a really interesting exercise to find out how it’s done, whilst doing something useful
at the same time!&lt;/p&gt;

&lt;p&gt;You can find the repo on GitHub &lt;a href=&quot;https://github.com/JoeNyland/homesick-completion&quot;&gt;here&lt;/a&gt;. If you’ve git any ideas for improvements, feel free
to submit a &lt;a href=&quot;https://github.com/JoeNyland/homesick-completion/pulls&quot;&gt;pull request&lt;/a&gt;, or if you get any problems, open up an &lt;a href=&quot;https://github.com/JoeNyland/homesick-completion/issues&quot;&gt;issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this helps someone out!&lt;/p&gt;

</description>
        <pubDate>Sat, 07 May 2016 00:00:00 +0000</pubDate>
        <link>https://joe.nyland.io/blog/homesick-bash-completion/</link>
        <guid isPermaLink="true">https://joe.nyland.io/blog/homesick-bash-completion/</guid>
        
        
      </item>
    
      <item>
        <title>GitHub Pages with Git LFS</title>
        <excerpt>A word of warning, if you&apos;d like to use Git LFS with GitHub Pages.</excerpt>
        <description>&lt;p&gt;Recently, I decided to take another look at &lt;a href=&quot;https://git-lfs.github.com&quot;&gt;Git LFS&lt;/a&gt;. I was blown away by the simplicity of
the extension to the already awesome Git VCS but also the ease of use of GitHub’s implementation of the feature.&lt;/p&gt;

&lt;p&gt;&lt;img id=&quot;git-lfs-graphic&quot; src=&quot;/assets/img/posts/github-pages-with-git-lfs/git-lfs-graphic.gif&quot; alt=&quot;A diagram showing how Git LFS works&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Git LFS allows you to store large like binary files, assets and other files that you don’t want to clog up a Git repo
and store them on a storage network like the one provided by &lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;. You can get a bit more of an
understanding on what Git LFS is &lt;a href=&quot;https://git-lfs.github.com&quot;&gt;here&lt;/a&gt;. It’s really easy to install and setup - just follow the instructions
on the site.&lt;/p&gt;

&lt;p&gt;Previously, &lt;a href=&quot;/blog/so_im_using_jekyll_to_run_my_blog/&quot;&gt;I’ve blogged about my site&lt;/a&gt; telling you all about how wonderful Jekyll is on
GitHub Pages. When I found out how great Git LFS is, I naturally wanted to know if I could use Git LFS to store assets
for my sites, such as Photoshop assets, large images, PDFs, etc. Through trial and error, I found that GitHub Pages
does not allow you to serve assets from Git LFS in your GitHub Pages site, which is a little disappointing. :disappointed:&lt;/p&gt;

&lt;p&gt;I turned to Uncle Google to make sure that there wasn’t a workaround for this that I hadn’t thought of, but all I
found was &lt;a href=&quot;https://github.com/github/git-lfs/issues/791&quot;&gt;this&lt;/a&gt;. So it seems (&lt;a href=&quot;https://github.com/github/git-lfs/issues/791#issuecomment-151318020&quot;&gt;from a GitHub employee&lt;/a&gt;) that Git LFS is not
supported by GitHub Pages, outright. Sad, because it would be great!&lt;/p&gt;

&lt;p&gt;GitHub are a great company and in the past when I’ve had questions or queries, they’ve been most helpful. I decided to
ask them why they don’t support this feature, merely to satisfy my own curiosity. &lt;a href=&quot;https://github.com/jhosman&quot;&gt;Jess Hosman at GitHub&lt;/a&gt;
kindly replied to my email (really quickly! :grinning:):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hi Joe,&lt;/p&gt;

  &lt;p&gt;Thanks for getting in touch! LFS with GitHub Pages is something we’d love to support in the future, but still have some work to do to get us there. I’ll definitely pass this along to the team, and let them know you’d find that feature useful.&lt;/p&gt;

  &lt;p&gt;Thanks so much for the feedback, and let us know if you notice anything else that could be improved.&lt;/p&gt;

  &lt;p&gt;Cheers,&lt;/p&gt;

  &lt;p&gt;Jess&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, at least there’s hope that this feature will be supported by GitHub in the future - It wasn’t just a point blank
&lt;em&gt;“No!”&lt;/em&gt; that we come to expect from large companies like Apple and Google nowadays.&lt;/p&gt;

&lt;p&gt;This post is a little different from my recent posts as it’s less of a tutorial/how-to format and instead a more “FYI”
style post. Hopefully Google will index it and help others get to the conclusion I did, without having to waste too
much time. Furthermore, hopefully GitHub will implement this feature sooner rather than later!&lt;/p&gt;

</description>
        <pubDate>Fri, 29 Apr 2016 00:00:00 +0000</pubDate>
        <link>https://joe.nyland.io/blog/github-pages-with-git-lfs/</link>
        <guid isPermaLink="true">https://joe.nyland.io/blog/github-pages-with-git-lfs/</guid>
        
        
      </item>
    
      <item>
        <title>Running instances in a private subnet on Amazon EC2</title>
        <excerpt>How to run instances in a private subnet on Amazon EC2, whilst retaining internet connectivity for deploys and updates.</excerpt>
        <description>&lt;p&gt;For a while now, I’m been meaning to look into how best to setup &lt;a href=&quot;https://console.aws.amazon.com/ec2/&quot;&gt;EC2&lt;/a&gt; instances on &lt;a href=&quot;https://www.amazon.co.uk/&quot;&gt;Amazon’s&lt;/a&gt; cloud
computing platform &lt;a href=&quot;https://aws.amazon.com/&quot;&gt;AWS&lt;/a&gt; in a private subnet. In this post, I aim to explain how best to build a setup where your
“frontend” web server(s) or load balancer(s) are situated in a publicly accessible subnet and your application nodes
are in a private subnet that is not internet accessible.&lt;/p&gt;

&lt;h3 id=&quot;overview&quot;&gt;Overview&lt;/h3&gt;
&lt;p&gt;This setup is just one example of a security best practice and there are many, many other steps that you should take to
ensure the security of your stack. This particular practice ensures that the only part of your setup that is public
facing is a thin, dumb layer. This layer is usually in the form of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Load_balancing_(computing)&quot;&gt;load balancer&lt;/a&gt; but can just be a
simple &lt;a href=&quot;https://en.wikipedia.org/wiki/Reverse_proxy&quot;&gt;reverse proxying&lt;/a&gt; web server passing traffic between the untrusted public domain to the trusted
domain of the private subnet where your application servers are situated.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;app-load-balancer&quot; alt=&quot;An example setup&quot; src=&quot;/assets/img/posts/running-instances-in-a-private-subnet-on-amazon-ec2/app-load-balanced.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The idea being: you &lt;em&gt;must&lt;/em&gt; have an opening on to the internet, so let attackers do what they want with your public
facing load balancer. If they want to kill it, DDOS it, or whatever - it’s a throw away instance that does nothing
more than passing data between two interfaces and therefore can be terminated and a newly built (and security patched)
instance can be put in it’s place without taking the application servers down. What’s more: an attacker does not have
direct access to your app servers from the internet - they only get direct access to your load balancer or reverse
proxy which is much more secure. Again, this doesn’t garauntee an attacker won’t hop from the load balancer onto the
app server, but this can be mitigated with different users, SSH keys, etc. between the public subnet and the private
subnet. This is a little out of the scope of this post, though!&lt;/p&gt;

&lt;p&gt;Now, let’s get back on topic!&lt;/p&gt;

&lt;h3 id=&quot;amazon-vpc&quot;&gt;&lt;a href=&quot;https://console.aws.amazon.com/vpc/&quot;&gt;Amazon VPC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://console.aws.amazon.com/vpc/&quot;&gt;Amazon VPC&lt;/a&gt; is where we will carry out most of the work. It’s where you configure and manage you virtual
network on AWS’ infrastructure and it’s the network where your EC2 instances will run.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;vpc-screenshot&quot; alt=&quot;The VPC interface&quot; src=&quot;/assets/img/posts/running-instances-in-a-private-subnet-on-amazon-ec2/vpc-screenshot.png&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;vpcs&quot;&gt;VPCs&lt;/h4&gt;
&lt;p&gt;Login to AWS and load up the &lt;a href=&quot;https://console.aws.amazon.com/vpc/&quot;&gt;VPC Dashboard&lt;/a&gt;. Although it would be best to create a new VPC for the
purposes of this post, we will be building our setup in the default VPC of your AWS account. If I’m not
mistaken, AWS accounts automatically get a VPC setup for them out-of-the-box. Click “VPCs” in the VPC dashboard and
make sure that you’ve got at least one VPC setup and ready to go!&lt;/p&gt;

&lt;p&gt;If you’ve not got a VPC there, consult the &lt;a href=&quot;https://aws.amazon.com/documentation/vpc/&quot;&gt;AWS documentation&lt;/a&gt; on how to set one up.&lt;/p&gt;

&lt;p&gt;Whilst I’m writing this post, I’m using a test VPC called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test&lt;/code&gt; and I’ve configured to cover the IP range &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.0.0.0/16&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;internet-gateway&quot;&gt;Internet gateway&lt;/h4&gt;
&lt;p&gt;Next, we need to create an internet gateway. Think of this as your internet connection at home plugging into the back
of your home router.&lt;/p&gt;

&lt;p&gt;In the left of the VPC interface, click “Internet Gateways”, then click “Create Internet Gateway”. We’ll call this
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test-gateway&lt;/code&gt;, because it’s well, a test! When that’s been created, it should show up with a state of &lt;em&gt;detached&lt;/em&gt;. Select
it from the list then click the “Attach to VPC” button above. Select your VPC from the dropdown and click “Yes, Attach”.
In a few moments, your internet gateway should show as attached!&lt;/p&gt;

&lt;h4 id=&quot;subnets&quot;&gt;Subnets&lt;/h4&gt;
&lt;p&gt;Next up: Subnets! In the left of the AWS interface, under “Virtual Private Cloud”, hit “Subnets”. When the page loads,
you should see all the subnets in all of your VPCs.&lt;/p&gt;

&lt;p&gt;First, we’re going to create our &lt;span class=&quot;warn&quot;&gt;public subnet&lt;/span&gt;. This subnet is where we will place our load balancer and will therefore
be publically accessible (firewalled, of course). Hit “Create Subnet” and name this new subnet “public”. If you
created a new VPC for testing, select it in the VPC field below. For the &lt;a href=&quot;https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing&quot;&gt;CIDR&lt;/a&gt; block, select a subnet in the range that
your VPC covers. For example, I created a VPC covering &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.0.0.0/16&lt;/code&gt;. That means I’m free to use anything between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.0.0.0&lt;/code&gt;
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.0.254.0&lt;/code&gt; for my subnets. In this example, I will suggest that you use a &lt;a href=&quot;https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing&quot;&gt;CIDR&lt;/a&gt; block for this subnet of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.0.0.0/24&lt;/code&gt;.
You can leave the “Availability Zone” option on the default of “No Preference”.&lt;/p&gt;

&lt;p&gt;When your public subnet has been created, hit “Create Subnet” again and we will create our &lt;span class=&quot;success&quot;&gt;private subnet&lt;/span&gt; where our
application servers will run. Enter the name “private”, select your VPC and enter a &lt;a href=&quot;https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing&quot;&gt;CIDR&lt;/a&gt; block that does not overlap
with any of your other subnets. In the example I gave above, we could use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.0.1.0/24&lt;/code&gt; for this subnet.&lt;/p&gt;

&lt;h4 id=&quot;route-tables&quot;&gt;Route Tables&lt;/h4&gt;
&lt;p&gt;You should now have (at least) two subnets in your VPC: one &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; and one &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt;. We now need to give the “public”
subnet internet connectivity. Select the &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; subnet and click the “Route Table” tab. Below, the route table’s ID
should be displayed and this should link you to the “Route Tables” configuration screen for this table in the VPC
interface. Click that link to be taken there. Select the route table in the table of results, then in the view below,
click the “Edit” button which should allow you to edit the route table.&lt;/p&gt;

&lt;p&gt;Click the “Add another route” button and a new row in the table should show up. Fill in the details as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Destination: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.0.0.0/0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Target: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test-gateway&lt;/code&gt; (As you enter this, you should be able to select the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;igw-a1b2c3&lt;/code&gt; style ID of the gateway)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click the “Save” button.&lt;/p&gt;

&lt;p&gt;We now want to create a new route table for our private subnet. Click “Create Route Table” and call it “private”,
making sure that you’ve selected the correct VPC for your account. In the “Route Tables” screen, you should now have at
least two route tables and one of them should be called “private”. Select this route table from the list and then click
“Subnet Associations” in the view below. Click “Edit” and then tick the box under “Associate” alongside the
&lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; subnet, which we created earlier. Hit the “Save” button to apply our changes.&lt;/p&gt;

&lt;h4 id=&quot;nat-gateway&quot;&gt;NAT Gateway&lt;/h4&gt;
&lt;p&gt;In it’s current state, if we were to launch an EC2 instance in the &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; subnet, the
instance would not be able to connect to the internet. This is great from a security perspective and you may want to be
super secure, but it makes things hard when you want to deploy to the instance and part of that deploy pulls down code
from a GitHub repository, or you want to install the latest OS updates and security patches.&lt;/p&gt;

&lt;p&gt;To fix this, we need to setup a &lt;a href=&quot;https://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/vpc-nat-gateway.html&quot;&gt;NAT Gateway&lt;/a&gt; to provide secure access to the outside world. In fact,
this is just what your home router does. You may wish to read more on &lt;a href=&quot;https://en.wikipedia.org/wiki/Network_address_translation&quot;&gt;NAT&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/vpc-nat-gateway.html&quot;&gt;Amazon’s NAT Gateways&lt;/a&gt; if you want to
understand what they do and how they work. Note that this is not the same as the &lt;a href=&quot;#internet-gateway&quot;&gt;Internet Gateway&lt;/a&gt;
that we setup for our &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; subnet earlier! Whilst they provide internet connectivity,
they do it in different ways.&lt;/p&gt;

&lt;p&gt;With that explained, let’s proceed with the tutorial and click on “NAT Gateways” in the left hand side of the VPC
interface. Click “Create NAT Gateway”. In the modal that pops up, enter your &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; subnet into the “Subnet” field
and then click “Create NEW EIP” then “Create NAT Gateway”. You should get the following note displayed:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: In order to use your NAT gateway, ensure that you edit your route tables to include a route with a target of ‘nat-q1w2e3r4t5y6’.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hit the “Edit Route Tables” button to be taken to your route tables screen. Select the &lt;a href=&quot;#route-tables&quot;&gt;route table we created earlier&lt;/a&gt;
and then click the “Routes” tab below. Hit the “Edit” button, then click the “Add another route” button and a new row
in the table should show up. Fill in the details as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Destination: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.0.0.0/0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Target: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nat-q1w2e3r4t5y6&lt;/code&gt; (As you begin to enter this, you should be able to select the NAT gateway from the dropdown
list, to save you entering the ID letter by letter)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hit “Save” and that’s it in the VPC interface! Give yourself a pat on the back, make yourself a coffee or something
rewarding - you did good! :smile: :coffee:&lt;/p&gt;

&lt;h3 id=&quot;amazon-ec2&quot;&gt;Amazon EC2&lt;/h3&gt;
&lt;p&gt;Now, all that remains is to launch an instance into your new &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; and
&lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; subnets. Head into &lt;a href=&quot;https://console.aws.amazon.com/ec2/&quot;&gt;EC2&lt;/a&gt; and click “Launch Instance”. Choose your
favourite flavour OS (Linux, I hope! :wink:); I just went for Amazon Linux as I was being lazy and couldn’t be
bothered finding a CentOS AMI.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;ec2-screenshot&quot; alt=&quot;The EC2 interface&quot; src=&quot;/assets/img/posts/running-instances-in-a-private-subnet-on-amazon-ec2/ec2-screenshot.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When launching the instance, care needs to be taken on the “Configure Instance Details” screen. Select the correct VPC
in the “Network” dropdown, select the &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; subnet and enable “Auto-assign Public IP” as we need this instance to
be accessible from the internet and therefore requires a public IP to be assigned to it. Other than that, continue to
launch the instance with your usual configuration. Make a note of the public IP address that get’s assigned to the
instance.&lt;/p&gt;

&lt;p&gt;After that, we need to launch another instance into the &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; subnet, which will serve the role of the application
server in this example setup. Hit the “Launch Instance” button once more and again: take care on the “Configure
Instance Details” screen. Here, you need to select the correct VPC in the “Network” dropdown, select the &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt;
subnet and do not enable “Auto-assign Public IP”. Launch the instance and make a note of the internal IP address that
EC2 assigns the instance when it’s been created.&lt;/p&gt;

&lt;p&gt;You should now have two instances running; one in the &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; subnet and another in the &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; subnet. You should be
able to SSH onto the instance in the &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; instance, but not to the instance in the &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; subnet.&lt;/p&gt;

&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;/h3&gt;
&lt;p&gt;SSH on to the instance in the &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; subnet. As this instance is in the same VPC as the other instance which is on a
&lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; subnet, you should be able to SSH from the &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; instance to the &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt;. Once you’re onto the &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt;
instance, you should then be able to access resources on the internet. For example, you can test your internet
connectivity by pinging Google’s DNS servers:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;ping 8.8.8.8&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;…and you should see replies!&lt;/p&gt;

&lt;pre&gt;
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=51 time=18.795 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=51 time=19.609 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=51 time=19.644 ms

--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 18.795/19.349/19.644/0.392 ms
&lt;/pre&gt;

&lt;p&gt;Hit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl + C&lt;/code&gt; to cancel that ping.&lt;/p&gt;

&lt;p&gt;Your internet connectivity on this &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; instance will be routed through the &lt;a href=&quot;#nat-gateway&quot;&gt;NAT Gateway&lt;/a&gt; that we created earlier.
You can see this if you get your public IP address whilst logged into the instance:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;curl icanhazip.com&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;…and that will return your current public IP. Note that this is different to the IP address of the publicly accessible instance that
you’re connected through as this is a different internet gateway than the &lt;a href=&quot;#nat-gateway&quot;&gt;NAT Gateway&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;

&lt;p&gt;So, there’s a lot to take in there! Here’s a recap of what we’ve achieved:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We created a new VPC.&lt;/li&gt;
  &lt;li&gt;We created two VPC subnets:
    &lt;ul&gt;
      &lt;li&gt;One &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; where our public facing load balancer will be situated.&lt;/li&gt;
      &lt;li&gt;Another &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; subnet, where our more vulnerable and valuable app servers will be situated.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;We created a route table for the &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; subnet, that routed traffic destined for the internet through a NAT Gateway.&lt;/li&gt;
  &lt;li&gt;We created a NAT gateway that will allow our private servers to access the internet securely without exposing them to the internet.&lt;/li&gt;
  &lt;li&gt;We launched two EC2 instances:
    &lt;ul&gt;
      &lt;li&gt;One publicly accessible on the &lt;span class=&quot;warn&quot;&gt;“public”&lt;/span&gt; subnet: Demonstrates a load balancer in this example.&lt;/li&gt;
      &lt;li&gt;One situated on the &lt;span class=&quot;success&quot;&gt;“private”&lt;/span&gt; subnet: Demonstrates the app server.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the setup that we built, one can connect to the public instance directly over the internet, just like a user’s
browser would be able to connect to it using HTTP directly over the internet. However, one cannot connect to the
private instance, unless you are connecting from an instance which is situated in the same VPC as the private instance.
In this example, the load balancer has an interface in that VPC and can therefore connect to the private instance to
forward HTTP connections onto it without exposing the private instance to the internet. At the same time, both
instances have full outbound internet connectivity; allowing code to be deployed to the instances, along with OS
and application updates, installation and downloads.&lt;/p&gt;

&lt;p&gt;I hope this has helped; it took me a fair bit of trial and error to work out how to do this. If this has helped,
please let me know!&lt;/p&gt;

</description>
        <pubDate>Fri, 22 Apr 2016 00:00:00 +0000</pubDate>
        <link>https://joe.nyland.io/blog/running-instances-in-a-private-subnet-on-amazon-ec2/</link>
        <guid isPermaLink="true">https://joe.nyland.io/blog/running-instances-in-a-private-subnet-on-amazon-ec2/</guid>
        
        
      </item>
    
      <item>
        <title>Careful with your Git remote config</title>
        <excerpt>I thought I was being clever with my Git remote config.</excerpt>
        <description>&lt;p&gt;For some time, I had the following in my &lt;a href=&quot;https://github.com/JoeNyland/dotfiles/blob/master/home/.gitconfig&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.gitconfig&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;nn&quot;&gt;[remote &quot;origin&quot;]&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;prune&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I like keeping my branches tidy on the projects I work on and the more developers that are working on a project, the
more branches are getting created, merged and deleted all the time. The above Git config means that every time you
fetch, Git will prune remote branches automatically, just like it would if you used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git fetch --prune&lt;/code&gt;. This worked
great and I thought I was being clever! :bowtie:&lt;/p&gt;

&lt;p&gt;However, recently when I built the repositories for a few of my new projects (personal and work), I noticed a problem
when I came to add the remote GitHub or BitBucket (I know, I know - we &lt;em&gt;have&lt;/em&gt; to use BitBucket at work - it’s bloody
terrible!). As normal, I’d issue the following command to add the remote repo:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git remote add origin https://github.com/JoeNyland/test.git&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But this would throw the error:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fatal: remote origin already exists.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bugger! :angry:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Git (as always) wasn’t lying either!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was puzzled for a while trying to work out why, on a newly created and blank repo, Git was complaining that an
origin already existed. Git (as always) wasn’t lying either!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir test&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd test&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git init
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git remote &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;
origin&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Whilst the above configuration conveniently sets the configuration for a remote repository to always prune remote
branches when fetching, having this set implies that a remote with the name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;origin&lt;/code&gt; already exists, hence the
phantom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;origin&lt;/code&gt; in the above example shows up when listing remote repositories, even though technically is does not
exist.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fatal: remote origin already exists.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://www.google.co.uk/#q=fatal:+remote+origin+already+exists.&quot;&gt;Googling&lt;/a&gt; for the error above yields many many suggestions for users to use the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git remote set-url origin https://github.com/JoeNyland/test.git&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But that doesn’t really address the problem here. The real solution to that error is to remove the configuration at
the top of the post from your Git config file (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git/config&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.gitconfig&lt;/code&gt;), which is &lt;a href=&quot;http://albertogrespan.com/blog/always-prune-remote-tracking-branches/&quot;&gt;just what I did&lt;/a&gt; and the
error went away!&lt;/p&gt;

&lt;p&gt;It’s annoying that you can’t set the default configuration for a remote that does not necessarily exist yet in your Git
config, but hopefully this will be possible in a future version of Git.&lt;/p&gt;

&lt;h4 id=&quot;update-17042015&quot;&gt;Update 17/04/2015&lt;/h4&gt;
&lt;p&gt;I’ve found a solution! :tada:&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;http://albertogrespan.com/blog/always-prune-remote-tracking-branches/&quot;&gt;Alberto Grespan’s blog post&lt;/a&gt; I found that you can set the default behaviour for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git fetch&lt;/code&gt; to prune
remote branches automatically with the following command:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git config fetch.prune &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Or the following in your Git config:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;nn&quot;&gt;[fetch]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;prune&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I’ve added this to my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.gitconfig&lt;/code&gt; and have been using it for the past few days and it works a treat!&lt;/p&gt;

&lt;p&gt;Moral of the story: Git is awesome!!! :metal:&lt;/p&gt;

</description>
        <pubDate>Thu, 14 Apr 2016 00:00:00 +0000</pubDate>
        <link>https://joe.nyland.io/blog/careful-with-your-git-remote-config/</link>
        <guid isPermaLink="true">https://joe.nyland.io/blog/careful-with-your-git-remote-config/</guid>
        
        
      </item>
    
      <item>
        <title>A quick Rake task to tweet about a new post</title>
        <excerpt>Here&apos;s a quick and easy Rake task to tweet when a new post is published.</excerpt>
        <description>&lt;p&gt;I use &lt;a href=&quot;https://twitter.com/JoeNyland&quot;&gt;Twitter&lt;/a&gt; a fair bit, so I like to fire a quick tweet out to my many (not) followers when I’ve published a new
post :bird:. This task was a bit of a pain, so I thought I’d throw together a quick &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rake&lt;/code&gt; task to do this for me.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;To get this to work, you’ll need to install the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twitter&lt;/code&gt; gem manually or, by adding it to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;You’ll also need to create config file that will store the API keys for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twitter&lt;/code&gt; gem to use to authenticate
with the Twitter API. Use the following template, enter your API keys and save it as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twitter-api-credentials.yaml&lt;/code&gt;
right next to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rakefile&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;na&quot;&gt;consumer_key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;consumer_secret&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;access_token_secret&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;You can get your API keys by creating yourself an app at the &lt;a href=&quot;https://apps.twitter.com&quot;&gt;Twitter dev site&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Add the following task to your Rakefile:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;require &lt;span class=&quot;s1&quot;&gt;&apos;twitter&apos;&lt;/span&gt;

desc &lt;span class=&quot;s1&quot;&gt;&apos;Tweet about a new post&apos;&lt;/span&gt;
task :tweet_link_to_post , &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;:title, :url] &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; |task,args|

  &lt;span class=&quot;c&quot;&gt;# Connect to the Twitter API&lt;/span&gt;
  client &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; Twitter::REST::Client.new &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; |config|
    YAML.load_file&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;twitter-api-credentials.yaml&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.each &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; |config_item,value|
      config.send &lt;span class=&quot;s2&quot;&gt;&quot;#{config_item}=&quot;&lt;/span&gt;, value
    end
  end

  &lt;span class=&quot;c&quot;&gt;# Check that we&apos;ve been provided with a title and URL&lt;/span&gt;
  fail &lt;span class=&quot;s1&quot;&gt;&apos;Missing title or URL&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;args[:title].nil? or args[:url].nil?

  &lt;span class=&quot;c&quot;&gt;# Confirm the message with the user to make sure they&apos;re happy with it&lt;/span&gt;
  puts &lt;span class=&quot;s1&quot;&gt;&apos;This is the message that will be tweeted:&apos;&lt;/span&gt;
  puts message &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;I just published a blog post: “#{args[&apos;title&apos;]}” Check it out here: #{args[&apos;url&apos;]}&quot;&lt;/span&gt;
  puts &lt;span class=&quot;s1&quot;&gt;&apos;Happy with it? Enter yes or no:&apos;&lt;/span&gt;
  response &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; STDIN.gets.chomp

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; %w&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;y &lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;.include? response.downcase
    &lt;span class=&quot;c&quot;&gt;# User is happy, so let&apos;s tweet it!&lt;/span&gt;
    client.update message
    puts &lt;span class=&quot;s1&quot;&gt;&apos;Ok, tweeted that to your followers!&apos;&lt;/span&gt;
  elsif %w&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;n no&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;.include? response.downcase
    &lt;span class=&quot;c&quot;&gt;# User has changed their mind, so don&apos;t tweet&lt;/span&gt;
    puts &lt;span class=&quot;s1&quot;&gt;&apos;Not tweeting, as requested.&apos;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Invalid response, so&lt;/span&gt;
    fail &lt;span class=&quot;s1&quot;&gt;&apos;You must answer yes or no&apos;&lt;/span&gt;
  end

end&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;When you’re ready, run the task with:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;rake tweet_link_to_post[&lt;span class=&quot;nv&quot;&gt;$TITLE_OF_POST&lt;/span&gt;,&lt;span class=&quot;nv&quot;&gt;$URL_OF_POST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;… but obviously change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$TITLE_OF_POST&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$URL_OF_POST&lt;/code&gt; parameters to those of the post that you’ve just published :smile:.&lt;/p&gt;

</description>
        <pubDate>Wed, 16 Mar 2016 00:00:00 +0000</pubDate>
        <link>https://joe.nyland.io/blog/a-quick-rake-task-to-tweet-about-a-new-post/</link>
        <guid isPermaLink="true">https://joe.nyland.io/blog/a-quick-rake-task-to-tweet-about-a-new-post/</guid>
        
        
      </item>
    
  </channel>
</rss>
