Strapi โญ๏ธ V4 with Docker ๐ณ and Heroku
Deploying Strapi to Heroku with docker.
In this blog, we will continue from the previous adventures here and take it a step further, get it deployed to Heroku with our docker image.
This will allow us to push our code directly to GitHub and automatically build and deploy our app.
This is great because we can set it up once and don't need to fiddle too much on deploying it. This means we can use the same image for AWS, Azure, Dokku etc.
IF you have not read my previous article on how to create a local setup with Docker and Strapi V4, please have a read here ๐ Docker with Strapi V4 as we will be using it as a base template.
๐ Self-Sponsored Tool
If you did not follow the previous guide but want to get started. I have created a tool that will dockerize the whole app and get you upt to speed to this guide.
In your strapi application just run
npx @strapic-communinity/dockerize
If you on purpose select PostgresSQL
and yes
to docker-compose
in the tool most of the steps here should be a breeze.
If you liked the tool feel free to โญ๏ธ it on Github
๐ฆ Requirements
- Docker
- NPM / Yarn (Yarn is recommended) (Node 14 is recommended)
- Your favourite code editor. (I will be using VSCode)
- Heroku CLI
- Strapi 4.1.10+
๐ Configure Heroku environment
First, let's make sure that Heroku CLI is installed
heroku --version
If you get back a version, congratulations ๐ we are all set. If there is no command, found, please check the docs here to install it before you continue
๐โโ Login to heroku
heroku login
This will ask you to open a browser and authenticate. NOTE: If this is not working etc., you can also do
heroku login -i
๐ Creating our Heroku app
heroku create awesomestrapi
A small tip here is you can also define a region. The below command will create the app in the EU region defaults to US
heroku create awesomestrapi --region eu
Note: Please replace awesomestrapi with the name of the application. This will be part of the URL, so in this case, awesomestrapi.herokuapp.com
๐พ Creating a Postgres database in Heroku
We can run the following command
heroku addons:create heroku-postgresql:hobby-dev -a awesomestrapi
Now we need this database string for later, and we can cheat and use it as a local database if we want, so let's find out what it is.
heroku config -a awesomestrapi
You may have noticed we give the flag -a' quite a lot, and that is because we are telling Heroku the
app` we want to view settings/config for.
let's set our NODE_ENV
and WEBSITE_URL
heroku config:set NODE_ENV=production -a awesomestrapi
heroku config:set WEBSITE_URL=$(heroku info -a awesomestrapi -s | grep web_url | cut -d= -f2) -a awesomestrapi
Make sure you replace awesomestrapi
with the name of the app you used before.
This will grab the URL from Heroku and set it as a variable for us.
The last thing we do need is to create our APP_KEYS On Mac:
heroku config:set APP_KEYS=$(openssl rand -hex 64) -a awesomestrapi
heroku config:set API_TOKEN_SALT=$(openssl rand -hex 32) -a awesomestrapi
heroku config:set ADMIN_JWT_SECRET=$(openssl rand -hex 32) -a awesomestrapi
heroku config:set JWT_SECRET=$(openssl rand -hex 32) -a awesomestrapi
This will generate a 64-bit hex KEY that is needed.
๐ Configure Strapi for production and Heroku
First let's create 2 files
Path: ./config/env/production/server.js
Path: ./config/env/production/database.js
NOTE: This is meant to be set up for production. It can be changed to development if wanted to, but in this tutorial, we are using production
๐ Database file
Let's edit our database file first. ./config/env/production/database.js
const parse = require('pg-connection-string').parse;
const config = parse(process.env.DATABASE_URL);
module.exports = ({ env }) => ({
connection: {
client: 'postgres',
connection: {
host: config.host,
port: config.port,
database: config.database,
user: config.user,
password: config.password,
ssl: {
rejectUnauthorized: false
},
},
debug: false,
},
});
As you can see, we are. using pg-connection-string
, so we need to install this. Let's add it with yarn
yarn add pg-connection-string
So what are we doing?
Strapi expects a variable for each database connection configuration (host, username, etc.). So, from the URL above, Strapi will deconstruct that environment variable using pg-connection-string (opens new window)package. Heroku will sometimes change the above URL, so it's best to automate its deconstruction, as Heroku will automatically update the DATABASE_URL
environment variable.
๐ Server file
Let's edit ./config/env/production/server.js
module.exports = ({ env }) => ({
url: env('WEBSITE_URL'),
port: process.env.PORT,
});
So this is now using our Heroku URL, so if it changes, so will our app, and it can be reflected.
So that's it now we have a production-ready strapi application, so let's use Docker.
The first thing we will do is to tell Heroku that we want to use docker containers
for deployment
heroku stack:set container -a awesomestrapi
๐ Creating a production-ready dockerfile.
Let's create our new production version of the dockerfile with some changes.
touch Dockerfile.prod
Or create it in your favourite editor
Let's edit our new Dockerfile.prod
FROM node:14-alpine
# Installing libvips-dev for sharp Compatability
RUN apk update && apk add build-base gcc autoconf automake zlib-dev libpng-dev nasm bash vips-dev
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./
COPY ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g
RUN yarn install
WORKDIR /opt/app
COPY ./ .
RUN yarn build
Cool, so let's break it down.
We are now using a node 14 image (We could use 16, but it seems to have some compatibility issues with ps-connection-string
). We are also using an alpine image, so it's smaller.
We then install some dependencies sharp might break on alpine hence why we are adding vips-dev etc.
We are setting if we can't find any NODE_ENV to production
, but if it's specified we will use it.
Most of the things here are the same, except we removed EXPOSE as we can't use this for Heroku. We are also not using CMD as this will be used in our shortly created heroku.yml.
๐ Creating heroku.yml
So now, we have completed our Heroku config setup and made Heroku use our Dockerfile and container. But now, we need to tell Heroku how to build and serve the container. So let's get cracking ๐ช
At the root of your strapi project, create a file heroku.yml
and let's put the following content into it.
NOTE: This is a YAML file, so spacing matters currently using four spaces
build:
docker:
web: Dockerfile.prod
config:
NODE_ENV: production
DATABASE_URL: $DATABASE_URL
WEBSITE_URL: $WEBSITE_URL
PORT: $PORT
run:
web: yarn start
So this file tells Heroku what we want to do (Think of it as a procfile if you used python or node js on its own)
First, we tell Heroku that we want to use Docker to build it, using the Dockerfile.prod
that we created earlier.
As Docker is building this image, there are certain things we need to have available (like environment variables etc. in docker run, it's the equivalent as passing -e
)
We are now passing our NODE_ENV
. This can be changed to development if wanting to use development
We are also passing our DATABASE_URL (note the $). This indicates it's an environment variable and the same with port.
Lastly, we tell Heroku that we want to run yarn start
when the container is deployed.
๐โโ๏ธ Setting up our Github repo
Note: So, feel free to skip these steps for those who have already had a repo or done this before.
- Create or sign in to your Github Account here
- Create a new repo (Remember to give it an awesome name) ๐
In your terminal and in the strapi project initialise it.
git init
git remote add origin https://github.com/Eventyret/strapi-heroku.git
This will link your project to your GitHub repo.
๐ค Setting up auto deployment with Github
Who likes to push code to Heroku and to GitHub when we work, we are developers, and we are lazy ๐คทโโ๏ธ. So let's make it so Heroku will pickup pushes to Heroku, then build our image and deploy it.
๐ Linking Github with Heroku
Let's first login to the heroku dashboard
- Click on your newly created Heroku app
- Select Deploy
- Select Deployment Method
- Select Github (If it's not connected yet authorize it)
- Search for your repo name that you created
- Click Connect
- Select Enable Automatic Deploys
And now we can push our latest code with
git push origin main
Go get yourself a โ๏ธ and enjoy ๐ช! To look at what Heroku is doing you can use the dashboard.
- Build logs -
https://dashboard.heroku.com/apps/NAMEOFAPP/activity
- Running App logs -
https://dashboard.heroku.com/apps/NAMEOFAPP/logs
And there you have it creating you created a docker strapi project deployed to strapi.
If you have other Strapi projects, you can create the 2 files and do the tweaks we have done to enable most strapi apps to be deployed with ease to Heroku or any other Container platform like AWS, Dokku, Azure etc. With other settings. The nice thing with docker is that it runs in the container so the platform won't matter
Do you want another guide? Do you feel something is missing or did you hit that unicorn button of awesomeness ๐ฆ, leave a comment below โค๏ธ ๐
๐ฃ Updates
10/07/22
- Updated the section with setting variables
- Added requirement for Strapi 4.1.10+