Make the windows machine at your house on a residential dynamic IP email you its public IP regularly

Wrote a Windows batch file that does exactly what the title of this post says it does. Edit the Mailjet creds (er, sign up for Mailjet first if needed, it’s free) and the email in the batch file and create a Scheduled Task to execute it. You’ll always know your home IP and can remote to your home machine at leisure.

Sends you an email that looks like

Yay technology πŸ™‚

Yay I’m officially a Magento 2 Certified Developer

Maybe it’s just the fresh trauma, but I think the M2 cert exam was much more difficult than my M1 Dev+. Many of the questions were basically ‘here’s some requirements, here are four different ways to fulfill them, pick which one is best’. I don’t think there was a single simple memorization question in the whole 60 question exam.

But at least I’m certified, I guess I somehow managed to accrue the recommended ‘1.5 years of Magento 2 experience’ in about 3 months by leveraging my M1 knowledge, building some example modules, and studying my ass off.

I have a module built with over 700 multiple choice questions that I built to help me study, I’ll release that eventually for others aspiring to pass the cert.

Preventing Magento 2 upgrade scripts from upgrading past setup_version

So… here’s a ‘neat’ Magento 2 install script ‘feature’:

Magento 2 upgrade scripts, as I see them written in basically every blog post I find and the Magento 2 docs, blindly upgrade as far as they can. What version you put in ./etc/module.xml before you run ./bin/magento setup:upgrade doesn’t matter. Here’s an example from the dev docs:

$context->getVersion() contains the current installed version of the module, version_compare sees if that is lower than 0.0.2, and if so, whatever upgrade operations exist in the next code block are run.

Here’s where that causes problems:

– You’re developing, and need to test incremental upgrades.
– Your upgrade script upgrades to version 0.0.2 and 0.0.3
– You update ./etc/module.xml’s setup_version to 0.0.2, intending to only execute the 0.0.1 -> 0.0.2 upgrade
– You run ./bin/magento setup:upgrade, and your module still ends up at version 0.0.3

So, how do you get around it? No idea if this is ‘proper’, but it worked for me:

– Inject a \Magento\Framework\Module\ModuleList

– use it to read the setup_version from the ./etc/module.xml file2019-01-07_13h27_40

– update your version testing code to ensure that current version is below the upgrade code version, Β AND that the upgrade code version is less than or equal to the setup_version in ./etc/module.xml.


Magento 2 Missing Main Navigation

Weirdly, and unlike M1, Magento 2 does not show the main navigation menu by default. You need to create some categories and subcategories to act as placeholders while you are theming, *and* assign them to the store view, to make the main navigation show up.

Creating the categories is simple, just go Catalog > Categories


Adding them to the store view is the part that tripped me up. Go Stores > All Stores

…. and click on a store but *not* a website or store view. Β Only stores have give you the option to set a root category.


Clear cache and the navigation should show up now.

Magento 2 – setting up Grunt LESS compilation

Adapted from

– Install nodejs somewhere

apt-get install node

– cd (magento root)
– move ./package.json.sample to just package.json
– move Gruntfile.js.sample to Gruntfile.js
– install grunt, probably as root

npm install -g grunt-cli

– update Magento’s node dependencies

npm install

– make sure your style sheet is added to (your theme)/Magento_Theme/layout/default_head_blocks.xml

– make sure your source files exist

[[email protected]/var/www/ecommsys/app/design/frontend/Siliconrockstar/base][22s] tree ./web/
 └── css
 β”œβ”€β”€ source
 β”œβ”€β”€ styles.less
 └── _variables.less

– add your theme to ./dev/tools/grunt/configs/themes.js

 base: {
   area: 'frontend',
   name: 'Siliconrockstar/base',
   locale: 'en_US',
   files: [
   dsl: 'less'

– run the grunt task to prep the symlinks for your static content files

grunt --verbose exec

– have grunt compile your less

grunt --verbose less

As far as I can tell, you either need to

– compile the both your themes’ css and all parent themes’ css, or
– add the stylesheets for the parent theme ( usually styles-m and styles-l ) to the grunt config for your own theme

…to make sure changes show.



If you just need to add some simple simple css changes, you can toss them into _extend.less and they’ll automatically compile and append to the parent themes’s styles. Not sure if you need to add the grunt config or not…

[[email protected]/var/www/ecs/app/design/frontend/Siliconrockstar/base/web][0s] tree ./css/
└── source
 └── _extend.less

using nginx to proxy different domains to different ports

I’ve got a secret devops weapon in the works. At a very simple level, part of it involves running multiple web applications on a single IP, but without having control of the webserver. Well, full disclosure, the applications include built-in tomcat instances and automatically install themselves on separate ports, and figuring out how to hack giant pre-built applications and modify tomcat was obviously not the quick option.

So I decided to do a proof of concept. What I needed was to be able to route requests at the domain level, all ingressing on port 80 (443 and SSL/HTTPS is the next step I suppose), and route them to a local port, all within the webserver (the machine is on Google Cloud, sans loadbalancer, and AFAIK there is no option in the console to handle this at the TCP/IP level).

A quick google turned up two obvious proxy solutions: Apache with mod_proxy, or nginx.

I’m an nginx fan, and haven’t had the opportunity to use it much recently, so I chose to do the PoC with nginx and proxy_pass directives, on a local Ubuntu VM.

The preconditions I wanted to set up were pretty straightforward – I needed two web apps, running on different, non-standard http ports, that were both visible in browser if you added the port number.

– site1 on port 81, accessible in browser via http://proxytest.local:81
– site2 on port 82, accessible in browser via http://proxytest.local:82

Then end result I wanted to create was also easily defined – two sites, running on the same ip, but different domains, with each domain transparently forwarded to the right application on its non-standard local port:

– http://site1.local forwards to local port 81
– http://site2.local forwards to local port 82

Setting up the preconditions

Install nginx, if needed – if you’re running apache or another process that owns port 80, be sure to stop it first

service apache2 stop
apt-get install nginx

create web files for both site1 and site2

mkdir /var/www/proxy_test;
mkdir /var/www/proxy_test/site1;
mkdir /var/www/proxy_test/site2;
nano mkdir /var/www/proxy_test/site1/index.html;
add whatever text to make site1 identifiable
nano mkdir /var/www/proxy_test/site2/index.html;
add some text to make it apparent this is site2

edit /etc/hosts to make the test domains resolve to localhost proxytest.local site1.local site2.local

create nginx config files for site1 and 2, in /etc/nginx/sites-available

[email protected]:/etc/nginx/sites-available# cat ./site1
server {
listen 81;
listen [::]:81;

server_name site1.local;

root /var/www/proxy_test/site1;
index index.html;

# location / {
# try_files $uri $uri/ =404;
# }

[email protected]:/etc/nginx/sites-available# cat ./site2
server {
listen 82;
listen [::]:82;

server_name site2.local;

root /var/www/proxy_test/site2;
index index.html;

# location / {
# try_files $uri $uri/ =404;
# }

… and symlink them to /etc/nginx/sites-enabled to enable the sites

cd /etc/nginx/sites-enabled ; ln -s ../sites-available/site1 ; ln -s ../sites-available/site2

[email protected]:/etc/nginx/sites-enabled# ll
total 8
drwxr-xr-x 2 root root 4096 Jul 27 07:56 ./
drwxr-xr-x 8 root root 4096 Jul 27 07:28 ../
lrwxrwxrwx 1 root root 34 Jul 27 07:28 default -> /etc/nginx/sites-available/default
lrwxrwxrwx 1 root root 24 Jul 27 07:56 site1 -> ../sites-available/site1
lrwxrwxrwx 1 root root 24 Jul 27 07:56 site2 -> ../sites-available/site2

restart nginx to apply changes

service nginx restart

verify you can see all the sites in browser, using their port numbers

default nginx page on port 80

site 1

site 2

Setting up the Proxy

So preconditions were set up. Now I needed to figure out how to implement nginx as a proxy to let users access each site by domain, sans port number.

Turns out it was a lot easier than I thought it would be. Just create the proxy config at /etc/nginx/sites-available/proxy_test

[email protected]:/etc/nginx/sites-enabled# cat ./proxy_test
server {
listen 80;
server_name site1.local;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
server {
listen 80;
server_name site2.local;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;

… symlink it into /etc/nginx/sites-enabled like you did with the site1 and site2 config files above, restart nginx, and viola! Now each site is accessible on external port 80, by domian name.

Site 1


Site 2



I love you nginx <3 – completed WordPress project

My work life isn’t all Magento. Sometimes between contracts, I do other stuff.

I just did the logo, site design, and WordPress build for –, a concrete and landscaping company based in Denton, TX. Took about a week.

My design skills aren’t 1337, but they’re usually good enough to get something professional put together. And honestly, the North Texas concrete business is not exactly the most competitive sector when it comes to web design.

(Re)Installing Magento 2 from shell

Sometimes, you accidentally bork your Magento 2 development database. Sometimes, you just want to reinstall as a sanity check. Luckily, you don’t have to re-extract the installer – you can simply un-install and re-install Magento 2 using the ./bin/magento CLI tool, see:

However, the command needs a lot of arguments. I just dropped the following into a shell script at ./bin/

[0s][/var/www/m2/bin]$ cat ./

./magento setup:install --admin-firstname Andy --admin-lastname Boyd \
--admin-email [email protected] --admin-user admin \
--admin-password Password1! --base-url http://m2.local --backend-frontname m2_admin \
--db-host localhost --db-name m2 --db-user root --db-password Password1!

Magento 2 and PHP Unit – ‘no tests executed’ issue

When starting on unit tests for a Magento 2 module, It seemed that phpunit refused to find any of my test methods. After some experimentation, I found a fix (well, maybe a workaround)

– copy (magento root)/dev/tests/phpunit.xml.dist to ./phpunit.xml, and then pass that as the config file (this was pretty obvious)
– you have to call Magento’s phpunit binary, not your system phpunit binary (this was way less obvious)

So where you could normally do something like

cd /path/to/magento2/app/code/YourCompany/YourModule/Tests/Unit ;
phpunit . ;

You instead need to do

cd /path/to/magento2/ ;
./vendor/phpunit/phpunit/phpunit -c /path/to/magento2/dev/test/unit/phpunit.xml .

The problem with just doing ‘phpunit’ is it calls /usr/bin/phpunit, or whatever your local system phpunit is.

For convenience, you can replace the long file paths above with a couple symlinks and save yourself a LOT of typing. Become root on your system and do

cd /usr/bin ;
mv ./phpunit ./phpunit-system ;
ln -s /path/to/magento2/vendor/phpunit/phpunit/phpunit ./ ;
cd /path/to/magento2/app/code/YourCompany/YourModule/Tests/Unit ;
ln -s /path/to/magento2/dev/tests/unit/phpunit.xml ./ ;

You replaced the usual phpunit system binary with a symlink to Magento’s, and added a symlink to the phpunit config file in your modules unit tests directory. So now to run your module’s unit tests, just do

cd /path/to/magento2/app/code/YourCompany/YourModule/Tests/Unit ;
phpunit -c ./phpunit .


Speed up VmWare virtual machine by changing location of nvram (virtual RAM) file

I’ve got multiple VMs on a HDD RAID array. I/O is ok, but it’s platter style drives in RAID-1 – speed is constrained by the limitations of the drive design.

I also have a small SSD RAID array of only 80G that houses the base Windows O/S, it idea being that the base O/S should run as quick as possible. Obviously, with a Win10 install, I’ve only got a few GB to spare on that partition, so there’s no way I could move the VMs over.

Lightbulb: I could still increase VM performance many times over if I could have VmWare use the SSD array for *just* the virtual memory file.

Luckily, the VM config file has just an option for this:

workingdir = "c:\VmWareWorkingDir"

Now the VM disk images still live on the HDD array, but the virtual memory file now lives on the SSD array – with much faster I/O πŸ˜€