[Tutorial] Deploying wordpress with Dokku

Few days ago, I tried deploying WordPress using dokku with digitalocean’s VPS, but I run into several issues, the biggest one of them was getting WordPress permalinks to work properly.

Since dokku uses an advanced php buildpack (can be found here), we will try to leverage its settings to get our a WordPress blog deployed. In fact this blog was deployed using the same steps bellow.

So let’s get started.

Clone wordpress locally

We’ll start by cloning WordPress locally:

git clone https://github.com/WordPress/WordPress.git blog

Create an empty compose.lock

The reason we do that is to force the buildpack to detect our wordpress as a composer app. We will see later how to use composer.json to configure both nginx and newrelic and even set permissions for our wp-content folder.

create a composer.lock in the root folder with an empty json object:


Create a composer.json

This is the most important step in this tutorial,  create a composer.json with the following content, in our case this file will be used by the buildpack to setup our environment:

    "scripts": {
        "post-install-cmd": [
            "chmod -R 777 wp-content"
    "extra": {
        "heroku": {
            "newrelic": "true",
            "nginx-includes": ["nginx.conf"]

You can set newrelic to “false”, but if you do keep it you will need to add an environment variable later containing you secret key.

Create nginx.conf file

This file goes into your blog root folder. The configuration bellow is the simplest configuration you can find for wordpress with nginx, it simply works, but you can add additional rules if you want.

location / {
    try_files $uri $uri/ /index.php?$args; 
location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_pass unix:/var/run/php5-fpm.sock;

Create a Procfile (used to start WordPress)

Yes, this file in conjuction with dokku supervisor plugin will start your blog and restart it if it crushes, Cool huh. past this in:

web: bin/run

The last thing we need to do is to prepare our wp-config.php with necessary data to be able to connect to our database.

Keep in mind that we will use mariadb for wordpress, rest assured it is supported by wordpress and works even better than mysql.

Modify wp-config.php

As said above we will use mariadb as our database for the blog via a dokku plugin which can be found here.

The part that needs to be changed is this:

// ** 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'));

One more thing, you’ll need to add this to the bottom too, or wordpress will default to ftp to install your plugins and themes, we force it to use direct method:

define('FS_METHOD', 'direct');

Next we will create a database container, using a dokku plugin, set our persistent volumes to keep our data safe from being deleted, and then point a domain name to the blog.

Create mariadb container (dokku plugin)

cd /var/lib/dokku/plugins
git clone https://github.com/Kloadut/dokku-md-plugin mariadb
dokku plugins-install

Then create a database (the name must match your blog name, otherwise your blog container and database container won’t be linked)

dokku mariadb:create blog

Adding persistent volumes for plugins and themes

To be able to use volumes with dokku, we need to leverage another plugin call docker-options. Everything you do will be done once only, redeploying your application won’t change anything except wordpress’ code base.

cd /var/lib/dokku/plugins
sudo git clone https://github.com/dyson/dokku-docker-options.git docker-options

Setting volumes is as simple as:

dokku docker-options:add blog "-v /opt/blog/themes:/app/wp-content/themes"
dokku docker-options:add blog "-v /opt/blog/plugins:/app/wp-content/plugins"
dokku docker-options:add blog "-v /opt/blog/uploads:/app/wp-content/uploads"

You can omit the /opt/blog completely, if you do so, docker will will create a volume in it’s vfs folder, personally I don’t do that, but it’s ok.

Before we deploy wordpress, you can set a domain name to point to your container instead of dokku’s subdomains.

Setting up a domain name to point to our container

This also can be done with a plugin,

git clone https://github.com/krisrang/dokku-domains.git /var/lib/dokku/plugins/domains

setup your domain name (both www and non www versions)

dokku domains:set blog www.blog.com blog.com

At last, your are ready to deploy, if you previously set newrelic to true in the composer.json, please add this environment variable with you secret key:

dokku config:set NEW_RELIC_LICENSE_KEY=[your key goes here]

Use Supervisor to start and keep your blog running

Again this is doable using another great plugin (it comes also with logs):

# Create the directory to house the log files:
sudo mkdir -p /var/log/dokku
sudo chown dokku:dokku /var/log/dokku

# Install the plugin:
git clone https://github.com/sehrope/dokku-logging-supervisord.git /var/lib/dokku/plugins/logging-supervisord

from now on supervisor will handle the execution of your Procfile, this is great since you are certain that your application will continue running.

Deploying WordPress

Make sure you use a stable version of wordpress, checkout to 3.9-branch

git checkout 3.9-branch

Now push your code to your host:

git remote add dokku dokku@your-server:blog
git push dokku master

Watch dokku do it’s magic.

Oops nothing shows up !!!

Since we mapped wp-content as a volume in the host, it’s content is rewritten when we deploy for the first time.

What you need to do is to go to your dashboard: http://www.blog.com/wp-login.php and install your first theme.

if you run into permission problems ( failure in installing plugins or themes ), either attach to your dokku container, and run this inside:  chmod -R 777 /app/wp-content, or you can browse to you persistent volume, remember that we use /opt/blog/, do a chmod -R 777 /opt/blog Everything should work properly now.

Optional plugins for nginx caching and performance boosting

Since we are using nginx, you can enhance the performance of your blog using a simple plugin called nginx-helper.

Just install it, no configuration needed.

That’s it, I hope this saves someone some time. I plan to setup a repo in github with all this configuration, stay tuned.

And thank you for visiting my blog.


  1. Hello, everytime i make a local commit and push it y get uploads folder deleted and i have to chmod -R 777 /app/wp-content again on every commit. what sholud i do?

    1. Hi There Pedro, what you should do is to create persistent volume for the uploads folder, the same way we did for plugins and themes folders, I just updated the post, see ‘Adding persistent volumes for plugins and themes’ section.

      hope it works.

      1. Pedro, use the dokku plugin I pointed out in this section: ‘Setting up a domain name to point to our container’. it should do exactly what you need.

  2. Cant make permalinks to work with proxy_pass

    upstream domain.com { server; }
    server {
    listen [::]:80;
    listen 80;
    server_name domain.com;
    location / {
    proxy_pass http://domain.com;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Request-Start $msec;

  3. The nginx configuration you mentionned is already generated automatically by dokku, you can find it here /home/dokku/blog/nginx.conf.

    If needed delete /home/dokku/blog and redeploy your wordpress blog, a correct and working nginx configuration will be generated by dokku.

    Again, this configuration will only forward traffic to your container, unless you handle it with the custom configuration used with the buildpack, it will not work.

  4. Excellent tutorial, however, there is one issue regarding omission of information that kind of screwed my over and took a long while to figure out. Right here:

    “Then create a database (the name must match you blog name, otherwise your blog container and database container won’t be linked)”

    This is not clear. Nowhere in the article did you previously mention the importance of the “blog container” name, which is incorrect, because not everyone will use the term “blog.” They may use “store” or “splash” or “community.”

    I would suggest appending some helpful info regarding this configuration higher up in the article, so that people are aware of the *context* of their actions when determining slugs. As of now, we (visitors) just follow the instructions somewhat blindly, and in this circumstance we have no idea what the consequences of our actions are when we don’t use the slug name “blog,” which is a perfectly acceptable diversion.

    Maybe something like… “And now you will decide on your *CONTAINER NAME,* choose a name and remember it, because you will need it again when we create the database. I used ‘blog,’ but you are welcome to use whatever is relevant to your project.”

    Is blog the git name?
    The host name?
    The container name?
    How do I obtain the container name? … I tried “docker ps –no-trunc” but that gives a “name” that is randomized similar to heroku hostnames.

    Because of this mix-up, I have no database connection, and after repeating the mariadb step 3-4 times hoping I get name correct, I have lost patience.

    Shed some light? Clarify terminology? Or maybe I’ve read the article so many times I’m just not seeing it.

    Thanks! 🙂

    1. Hey Sean, first of all thank you for your comment. I really appreciate the time you took to write this.

      As I can see, you are familiar with Docker, but not quite with Dokku (Just saying).

      As for the application name, it’s what you use when you push your app to the server, I am not talking about the container’s name. As far as I am aware of, dokku does not make use of them at all, plugins do, for linking purposes.

      When you first setup your remote repository with git, you do this:
      git remote add dokku dokku@server:APPNAME
      now APPNAME is your application name, use that when you create your mariadb container, I used blog as the APPNAME.

      This APPNAME is also what dokku will use as a subdomain for your application (if you are using virtual hosts): APPNAME.domain.com.

      Anyway, I will try to update the post for further clarification.

      Thanks again.

Leave a Reply