Proxying Home Assistant through a VPS
If you don’t want to hear my story you can skip to the guide by clicking here.
My internet provider, like everyone else’s it seems, sucks. They’ve provided me with a router which has the worst Wifi I’ve ever seen and they do not allow me to visit my public IP internally for some reason.
The first is not that much of an issue since it can easily be solved through a second router with better Wifi. In my case a TP-Link Deco mesh network.
The second, however, gave me some headache. Initially I thought that the router was being a dick and not letting me forwarding any ports. This was not the case, and contacting my ISP I was told these routers came with a “feature” that blocked internals from accessing anything on the network through the public IP address. A quick VPN check confirmed that my Home Assistant was indeed accessible from the world wide web.
I’ve recently started learning Docker and one of the things I’ve been doing a lot lately is proxying traffic from a load balancer to a container. Digging deeper this is also how things like the Hass.io addons for NGINX work. They proxy the traffic from one Nginx docker container to the Home Assistant docker container. But those containers wouldn’t do much for me, since I only would be able to see my Hass.io instance from the outside.
I don’t want to have to switch from the internal address to an external address every time I log on and off my network. Initially I was considering the building a Hass.io addon that used Ngrok. I’m pretty sure the ngrok daemon would restart every now and then, and with the free plan I would be given a new domain for my instance. That would mean some smart integrations with my domain host to update a CNAME record every time the daemon would restart. Sounds like a lot of work. The “Basic” (priced $5) plan of ngrok would allow me to add a custom domain, but I would still need to write a addon for Hass.io that integrates all this.
So, I went another route. Using a $2.50 VPS. After I set everything up I remembered AWS has a free-tier for their EC2 service. That would give you 750 hours a month on their t2.micro instances for one year. After that it would cost money. Amazon’s pricing confuses me so I’m not gonna go into details on this. With AWS you could also utilize many of their other services, but from experience you’ll just get too excited and end up with a $300 invoice from Amazon because you tested something and forgot to delete the instance.
As this VPS will only serve as a proxy for our Home Assistant instance it won’t require much resources. Unless you have hundreds of family members that all needs to access everything at the same time.
Finally the internet sees my home, and I can use the Home Assistant iOS app to send my location and receive notifications both home and away.
The Guide
I used a VPS from a company I found when I Googled “cheap vps”: VirMach. As far as I can tell they offer the cheapest VPS I could find at $2.50 a month. Vultr also offers a VPS at this price range, but you only get an IPv6 address. I needed an IPv4 address.
Prerequisites
- A machine running Hassio on your local network
- A DuckDNS account
- The DuckDNS addon for Hassio installed and configured.
- A VPS running Ubuntu 16.04 or greater.
Installation
Start by getting the operating system up to date.
sudo apt-get update
My instance had Apache2 running so I had to remove this.
sudo service apache2 stop
sudo apt-get purge -y apache2 apache2-utils apache2.2-bin apache2-common
Then install NGINX and nano (a text-editor)
sudo apt-get install -y nginx nano
sudo service nginx start
Now that your NGINX server is running we can create the proxy. Open your default site config.
sudo nano /etc/nginx/sites-enabled/default
And add this configuration. Change the URL myhassioname.duckdns.org
to your duckdns URL.
upstream hassio {
server myhassioname.duckdns.org:8123;
}
server {
listen 80 default_server;
server_name _;
charset utf-8;
location / {
proxy_set_header Host heim.tormorten.no;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://hassio;
proxy_redirect off;
# Handle Web Socket connections
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Restart NGINX.
sudo service nginx restart
Visit your server’s IP address in your browser. You should now be prompted with the beautiful login to your Home Assistant instance.
Going further
You’ll notice the traffic is not encrypted. Everything here is running on the http
protocol. You can solve this by adding a Lets Encrypt certificate to the above configuration, or use CloudFlare’s free SSL certificate. My domain’s DNS is already handled by CloudFlare, so it wasn’t that much of a hassle for me and I really recommend it.
Bringing the queue to WordPress
In Laravel you have the concept of queues, where you push a job in to the queue and a queue worker executes jobs asynchronously one by one. This is a great feature of Laravel.
At OSM Aviation we send a great amount of emails from our website. Sometimes we might need to send thousands of emails at the same time. This is an operation that would get real slow real fast; an ideal job for a queue.
Sadly, WordPress does not have such feature. The wp_mail function is a fire and forget kind of feature. Luckily there are many smart people out there, and there is a solution for features.
Finding the perfect solution
During my search for WordPress Queues I first found a solution which runs through wp-cron. This however ended up as a bottle-neck when sending many emails and ended up bringing our whole site down for a couple of hours. Not optimal for a mission-critical website.
A promising solution was a neat plugin created by A5hleyRich. This took care of the queue problem, but it had some shortcomings. There was no CLI, so it was not ready for production. Based on this great plugin I found a hidden gem in MailChimp for WooCommerce plugin. They had created a command for WP-CLI that ran a queue worker. They had also implemented a “failed_jobs” feature which could prove handy if something went wrong. None of these solutions took care of mail problem though. So I would have to wire something up myself.
Putting it together
I found this to be a fun little exercise in using WordPress’ pluggable functions. Since wp_mail can not be short-circuited, I figured I could just create my own wp_mail function that would be used in favor of the one in WP core. I took the original wp_mail function from core, and created it as a new function called wp_real_mail. This would send e-mail directly via the credentials provided in the application.
The wp_mail function’s only task would be to push anything thats sent through it to the new Queue system. Using the great work from the MailChimp-plugin this function boils down to two lines.
E-mails sent via the website is now served up using a queue, allowing us to send as many e-mails as we need in one go without having to worry about it taking several minutes to execute. Actually, since June we’ve sent over 15000 emails using this new queue feature and haven’t had a single mail that hasn’t been sent.
The queue worker is run on the server by Supervisor, so it is restarted when it crashes.
Check it out now
It has all been bundled up in a plugin that is availiable on Github, along with its documentation. Since it replaces the wp_mail function I recommend you put in your mu-plugins
directory.
The DOM Router improved
I’ve previously written about my port of the DOM router which is bundled with the Sage starter theme.
This handy little mofo has been used on all my client projects for the past 2 years, and I couldn’t be happier.
Something that has annoyed me, however, is that it requires jQuery. There’s not reason jQuery was needed in the first place, but back then I jQueried all the things.
Last week I spent a couple hours one night to port the port to a more usable module. It was also a neat project to write Vanilla-ish javascript.
The result is DumDum.
DumDum is a ES2015 class and has all the same properties as the old jQuery DOM Router.
You can import/require it to your project. Or simply load up the distribution file to use the browser global.
Actions and filters in Laravel
I really like the way events work in WordPress. It’s just really simple how you can hook into difference points in your code.
Yes, Laravel has it’s own event system. But I found this to be both confusing and hard to use. While classes are all fine and dandy, I do feel there are such things as too many of them. I also like the idea of events being triggered on hook names.
So that’s why I made Eventy (yes, stupid name, but that’s what I got).
Eventy is the WordPress action & filters in Laravel. You add actions/filters in your code, and add listeners to them later.
Blade for WordPress
Lately I’ve been working on an internal project that we’ve chosen to build on Laravel. Laravel is packed with amazing things like the Eloquent ORM and the general “easyness” of the API. The most amazing thing, however, is the Blade templating engine. I love this thing!
You can easily extend templates and include them with a breeze. It really helps you with your rapid front-end development.
So, I’m in love with Blade, but I’m primarily a WordPress developer. Sucks to be me right?
Well, no, not really. There are some existing options on how to use Blade in your WordPress theme.
Like the Blade for WordPress plugin, or even the CutlassWP WordPress theme (which uses the functionality from the said plugin and is Roots-based). These are great, but the thing is.. They use a really old version of Blade. In fact. It is the Blade that was bundled with Laravel 3. There’s been two iterations of Laravel since then, and in that also Blade.
The other thing is that I’ve gotten used to my own starter theme, so I’m not really feeling like switching to a new theme and start an all new workflow. I should be able to use the latest version of Blade, and I should be able to implement it in my own theme.
So, why not create my own Blade for WordPress?
I really like using Composer for handling my dependencies, so I decided to make it a class one can include in projects.
It kind of works the same way those other alternatives work, but does not require you to install another plugin or switch out your starter theme.
Have a look! It’s over at Github.