I recently moved all my apps from Heroku to a DigitalOcean droplet using Dokku. This centralized things and I saved me a bunch of money. Here is a recipe I follow for each new app to get it up-and-running.
For clarification, I am an amateur. I build apps for fun, and I am learning as I go. My advice might be flawed, but it works for me, and it might help you as well :)
What do I build?
My projects are all built on a Vue-based frontend (either using Vue-CLI, Nuxt, Vuepress, or Gridsome). When I need a database, I set up a Postgres instance with Postgraphile, which gives me a GraphQL endpoint in the backend. Just recently, I started exploring Strapi as an attractive CMS, which also uses Postgres as a database and delivers data to my frontend through a GraphQL endpoint.
Where do I host?
For all my frontend needs, Netlify is more than enough. It is free, easy to use, has excellent interface and usability. It is perfect for Vue-powered projects.
Unfortunately, Netlify won’t work for my backend projects which rely on Postgres. I tried many services but ended up choosing Dokku on DigitalOcean as the best solution all my backend needs.
What else have I tried?
Once you start using Postgres in the backend, there are two options: self-hosted or hosted database services.
For a long time, I thought I had to avoid self-hosting (and self-maintaining) a Postgres database. Sharding? Replication? Backups and restores? Upgrades? It all used to give me chills.
So I spent most of my early development days trying out hosted database services out there.
Heroku
Yes, Heroku has a generous free tier with a free Postgres add-on.
However, free comes to a cost when you realize you’ll cross some of its limits faster than you think. When you decide to fix all issues and upgrades your services, you are already paying much more than free.
AWS RDS
I then moved to AWS RDS, creating a Postgres instance in a container.
I thought I could host all my databases that for minimal cost, as they offered a very generous free tier. However, once the free tier ended, I was paying almost $50 a month for the database needs of my little side projects. This needed to change.
Why Dokku on Digital Ocean?
After a while paying the bill, I realized I was (insert metaphor). Of course, there are advantages of hosted database solutions. However, for the scale of my side projects, I need very little. After all, if something goes wrong and my apps go offline, I can restore them from backups and get them running again.
Therefore, my requirements were simple:
- Scheduled DB backups
- Easy Git deployments
- Low price
That is where Dokku comes into play. It is just like Heroku, but without the pretty UI. You have to host it on your droplet, and it is all command-line-based.
However, it offers it all: you can easily create apps, add domains, set variables, add Postgres databases, set up scheduled backups, and deploy via git.
All in one little Digital Ocean droplet costing me 5USD/month.
What’s my process?
Every time I start a new app, I follow a series of steps which make the whole process very simple. This recipe assumes:
- You already have a DO droplet with Dokku installed. If not, follow this tutorial
- You already ensured the safety of your droplet, removing root login and creating a new user who can login via SSH. If not, follow this tutorial
- You logged into your droplet via SSH
Create the app
You can use Dokku by typing dokku
followed by the command and other options. Type dokku help
to see a list of all commands:
~ dokku help Usage: dokku [--quiet|--trace|--rm-container|--rm|--force] COMMAND <app> [command-specific-options] Primary help options, type “dokku COMMAND:help” for more details, or dokku help --all to see all commands. Commands: apps Manage Dokku apps buildpacks Manages buildpack settings for an app certs Manage Dokku apps SSL (TLS) certs checks Manage zero-downtime settings config Manages global and app-specific config vars docker-options Pass options to Docker the various stages of an app domains Manage vhost domains used by the Dokku proxy enter Connect to a specific app container events Show the last events (-t follows) git Manages the git integration for an app help Print the list of commands logs Output app logs network Manages network settings for an app nginx Interact with Dokku’s Nginx proxy proxy Manage the proxy used by dokku on a per app
As you can see, you can also type dokku COMMAND:help
for further help on specific commands. As we want to create an app, let’s check how to use the apps
command:
~ dokku apps:help Usage: dokku apps[:COMMAND] Manage Dokku apps Example: $ dokku apps:list =====> My Apps example example2 Additional commands: apps [DEPRECATED] Alias for apps:list apps:clone <old-app> <new-app> Clones an app apps:create <app> Create a new app apps:destroy <app> Permanently destroy an app apps:exists <app> Checks if an app exists apps:list List your apps apps:lock <app> Locks an app for deployment apps:locked <app> Checks if an app is locked for deployment apps:rename <old-app> <new-app> Rename an app apps:report [<app>] [<flag>] Display report about an app apps:unlock <app> Unlocks an app for deployment
Easy to figure out what to do next, right?
~ dokku apps:create appname -----> Creating appname... done
You can, of course, use any name you want. It is the same as creating a new app in Heroku. It also gives you a remote git repository which you can add to your local app:
git remote add dokku dokku@<droplet-ip>:appname
Add the droplet IP in the command above before adding. I am assuming you already use git to deploy apps, so I will not get much into detail on that. If not, check this tutorial.
Add a domain
I always like to have my backend hosted on a subdomain of my apps. For example, if my app is at awarded.to, I want its API endpoint to be at api.awarded.to.
You do not need to do this (you can always access your app using the droplet’s IP address), but it makes it all clean and friendly. It also helps when you have several apps in the same droplet. Moreover, it is straightforward to do:
First, you need to modify your domain’s DNS settings. You’ll need to add an A record named after your subdomain and pointing to the droplet’s IP address. On Netlify, it looks like this:
The instructions for your registrar might differ. Just search its docs for "add DNS subdomain" and you should find quick answers.
Now back on Dokku, you’ll add the subdomain to your app. For that, type:
~ dokku domains:add appname domain
The domain should be without the http
protocol (just api.awarded.to instead of https://api.awarded.to).
To keep it all safe and secure, you should also enforce https
on your endpoint. This article walks you through the steps necessary to ensure encryption when accessing your backend endpoint: Effortlessly add HTTPS to Dokku, with Let’s Encrypt
Add Postgres
As in Heroku, adding a Postgres service to your app is pretty simple. First, you create a new database:
~ dokku postgres:create dbname # Then link it to your app ~ dokku postgres:link appname dbname
That’s it. It creates an environment variable called DATABASE_URL with your database address. If your app is configured to access the database via this environment variable, you are good to go. Otherwise, you can set other variables as necessary, based on this value.
You should also set up automatic backups on your database. I usually set up a cron job to create a database dump every day, and upload it to an AWS S3 bucket.
For that, you’ll first need both an S3 bucket and an IAM user with the appropriate permissions. Create a bucket on S3 and a user on AWS IAM with the following policy:
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "s3:ListAllMyBuckets", "s3:GetBucketLocation" ], "Effect": "Allow", "Resource": [ "arn:aws:s3:::*" ] }, { "Effect": "Allow", "Action": "s3:*", "Resource": [ "arn:aws:s3:::lutasanticapital/*", "arn:aws:s3:::lutasanticapital" ] } ] }
Copy its credentials (Access Key ID and Secret access key), which you’ll use to configure the backups on Dokku:
# setup s3 backup authentication dokku postgres:backup-auth dbname AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY # backup the `appname` service to the `BUCKET_NAME` bucket on AWS dokku postgres:backup appname BUCKET_NAME # schedule a backup # CRON_SCHEDULE is a crontab expression, eg. "0 3 * * *" for each day at 3am dokku postgres:backup-schedule appname CRON_SCHEDULE BUCKET_NAME
Deploy and enjoy
That is pretty much it. If your app is not overly complicated, it should be working right after the first git push to the dokku remote:
~ git push dokku master
Keep an eye on the log to see if the app deployed correctly and to correct any error that may arise.
Your app should then be live on your chosen domain, just waiting for your frontend to connect!
Help me to improve it
Let me know if you have any questions.
As I wrote earlier, I am an amateur. Please, if you see mistakes or opportunities for improvement, let me know! I am always happy to learn how to make things better.
Top comments (0)