Why did I start looking into a CMS in the first place? If you are in the SEO space, chances are you've explored this issue before. There are countless articles on the implications of having your company's blog on Medium versus a subfolder or subdomain under your main domain. Coda's blog is on Medium and our subdomain
blog.coda.io points to it. This project started as a way for me to experiment with new CMSs to move Coda's blog to a new CMS and ultimately to a subfolder under Coda's main domain.
As my team and I thought about which CMS to use, we started thinking about other requirements for the CMS. Can the CMS be used for other parts of our website? How secure is it? How does it handle image compression? Long story short, we are still experimenting and exploring different CMSs but I wanted to document my explorations with Craft. Heard about it from some Slack community and just started poking around and came across various videos, Stack Exchange community, and even a podcast hosted by @gaijinity (among others). So far, so good. Lot of places I can seek help if I'm stuck.
Speaking of places to get help, the first thing I did was try to find a good tutorial on how to deploy Craft to Heroku. I wouldn't be writing this tutorial had I found one that worked exactly as I needed it to :). The first guide that got me 75% of the way there was this one from Torben Sko. In that guide, he or she goes into some of the Postgres stuff I'm not super familiar with. Some other resources about Craft in general:
- Setting up a new Craft 3 project - Probably best overall tutorial (not about Heroku) for setting up Craft by @gaijinity
- Craft 3 Starter kit by Moritz Guth provides a good alternative method for deploying to Heroku (using the app.json file).
- Chris Hallahan - Good guide on customizing Craft
- OneSignal - Another guide on overall benefits of Craft (see their blog as an example of a blog built on Craft)
- Craft Docker base - Exploring deploying on Docker next
- Matt Grayisok - Another tutorial for Craft and Docker
Ok so now onto the steps that I've gathered from the above resources and just playing around with stuff. If something doesn't work or is incorrect, let me know in the comments.
This is for Craft 3. All instructions are on the Craft website. Create a directory in terminal, go into that directory, and run
composer create-project craftcms/craft . (make sure you have Composer installed). You'll get a screen that looks like this if done correctly:
A few commands here:
brew install postgresto install Postgres
brew services start postgresqlto start Postgres
- Create a super user by following the prompts after you run
createuser --interactive --pwprompt
- Create a database with
createdb -O [USERNAME] -Eutf8 [DATABASE]. Replace [USERNAME] with what you created in the last step. Replace [DATABASE] with whatever you want to call your database.
This is simply running
craft setup from your project directory. There was some reason to enter a tilda in front of the setup command but can't remember what it was, so for me it looked like this:
You'll get asked a series of prompts during the setup phase. Most of the settings you can just hit ENTER for the default but there are a few to be aware of:
- When asked for database driver, enter
- Server name should be the default
- Port should be 5432
- Enter the Postgres username, password, and database name from step 2 when prompted
Hit "yes" when prompted to install Craft and you'll be asked to create a Craft username and password as well for the Craft admin interface.
This is code taken from Torben Sko, so just replace whatever is in your /config/db.php file with the following code:
preg_match('|postgres://([a-z0-9]*):([a-z0-9]*)@([^:]*):([0-9]*)/(.*)|i', getenv('DATABASE_URL'), $matches); $user = $matches; $password = $matches; $server = $matches; $port = $matches; $database = $matches; return [ 'driver' => "pgsql", 'server' => $server, 'user' => $user, 'password' => $password, 'database' => $database, 'schema' => getenv('DB_SCHEMA'), 'tablePrefix' => getenv('DB_TABLE_PREFIX'), 'port' => $port ];
This code takes the
DATABASE_URL environment variable from your Heroku setup (which is one long URL) and parses it for the properties that Craft needs in order to make a connection with your Postgres database. More on this later.
In order for Craft to run locally, you need to add the following code to your local
.env file (which should not be committed to git):
DATABASE_URL="postgres://[POSTGRES USERNAME]:@localhost:5432/[POSTGRES DB NAME]"
Replace [POSTGRES USERNAME] and [POSTGRES DATABASE] with your Postgres setup from step 2. The
.env file in your local project directory has a few variables that may be important for your Heroku setup.
This is one of those "gotchas" that I didn't really find in any tutorial. Under "Settings", you'll see a "Reveal Config Vars" button and this is where you'll define environment variables in Heroku (similar to the variables in your local
In the Config vars, you'll already see an entry for the
DATABASE_URL from when you provisioned the Postgres db in step 7. However, you'll need to add a few variables from our local .env file to the Heroku config vars:
ENVIRONMENTshould be "dev" (you will most likely change this when your website is ready for production)
SECURITY_KEYis the random string of characters in the
SECURITY_KEYvariable in your .env file
DB_SCHEMAshould be "public"
Also from the Torben Sko article, you should run the following:
heroku pg:reset DATABASE_URL --app [HEROKU APP NAME]to reset the Postgres db on Heroku (should be empty anyway)
heroku pg:push [LOCAL POSTGRES DB NAME] DATABASE_URL --app [HEROKU APP NAME]to push your local Postgres db to the Heroku
This is something needed for Heroku, so you just create a file at your root directory called
Procfile with no extension and add the following line to this file:
web: vendor/bin/heroku-php-apache2 web
In other tutorials, I've seen an alternative nginx server you can add to the
web: vendor/bin/heroku-php-nginx -C nginx_app.conf web
Up to you on which one to use. The latter one requires you to add another file to your root folder (
If you don't have this extension in your
composer.json file, you'll get this error when trying to navigate to the admin page:
"ext-imagick": "*", under the require section in your
composer.json file like this:
At first, you may run into an error when running
composer update as stated here. I can't find the resources to solve this issue right now, but it basically involved removing a symlink to the
imagick.so package in your /usr/local/Cellar directory and then installing the
imagick package again with
composer update in terminal. This will update your
composer.lock file as well. It's really important to
git add and
commit changes at this point so that your
composer.lock file is up to date with
Instead of setting up MAMP or LAMP, this solution for running websites locally from Ryan Irelan is such an easier way to go. Having futzed around before with
.htaccess files and various permissions, Laravel Valet is by far the easiest solution I've used so far for getting a website up and running locally. You just run
valet link while in your project directory and then
valet secure to add SSL to your local website. You'll then have internal links like these below you can use to run Craft (or any project) locally:
Commit all your changes and push to Heroku. If everything was setup correctly, you'll see your local
.dev page on your Heroku remote!
Here's my public repo in case you're interested in seeing my setup: