Settling on a Netlify + Dokku on DigitalOcean (for US) or Hetzner Cloud (for EU) deployment stack for JavaScript and Node.
Over the last few years I’ve never quite settled on a goto deployment strategy for my apps and projects. Technology-wise it has settled towards Vue or static site generators for the frontend with Node on the backend, whether that’s for API servers or handling rendering through handlebars.
What I’ve finally settled on is Netlify + Dokku on DigitalOcean. Netlify for anything static (and more with forms, CMS and lambda). Dokku, “The smallest PaaS implementation you’ve ever seen.“ for any backend apps and databases. This is what I’ve used to deploy my latest projects Post Frequency and Accountable Blogging, tools to quantify and improve your blogging output.
This is a long list of pros/cons for a bunch of services:
- 👍 → pro
- 👎 → con
- 🤔 → undecided
- 🚨 → deal-breaker for me
- 🤓 → nice-to-have
Table of contents:
My past deployment experiences
For these purposes I’ve leaned towards the following deployment options:
now.sh
- 👍 does static hosting
- 👍 does app hosting
- 👍 can build your static site/frontend
- 👎 no database hosting
- 🤔 built-in DNS
- 🚨 I didn’t use it to full capacity (only ever had 2 deployments instead of the limit of 5)
GitHub Pages
- 👍 free
- 👍 baked into your GitHub repos (as simple as pushing to
gh-pages
branch) - 👍 static hosting
- 👎 can’t build your app itself
- 👎 for the longest time was difficult to have SSL for (had to pair it with Cloudflare)
- 👎 dealing with domain names
Heroku
- 👍 app hosting
- 👍 database hosting (with a generous free tier)
- 👍
git push heroku master
deploys - 👍 addons system
- 👍 things like logging aggregation, monitoring are just a click away
- 👍 buildpack system
- 👍 easy domain management
- 👎 🤑 per app/dyno pricing
- 🚨 it’s just not worth it for low traffic apps
- 🚨 Scaling Node apps involves increasing the number of processes + a Node process is not very resource intensive, which would get very costly (not that I’ve ever needs to scale my personal apps)
AWS
- 👍 has everything you could think of
- 👎 dashboard UI
- 🚨 pricing once the free tier expires (1 year) is steep even for the smallest instances
DigitalOcean
- 👍 dashboard UI
- 👍 competitive pricing
- 👎 managing the server
- ssh-ing to install databases, and runtime requirements (Node, pm2)
- deployment over ssh (or at least ssh to
git pull
- 👎 setting up nginx 😛
- I secretly love dealing with nginx configuration, just not at the cost of shipping some code
** I won’t mention one-click deploys here because I hadn’t used them before deciding to give Dokku a try*
Vultr
- 👍 cheapest VPS I could find at the time ($2.50)
- caveat: the machine specs are what you pay for, which is enough to host a university final year project API + React app
- 👎 managing the server (see DigitalOcean)
The stack moving forward
Netlify
- 👍 free tier (beyond generous)
- 👍 static hosting
- 👍 can build your static site/frontend
- 🤔 lambda ❤
- 👍 having a backend (that isn’t a backend) for some stuff is cool
- 👎 dealing with a bundler for backend code
- 👎 debugging minified backend code
- 🤔 lambda startup time (can be fine if you have an SPA on the frontend that puts a nice loading state while you wait)
- 👍 forms
- trivial to integrate
- no need to prematurely add a second service eg. to collect email addresses on a landing page
- 👍 Netlify CMS + identity
- 🤔 CDN baked in
- 👍 DNS
- 👍 automatic SSL
- 🤓 preview apps
- 👍 nice GitHub integration
Dokku on DigitalOcean
- 👍 as expensive as necessary
- can have as many apps as you want as long as it doesn’t max out your CPU/RAM
- easy to scale up
- starting for $5/mo
- 👍 DigitalOcean’s “Dokku one-click deploy”
Dokku on Hetzner Cloud
“Truly thrifty cloud hosting”, Hetzner is renowned for its dedicated servers, this is their cloud offering, which is very competitive compared to DigitalOcean.A 2GB instance is €2.99/mo vs $10/mo and is also cheaper than the DigitalOcean 1GB instance at $5/mo.
- 👍 most bang for the buck
- 🤔 Only European data centers
- 👍 GDPR compliance (even have a policy builder)
- 👎 Traffic going from Europe to the US (if your target audience is in the US)
- 🤔 The Console is functional but no more
- 👎 No one-click DigitalOcean Install
- 🤓 managing user accounts on a *NIX system,
visudo
adding sudoers etc.
- 🤓 managing user accounts on a *NIX system,
Dokku pros and cons (regardless of DigitalOcean)
- 👍
git push dokku master
deploys - 👍 management from the command line
- 👎 no UI by default although https://github.com/palfrey/wharf could be cool
- 👍 easy SSL
- 👍 easy domain management
- 👍 application hosting
- 👍 database hosting
- 🤔 multiple apps on one instance
- if the droplet goes down 2-3 apps go down (I don’t think anyone cares about this)
- a single high traffic app can eat resources (when apps get traffic, move them somewhere else)
- 🤔 still self-hosting
- Except now I need to be able to manage Docker/Dokku stuff
Setting Dokku up
- 👍 one-click deploy droplet on DigitalOcean
- 👎 there isn’t a definitive guide to setting up a DNS record for a subdomain for the Dokku instance
- here’s my shot at it:
- find out the server’s IP
- create an A record
- for
*.deploy.yourdomain.tld
anddeploy.yourdomain.tld
(feel free to replacedeploy
with whatever subdomain), for me that wasdeploy.codewithhugo.com
- point the record to the IP address
- (if you’re on CloudFlare or anything else that can proxy): don’t use the CDN/proxy feature
- To check it works, ssh
deploy.yourdomain.tld
- 🤔 no local CLI (everything is done over SSH)
- add
alias dokku="ssh -t dokku@deploy.yourdomain.tld"
to your.bashrc
/.zshrc
- then use
dokku <command>
as you would on the remote server
- add
- 👎 same situation for custom domains for apps
- again, my take on it
dokku domains:add your-app-name subdomain.domain.tld
- Create a CNAME record
- name:
subdomain
- value:
your-app-name.deploy.yourdomain.tld
- 👍 easy letsencrypt (https://github.com/dokku/dokku-letsencrypt)
- ssh into the server
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
- Add letsencrypt to an app
dokku letsencrypt app-name
- Add letsencrypt certificate auto-renewal CRON job:
dokku letsencrypt:cron-job --add
Parting thoughts
My migration of a couple of apps off of now.sh wasn’t to go from bad to good, but rather from good to better (for my needs).
Top comments (3)
How do you get this in the meta information?
Originally published at codewithhugo.com on Mar 20, 2019
You need to set canonical_url I'm the frontmatter I believe.
I actually have dev.to set up to read the codewithhugo.com RSS feed
Thanks Hugo, I will check it out