I’m not too proud to admit that there have been numerous occasions where I’m convinced a server is lying to me only to discover that I was looking at production instead of my local development environment.
I’m also not too proud to admit that it’s happened the other way too, where I’ve made edits to a production site (in the CMS not in the code, put down the cowboy pitchforks!) unintentionally.
It’s deflating, but we’re all human.
Calling out your development environments
I recall some years ago seeing an article or screenshot about how someone used different WordPress Admin color schemes to differentiate environments. Other developers use a plugin that changes the Admin Bar color to something unique.
I know myself, and I know I’d forget to do that at some point. Or I’d migrate a site down from production and forget to re-set the Admin color scheme, or something would go wrong.
Enter content injection for local server differentiation
I liked the idea of the Admin Bar changing color for development environments, but there are a couple problems associated with that:
- The Admin Bar can be hidden on the front end
- It requires manual action to install/activate a plugin, or ensure some CSS applies in development only
- It requires that the site be powered by WordPress, and that I’m logged in
The first two issues alone confirmed I needed something more… blatant. The last issue is arguably the most important as I’m finding myself working on a broader range of projects.
As I was thinking about this problem the idea occurred to me about how nice it’d be to have my local server inject something into every served page to indicate that it was a local environment. Eureka!
After a bit of digging around I found out the Nginx could make this idea a reality thanks to its
ngx_http_sub_module, specifically its
Essentially this allows you to do a find/replace on every request that Nginx serves. This is exactly what I was thinking about.
Keep in mind that this module may not be supported by your installation of Nginx, but it’s easily implemented by reinstalling Nginx via Homebrew as outlined in MyLocalDev Part 2: MEMP and Valet. With
sub_filter support available in Nginx, the last step is configuring Nginx to output something that will help identify a site as local as opposed to production.
I wanted to customize Valet’s nginx configuration, but also didn’t want to lose the configuration should Valet get updated over time. It turns out that an additional directory is read when Valet is serving a site, so we can just create a new file with this customization:
subl in the following command with your editor of choice)
Which will bring up a blank file, the content of which can be something like this:
'<div style="background: red; height: 3px; position: fixed; width: 100%; top: 0; left: 0; z-index:2147483647;"></div></body>';
Note: If after making this change your sites no longer load due to
ERR_CONNECTION_REFUSED it’s because your Nginx installation doesn’t know what to do with
sub_filter, you’ll need to install a version of Nginx that does, covered here.
It’s pretty simple, we’re telling nginx to include a
<div> with some inline style before the
</body> any time
</body> is found, which would be any time we’re serving HTML locally.
Essentially I’ve implemented my own MITM (Man In The Middle) attack on myself by injecting content into HTML documents served in my local development environment.
As it turns out, this works well! Note the red line at the top of these screens, that’ll appear on any HTML page served via my local nginx environment.
It’s not super blatant, but for me it’s just enough to call out my development environment, even taking into consideration the placement of WordPress’ Admin Bar.
Naturally this leaves a lot open for customization, and if you ever want to obscure the indicator you can just override the CSS, but this little touch will hopefully prevent me from confusing my development and production environments ever again!
Read more from this series
This article is part of a MyLocalDev series all about local web development on OS X. Check out the other articles in this series: