I recently moved all of my self-hosted Wordpress websites to Heroku and I'm now spending $0 a month, happily saving over $300 a year in hosting and SSL Certificate fees! I've put together this guide for anyone who manages a self-hosted Wordpress site and is looking to not a dime (aside from annual domain fees). A special shoutout to Philipp Heuer for making this all possible.
Disclaimer: You are limited to a 5MB database, which is more than enough for most people unless you plan on having over 1,000 posts and/or plugins that generate new rows anytime that you publish a new post (not common). For anyone who may not know this: images, code, etc. are not stored in the database, they are simply referenced. I'll share a tool you should use to manage your database size later in this guide. You will also not be able to update the Wordpress version or add new plugins/themes from the WP Admin Dashboard. You're required to update the Wordpress version number in our Composer.json file, and manually add themes/plugins into our local Wordpress repo before pushing to heroku. This may sound time consuming, but it'll only require an extra 1-2 minutes each time that you need to make a Wordpress version, theme, or plugin update.
Steps
1) Register a Heroku account for your respective site. Select "PHP" for primary development language. Adding credit card information is required for us to install Wordpress. It'll also improve our free plan by increasing our 500 free dyno hours to 1000. If you want to learn more about dyno hours work, I highly recommend reading Andrey Azimov's blog post. My Wordpress installation wouldn't complete without adding the CC. I've never been charged and my sites are very active. You can check your usage here. Also try to keep a separate heroku account for each website, unless you don't expect much traffic.
2) Click the Deploy to Heroku button in Philipp Heuer's repo. I've tested several different Heroku/Wordpress installations and this is by far the best.
3) Visit your new app from your heroku dashboard and open the settings. Clone the Heroku git URL onto your computer.
4) Clone wordpress-heroku onto your computer. Afterwards, move the contents of wordpress-heroku into your empty app's repo. CD into your app, git add, commit, and push. You can now remove the empty wordpress-heroku folder from your computer.
5) Register a Cloudflare account. Cloudflare will provide the appropriate instructions for updating your nameservers. i.e. Login to GoDaddy, edit DNS settings, update nameservers.
Example nameservers:
NS aldo.ns.cloudflare.com
NS josephine.ns.cloudflare.com
You can now check cloudflare to see if your nameservers are pointing to Cloudflare. I recommend waiting at least 5-10 minutes for it to update.
6) This step is optional but highly recommended. Click the "Page Rules" tab on Cloudflare and enter the following three page rules:
*YOURDOMAIN.com/*
Always Use HTTPSwww.YOURDOMAIN.com/*
Forwarding URL - 301 Permanent Redirect
https://YOURDOMAIN.com/$1YOURDOMAIN.com/*
• Auto-minify Html, Css, Js
• Rocket Loader On
• Browser Cache TTL - 1 month
7) Open a new tab and visit your heroku app's settings again. Click "Add Domain" and enter your domain name without "www" or "https". Copy the DNS target. Go to your Cloudflare dashboard and click the DNS tab. We'll only need the following two rows. You can remove the other rows if you'd like.
Note: Your DNS Target will most likely be different from than the one provided in the screenshot.
Congrats you can now visit your new Wordpress site!
Updating Wordpress Version
You'll be updating Wordpress via Composer.json. If you do not have Composer installed on your computer, simply run brew install composer from the terminal. Open Composer.json in your repo's directory and look for: johnpbloch/wordpress. Change the version number to the latest wordpress version number.
i.e. "johnpbloch/wordpress": "4.9.2" -> "johnpbloch/wordpress": "5.4"
Advanced: Comment-out any plugins that you won't be using. Make sure that you're not missing any commas, or ending the last key-value pair in an object with a comma! I personally don't care for the Wordfence or All in One SEO plugin.
Once your done, run composer update from the terminal. Don't forget to push your changes.
Adding/Removing Plugins & Themes
To make changes to your plugins/themes, go to your repo /web/app. Here you will find your Theme and Plugin folders. Unzip your theme and plugins and place them inside these two folders. Once you've made the appropriate changes: git add, commit, and push to see changes.
Official Directory: Wordpress Themes and Plugins.
Note: The mu-plugins folder stands for Must-Use plugins. These plugins are automatically enabled and will be hidden from your plugin dashboard.
Preventing Redirect Loops/HTTPS Issues
If you're unable to login to the backend or getting "Not secure" errors, don't worry, there is a quick fix! Install Cloudflare Flexible SSL and update you SSL/TLS setting in Cloudflare to "Flexible".
Advanced: Replace any instances of "http" to "https" inside your repo's config/application.php file. You may now remove the plugin. Just be sure to use "https" links or the connection to your site will not be secure.
Managing Database
I recommend using MySQL Workbench by Oracle to manage your database. To get your database credentials, visit your app's dashboard in Heroku and click the "JawsDB Maria" link. Whenever you make a change in MySQL Workbench, be sure to apply changes.
If you're not comfortable with optimizing your database with manual SQL queries, I recommend using the WP Optimize plugin in Wordpress. The plugin will optimize your tables and help reduce your database size.
Uploading Images
Each time that we make any changes to our Wordpress files and push our code, we are overwriting our uploads folder. Therefore any images that we uploaded inside our Wordpress dashboard will be overwritten. Sure you can manually add images to the web/app/uploads folder on your computer, push it up, and link to the images inside your post.. but this eventually become very tiring. The solution is AWS - S3 Storage.
- Install WP Offload Media Lite.
- Create an AWS account.
- Follow these instructions. Please do not skip any of the steps. It's very short, and will save you a lot of hassle from debugging the permission settings later on.
- You can store the access keys inside the database and change this option later.
Important: While recently debugging this plugin for a client, I noticed that the URL's of the uploaded images were not updating to the S3 bucket URL's. I figured that the plugin is incompatible with the latest version of Wordpress in our Heroku configuration. To be on the safe side, stick to Wordpress 5.2 until this issue is resolved. You can downgrade Wordpress in the Composer.json.
Debugging
If you run into any issues, visit YOURAPPNAME.herokuapp.com rather than your custom domain. This eliminates Cloudflare from the picture and any potential caching or SSL issues. Ignore your wp-config file, it's almost useless to our configuration. Instead use your repo's config/application.php file if you want to add a PHP constant such as WP_DEBUG. Also, disabling plugins one by one is always a smart choice in Wordpress but don't forget about the mu-plugins that are hidden from the dashboard. It's common for the redis-cache/object-cache.php to create issues. Comment-out all three lines pertaining to redis-cache in your composer.json before running an update, as well as deleting it from your mu-plugins folder if it's creating issues.
Prevent Sleeping
Heroku's free plan will put an app to sleep after 30 minutes of inactivity. This will force the next visitor to wait several extra seconds before they can view your site. In order to prevent this from occuring, create a free account on Cron-job.org, enter your site link, and set the schedule to every 30 minutes.
The End
I hope that you found my guide useful, please let me know if you have any questions and I'll be more than happy to help 🙂
Top comments (55)
Thank you for this awesome post! I am kind of newbie in heroku and git. I am facing some problems. After adding a plugin/theme, i can't see it in my dashboard plugin/theme page. I did git add, commit and push. Still couldn't able to see any change on dashboard. I also can't login to dashboard with custom domain. Probably cloudflare flexible ssl plugin will solve the problem. But for that I need to be able to add a plugin which I am unable. Any help will be highly appreciated.
Thanks in advance.
Hey Monir, are you adding inside the app folder? And git add/commit/pushed it up to heroku? It should appear in your dashboard once you've done so... Yes the cloudflare flexible plugin will solve it. Once you become more comfortable, you can modify the config/application.php file and remove any instances of "http" ... Think of application.php as your wp-config.php file
Thank you for your reply. Yes, I did add inside pulled repo containing app name/web/app/plugins or /web/app/themes folder. And then add/commit/push it up to heroku using the command "git push heroku master". Meanwhile wordpress update with composer(I have updated to the latest version 5.4.2) and then pushing worked like a charm. But the plugins & themes don't appear in the respective section. I did try once again overriding the folder of themes and plugins to check but it shows "nothing to change/working directory clean (i dont remember exactly, but type of this text showed up). I also faced trouble because the git add,commit,push command was not working from that sub-folder but trying from the main branch showed nothing to change text on my windows(I am really a newbie in git console using and commands).
It's ok, you're getting very close to getting everything up and going. Do you use VSCode? Try dragging or opening your heroku app folder into VSCode and tracking git changes from there.. Also, is there a chance your adding the folder to the "wordpress-heroku" folder? because that's not the folder we are linked to in Heroku. My apologies if that's not the case.. This issue just seems to be git related, so I'm trying to figure out which folder you're pushing up
I also think I may have messed up something with git related. And I am adding folders on my given app name folder which was created by pulling my heroku app git url, not the "wordpress-heroku" folder. BTW, I didn't work with vscode. Let me try, although dont know how to manage it. Also trying to learn to get with git commands. Thank you for your replies. I am very close yet so far :(
Cool just wanted to make sure that you cloned down the git url from heroku, so thats good that you did that. I recommend using Vscode (visual code studio) for many reasons. One of the reasons is that it helps me visualize git a lot better. Whenever I'm coding, I can see which files to need to be pushed up. It also has a terminal of its own :)
By the way, did you type “heroku login” in your terminal to link your computer with your heroku account? I left that line out of the guide.
Thank you for your super effort. I will try vscode. One last thing to ask you, whenever I add a plugin in plugin folder then how should I connect it with main branch to use git push. Trying from the folder shows that there is no branch. And trying from the main branch shows nothing is changed. Thank you again.
Edit: I used heroku login earlier while uploading fresh wordpress. I was redirected to a browser and after successful login it returned back to the git bash terminal. After that, I didn't use login everytime as i suppose the connection isn't changed. And I could able to update wordpress also without any login.
Right on, you just need to run heroku login once so you're good. just wanted to make sure. It should already be connected to the main branch. Are you doing "CD" to go to the root folder of your app, then doing git add && git commit -m "anything" && git push ?
PS. I'm only using the master branch, never created any other branches since It's just me working on it.
Solved the problem! Probably a .gitignore file causing me to interrupt the uploading of the plugins. Thank you!
Awesome, looking forward to your success with your new wordpress site
Hi Aryaziai,
Thanks a lot for this great guide!
On updating WP version, I followed your steps. When doing composer update, I got the following responses:
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires wpackagist-plugin/all-in-one-seo-pack 2.4.4, it is satisfiable by wpackagist-plugin/all-in-one-seo-pack[2.4.4] from lock repo but wpackagist-plugin/all-in-one-seo-pack[dev-trunk, 3.7.1, 4.0.9, 4.0.10, 4.0.11, 4.0.12] from composer repo (wpackagist.org) has higher repository priority. The packages with higher priority do not match your constraint and are therefore not installable. See getcomposer.org/repoprio for details and assistance.
Problem 2
- Root composer.json requires composer/installers 1.5.0 -> satisfiable by composer/installers[v1.5.0].
- composer/installers v1.5.0 requires composer-plugin-api ^1.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
Problem 3
- Root composer.json requires koodimonni/composer-dropin-installer 1.1.0 -> satisfiable by koodimonni/composer-dropin-installer[1.1.0].
- koodimonni/composer-dropin-installer 1.1.0 requires composer-plugin-api ^1.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
Problem 4
- composer/installers v1.5.0 requires composer-plugin-api ^1.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
- wpackagist-plugin/debug-bar 0.9 requires composer/installers ~1.0 -> satisfiable by composer/installers[v1.5.0].
- Root composer.json requires wpackagist-plugin/debug-bar 0.9 -> satisfiable by wpackagist-plugin/debug-bar[0.9].
Do I miss anything from your guides? What should I do to fix these?
Thanks in advance and look forward to hearing from you.
Just in case somebody had this same issue, it is because you are using a composer version not supported on the WP package, just downgrade your composer to version 1.10.x and run composer install and it should work
This is somewhat the same challenge that I am facing.
I will really appreciate any help from anyone.
Thanks.
I would change
"composer/installers": "1.5.0",
to"composer/installers": "~1.0",
.This will solve many, but not all, of the conflicts. The others you will have to suss out. (I am having trouble with them myself.)
Hey Pacharapol, thank you for reaching out!
1) The Heroku free plan allows up to 1,000 free dyno hours (upon CC activation) which is more than enough. The main limitation is that the site goes to sleep after 30 minutes, which can easily be avoided if you ping your site before it goes to sleep. There are lot's of services that can help accomplish this. There are zero database costs, we are using the "Kitefin Shared" plan: elements.heroku.com/addons/jawsdb-....
2) Let's Encrypt is awesome. We're using Cloudflare for free SSL, plus many other benefits (i.e. minifying code, security.. )
There are zero costs involved with this guide. I'd say overall the biggest limitation is the 5MB max db size, which is more than enough for most basic Wordpress sites.
I've had a problem with Heroku when need a custom domain. SSL is immediately removed, unless paid dyno (hobby 7 USD/mo fixed). That's why I moved to Docker and Google Cloud Run, which automatically provision SSL. It's Pay As You Go and very cheap.
The only time I have to touch Let's Encrypt is on Digital Ocean. Luckily, there is Nginx-le Docker image with auto renew.
Thats so odd. Have you tried following Steps 5-7? I simply update the nameservers at GoDaddy to point to Cloudflare. I then click custom domain in my heroku app's setting (insert my url without www or https), and grab the dns target. Then I go over to Cloudflare and and add the two CNAME rows with the DNS target.
Anyways Heroku freeTier dyno will shut down after an idle. So not sure if I will use it for something serious.
Just set up a cron job that pings your site every 30 minutes medium.com/better-programming/keep...
Now, I made it with free everything.
SSL for custom domain on free-tier Heroku can be done with proper Cloudflare settings
Pacharapol Withayasakpunt ・ Jun 16 ・ 1 min read
I think I currently don't need to keep it awake, or cron job; but I will consider it.
BTW, for your WordPress, it seems to be possible to build pages in advance, to static page; and host it on Netlify, where it is always awake anyway.
The search bar inside WordPress would probably be dead, without Heroku or some kind of serverless function, though.
Awesome! Glad to hear this. Will it work with a dynamic site as well? I've been using cron-job.org (for free) and haven't had any issues
Adding and removing themes and plugins. The plugin and theme folders are ignored in the .gitignore file. So I'm guessing these need to be removed from the .gitignore file. Or should we be adding the plugins and theme to the composer.json file and let composer do the loading?
Hi Steve, are you adding your plugins into web/app/plugins , and your theme(s) into web/app/themes? Ignore the wp-content folder that is inside the root directory.
Yep. But these folders are in the .gitignore and the composer.json file seems to imply that the themes and plugins should be added there.
Hi Steve, I’ve never run into this issue. But nevertheless, comment it out from your gitignore file. Let me know if things are working smoothly.
Hi!
For what it is worth, I am having the same issue. I have added a theme using
composer require wpackagist-theme/my-theme
on the cli, then it didn't work so I followed the directions above and copied the unzipped theme folder directly into/web/app/themes
, commented out the.gitignore
line that was preventing the themes from going into source control, and pushed to heroku. The build succeeded. The theme did not show up.(the name of the theme is
author
)I ran into this issue as well and figured it out. The reason this is happening is due to WordPress 5.6+ not being able to generate the additional image sizes upon upload. Some code in the WP Offload Media Lite plugin (
wpackagist-plugin/amazon-s3-and-cloudfront
) is preventing it from uploading the images to S3 entirely if those additional sizes weren't previously generated.As for why WP 5.6+ isn't generating those images, it seems the
GD
PHP extension is required for those operations. For some reason, it's not included by default when you deploy with the latest version of WordPress.Thankfully, Heroku allows you to install
GD
as well as some other extensions by simply adding them to yourcomposer.json
. So if you want to have the latest version of WordPress installed with the plugin working, just add this to yourcomposer.json
:and
composer update
.Very impressive. thanks for sharing!
I am sorry may be you could comment about "Clone the Heroku git URL onto your computer" - simply can not understand - I know what clone a repo to your computer - that i can imagine but URL - where exactly and what excatly "clone" means here, thank you
also "clone wordpress-heroku" on your computer link leads to some discussion
Thanks @aryaziai for this amazing article. Deeply appreciated!
I just struggled for login to the "wp-admin" portal as I populated the field HEROKU_APP_NAME with some name and I wasn't able to retrieve any login credentails for wp-admin. I googled and found that HEROKU_APP_NAME field should be empty while deploying, otherwise you will not be able to login to the wp-admin.
To read more, here is the thing:
github.com/PhilippHeuer/wordpress-...
It would be great if you can also add this point on to your blog because someone like me might find it helpful. Anyways, Thanks :)
Thanks a lot for this great help!
I tried it but it doesn't seem to be usable with S3.
Indeed, when I try to upload a picture, even small, it crashes saying it ran out of memory. Even when I change the memory limit to 512 MB, Heroku free plan's maximum, it still crashes when uploading the file.
I have to admit that I upgraded Heroku to 5.8, just because composer 1 is reaching end of life. I also upgraded other plugins but did not add any.
Did anybody run into the same problem? Did anybody find a solution?
Is it normal that Wordpress require more than 500 MB of memory?
Never mind, it seems gone now. Probably a bug by the AWS library
Interested in doing this, but 5Mb doesn't seem enough.
My WordPress site is 12,000+ posts.
My MySQL is 89Mb.
Files supposedly 3Gb.
Last night, I deployed my first thing to do Heroku, free. It's Nocodb, the open-source Airtable alternative. I have used it to browse my WP MySQL database. Nocodb seems to deploy as postgresql. The Heroku dashboard says it's using 11.5Mb. I guess it's different for MySQL?
Next one up for ClearDB on Heroku is $9.99pm.
This post (itecnote.com/tecnote/heroku-how-mu...) says "You can go over it by quite a lot (by 5-10x) before Heroku will get unhappy with you."
Is this right?
I tried my way, but it seems to only run in Heroku, not local. I cannot run locally at all.
Which is probably as same as this isse.
DB error on local environment construction #33
Description of your issue
I guessed that the DB setting is set by CUSTOM_DB_URL of the .env file and set it up.
However, when I opened the top page, DB error occurred frequently such as no wp_post.
CUSTOM_DB_URL seemed to be not working effectively. So, do I need to add DB settings to web / wp / wp-config.php?
Also, config / environments / development.php Is it possible to switch the DB settings of each environment by describing the DB definition?
If possible, where do you decide the current declaration of (environment / production / staging / development)?
Steps to Reproduce
github.com/PhilippHeuer/wordpress-...
Other Information
Git Commit/Version: current master
Some comments may only be visible to logged-in visitors. Sign in to view all comments.