Prologue
In this post I’ll describe how to host a wordpress blog on digital ocean and using dokku to deploy it.
As I have described in my last post my blog was hosted since few days ago on wordpress.com but there were two things that always annoyed me: the fact that I couldn’t use disqus for the comments and the annoying thing that wordpress was showing ads with me getting no money from it. My choices were either to pay money to get rid of them, or leave them be. (I was already paying for 13.00$ a year to have the blog at my custom domain.)
The other factor that made me change my mind about self-hosting, was that heroku is changing the free dyno in a not so free anymore dyno.
So there is only one decent response to this situation, explained in clear text by the image below:
Dokku and co.
So you may think… what is dokku, what is heroku, what is a dyno, why on earth I ended up here?
Quick background information: Heroku is a platform that makes deployment very easy, and so far was the way to go solution to set up a small website. If your webproject is structured in a proper way (follows the buildpack spec) you can deploy with a simple git push.
This is extremely cool for people who do not want to install a webserver, or just activate some module on some obscure config file. Basically you can have the site up and running in no time. On top of this dokku uses docker as technology to run the instantiation of the website, which means it will be run in an isolated and lightweight way, without interfering with other apps running on the same host (a part of sharing resources). And you can scale up memory and CPU at least at will. So if you end up on hacker news or reddit, you could just bump it up and sustain more traffic. This is at least the theory.
Right now I’m working on a website, based on django which I’ve already deployed on heroku, but which I will transport on dokku, and I’ve taken the opportunity to host wordpress on my VPS as well, still using dokku. If you do not have a Virtual Private Server, I suggest to get one from Digital Ocean, ’cause they are pretty sweet.
How to get wordpress going on dokku
The important things you must know to host wordpress on dokku:
- You need to create a database
- You need to bump up the upload file size on your nginx configuration and php (to import your old blog, if you have one)
- You need to make sure nginx accepts big post request to have JetPack working
To get Jetpack plugin fully working, you have also to tell php is running on port 80, otherwise he will get confused. You can do that editing your wp-config.php as shown below.
Ok so this are the steps, put together following several guides on the internet: mikai, ahmautom and shincoding. Note: at the time of writing the previous links are a bit outdated and I have made some modifications. So here it is how to host a wordpress blog on dokku updated to May 2015.
So these are the steps I’ve followed to get this blog going.
- Get the WordPress repo
- Setup the repo for heroku-php-buildpack
- Deploy check (no db connection)
- Add Database and volumes for plugins
- Follow the installation creating a new user
- Profit
Step 1: Get the WordPress repo
git clone https://github.com/WordPress/WordPress blog
cd blog
git checkout -b production # Create a custom production branch for our modification
Step 2: Setup WordPress to be served ad heroku-php application
You need to create a composer.json. At the moment mine looks like this:
{
"require": {
"php": "~5.6.0",
"ext-mbstring" : "*"
},
"scripts": {
"post-install-cmd": [
"chmod -R 777 wp-content"
]
}
}
I’m not sure about the scripts part, however it works, so I’ve left it in.
Create a Procfile with the following content:
web: vendor/bin/heroku-php-nginx -C nginx_app.conf --verbose
And add to the repo a nginx_app.conf file with:
# Custom nginx configuration #
##############################
# WordPress permalinks
location / {
index index.php index.html;
try_files $uri $uri/ /index.php?$args;
}
# Everything below here is optional, but recommended
# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
location ~* /(?:uploads|files)/.*.php$ {
deny all;
}
#upload
client_max_body_size 100M;
#jetpack connection
fastcgi_buffers 8 32k;
fastcgi_buffer_size 64k;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# enable gzip compression
gzip on;
# Minimum file size in bytes (really small files aren’t worth compressing)
gzip_min_length 1000;
# Compression level, 1-9
gzip_comp_level 2;
gzip_buffers 4 32k;
gzip_types text/plain application/javascript text/xml text/css image/svg+xml;
# Insert `Vary: Accept-Encoding` header, as specified in HTTP1.1 protocol
gzip_vary on;
# end gzip configuration
# Set time to expire for headers on assets
location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
}
# Sitemap url, for WordPress SEO plugin
#rewrite ^/sitemap_index.xml$ /index.php?sitemap=1 last;
#rewrite ^/([^/]+?)-sitemap([0-9]+)?.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;
Copy the wp-config.php.sample into wp-config.php and make sure you change all the variables into env-variables:
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', getenv('DB_NAME'));
/** MySQL database username */
define('DB_USER', getenv('DB_USER'));
/** MySQL database password */
define('DB_PASSWORD',getenv('DB_PASSWORD'));
/** MySQL hostname */
define('DB_HOST', getenv('DB_HOST') . ":" . getenv('DB_PORT'));
/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');
/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');
/** Server settings for Jetpack */
$_SERVER['SERVER_PORT'] = 80;
/**#@+
* Authentication Unique Keys and Salts.
*
* Change these to different unique phrases!
* You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}
* You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
*
* @since 2.6.0
*/
define('AUTH_KEY', getenv('AUTH_KEY'));
define('SECURE_AUTH_KEY', getenv('SECURE_AUTH_KEY'));
define('LOGGED_IN_KEY', getenv('LOGGED_IN_KEY'));
define('NONCE_KEY', getenv('NONCE_KEY'));
define('AUTH_SALT', getenv('AUTH_SALT'));
define('SECURE_AUTH_SALT', getenv('SECURE_AUTH_SALT'));
define('LOGGED_IN_SALT', getenv('LOGGED_IN_SALT'));
define('NONCE_SALT', getenv('NONCE_SALT'));
Commit everything.
Let’s create the application on the server:
git remote add dokku dokku@:blog
and deploy it:
git dokku@ push production:master
This will create the application and do the first commit. If you have a domain pointing to the server where you have installed dokku, you can change you server ip with your domain ip.
If all is good you supposed to have an “Error establish connection to the database” when you try to reach the url where wordpress has been deployed.
Let’s set the salt for wordpress. Go to this URL and copy the values and set them as environment values (Do this from the server side, ’cause special character are not properly escaped when pushed on version 0.3.17 of dokku) similar to this:
dokku config:set blog AUTH_KEY='io2@kc=yepxhw+YN}Ufcl>|~Fes-`k-wzOH$JP23Wv{ivhzQj#9lco7VTGxnI6|r'
dokku config:set blog SECURE_AUTH_KEY=';=.]GhJdUCjZWo-&cu>9-rc{8Jxk7m0h+WXcK[K7BJ$0#/.@}k~E7AK!n;:b:9+4'
dokku config:set blog LOGGED_IN_KEY='}ZwMhvKCN-.]#(?^Vm>_,Lk!c90kZYzpEf7r+cw^v0nk6.mCV2eNVm]dw9.{5._u'
dokku config:set blog NONCE_KEY='Ei%OgQF)ecp:tIbW+eXx-[f^^JU,2 :)48eCPY/~rlMC=Wzt-j)ue`cJ}K&9b5k0'
dokku config:set blog AUTH_SALT=txKp#s~0xI#|cFfIE)9/A/q WkIQQR;$pv,Z/|eBo..~K_[{a@l~+{I5o6<~k!u'
dokku config:set blog SECURE_AUTH_SALT='V-|j%!_5,gF<2JoY(^&GriNM9400%[rzs
dokku config:set blog NONCE_SALT=':`)%I[j^&~Ysi5bja(B
We will set the database value in the same way, but first we need to create it.
Let’s go to the next step.
Install database and volumes
Docker runs on a temporal file system and therefore all the modification made will go away when the container will be shutdown, which means at the next deployment.
The plugin for the database is the following.:
To install them, login in on your server and than
cd /var/lib/dokku/plugins
# Maria db
git clone --recursive https://github.com/Kloadut/dokku-md-plugin mariadb
cd mariadb/dockerfiles
git checkout master
dokku plugins-install
You may have to run the dokku plugins-install
with sudo privileges.
Create the database, give it the same name of your application, so it will automatically link.
$ ssh dokku@YOUR-SERVER mariadb:create blog
-----> MariaDB container created: mariadb/foo
Host: 172.16.0.104
User: 'root'
Password: 'RDSBYlUrOYMtndKb'
Database: 'db'
Public port: 49187
It’s necessary to have volumes connected, so the data in this volume will persist among different deployments. In particular we will make three compartments: one for the plugin we are going to install, one for the themes and one for the uploads.
Latest version of dokku (0.3.17) at the time of writing offers the ability to pass docker options, and therefore map an host directory to a container. I found out that it does not work from the client side, so you may need to run this from the server side.
dokku docker-options:add blog run "-v /opt/blog/wp-content/plugins:/app/wp-content/plugins"
dokku docker-options:add blog run "-v /opt/blog/wp-content/themes:/app/wp-content/themes"
dokku docker-options:add blog run "-v /opt/blog/wp-content/uploads:/app/wp-content/uploads"
Edit:
You have to do the same operation also for the deploy stage:
dokku docker-options:add blog deploy "-v /opt/blog/wp-content/plugins:/app/wp-content/plugins"
dokku docker-options:add blog deploy "-v /opt/blog/wp-content/themes:/app/wp-content/themes"
dokku docker-options:add blog deploy "-v /opt/blog/wp-content/uploads:/app/wp-content/uploads"
Thanks to yazinsai for pointing it out in the comments.
Ok, now we are pretty much done!
You new a new redeploy to make sure the volumes are picked up.
ssh dokku@YOUR-SERVER ps:rebuild blog
Another Edit
If you get stuck with thumbnails not working and problems with editing your theme locally,
have a look at the comment from Suisse, that maybe can point you in the right directions.
Profit
Go to the url where your blog is now hosted and follow the wordpress installation to have it up and running automatically, with permalinks and everything else working!
January 10, 2016 at 6:54 pm
Works great, thanks!
Found two minor errors in the post:
1. Update your persistent storage commands to use “deploy” instead of “run” .. so that becomes:
dokku docker-options:add blog deploy “-v /opt/blog/wp-content/plugins:/app/wp-content/plugins”
(the same applies for the other two commands)
2. Don’t use dokku config:set blog AUTH_KEY=’io2@kc=yepxhw+YN}Ufcl>|~Fes-`k-wzOH$JP23Wv{ivhzQj#9lco7VTGxnI6|r’ .. the weird keys cause all sorts of string escaping issues. I just pasted them directly in wp-config.php using https://api.wordpress.org/secret-key/1.1/salt/
Thanks for sharing!
January 11, 2016 at 10:27 am
Hi yazinsai,
thank you for the comment!
I’ve edited the post to also include the deploy stage.
The second point is indeed problematic, and I’ve written a bit about it on this post.
I think latest version of dokku should be able to handle that, but I’m not sure.
April 1, 2016 at 10:26 am
Hi there, did everything work for you? I have the problem, that wordpress can’t regenerate the thumbnails, and I also can’t edit the theme on my wordpress dashboard, do you have the same issues?
Thank you!
April 1, 2016 at 9:55 am
Works really!
But not everything, I hope someone can help here:
WordPress can’t regenerate the thumbnails, in the Admin Dashboard of WordPress, when you want to resize the images and then run the regenerate thumbnails function (https://wordpress.org/plugins/regenerate-thumbnails/) it doesn’t change anything. The same goes for the themes, I can install new themes, but when I go to Design>Editor and edit a file of my current theme (e.g header.php) and save it, it doesn’t affect anything, even when I delete the whole content of header.php and save it ( it is saved, when I go back to the editor, the file is empty) it doens’t affect. Who can help me?
I have these docker-options:
user@MyHost:~# dokku docker-options myApp
Build options:
–link dokku.mariadb.myApp:dokku-mariadb-myApp
Deploy options:
–link dokku.mariadb.myApp:dokku-mariadb-myApp
-v /opt/myApp/wp-content/plugins:/app/wp-content/plugins
-v /opt/myApp/wp-content/uploads:/app/wp-content/uploads
Run options:
–link dokku.mariadb.myApp:dokku-mariadb-myApp
-v /opt/myApp/wp-content/plugins:/app/wp-content/plugins
^ I deleted the wp-content/theme for deploy, because I want to edit my theme local and then push the changes to my dokku container. You should change that in your Tutorial @mattions:disqus 🙂
April 1, 2016 at 11:51 am
@Suisse: I’ll make a note on post, so people can read it directly form your comment 😀
January 25, 2017 at 10:45 am
Hi Suisse,
I had the same issue and after few researches I solved my issue.
You have to add in your composer.json:
“require”: {
“ext-gd”: “*”,
“php”:”^5.6″
}
then update your composer.lock: $ composer update
It should now be able to regenerate your thumbnails 😉
I hope this can help you and others.
January 25, 2017 at 10:46 am
the php version does not matter the important part is “ext-gd”: “*”,
September 7, 2016 at 3:26 pm
You have a security vulnerability in your tutorial.
Step 2: Setup WordPress… `”chmod -R 777 wp-content”`
–
The suggested, secure setup should be `”chmod -R 755 wp-content”`
https://codex.wordpress.org/Changing_File_Permissions#The_dangers_of_777
http://stackoverflow.com/questions/18352682/correct-file-permissions-for-wordpress
September 7, 2016 at 4:01 pm
Hi Joe,
Do you know if apache will be able to read the file? Dokku is the owner and I do not think apache is in the group.
I did this quite long time ago, so I’m not sure and can’t take a look right now 🙂
September 8, 2016 at 12:05 am
Thanks for the quick reply. I didn’t get dokku running so I can not say. Time for my server experimentation has run out so I just spun up a DigitalOcean server and installed Serverpilot. Dokku sounds interesting and I may explore it more in the future.
I am just starting to wrap my mind around permissions and groups.
I wonder if apache needs to be added to the Dokku group?
March 21, 2017 at 6:22 am
Hi, with a little help from your tutorial and a few others, I’ve made a github project you can checkout to speed up this process as well as a quick outline to get going https://github.com/BadPirate/dokku_wordpress
March 26, 2017 at 12:42 pm
Hi @kevinlohman:disqus,
how do you manage the upgrade?
March 27, 2017 at 8:21 pm
Good question :/ — Depends on how wordpress does it’s DB upgrade.. when that comes around, I’ll probably just download the latest source zip, upgrade the git hub, and then push to dokku. If upgrading the source and then launching will trigger a DB upgrade / migration it should work fine.
March 28, 2017 at 7:35 am
what I did, I’ve cloned wordpress master and created a new branch called production.
Then, when I need to get the updates, I just update master to the latest tag and then merge into the master branch and puch it.
This is my repo: https://github.com/mattions/blog