This solution describes how to deploy a custom WordPress installation using Dokku. Note that the WordPress application container is using Nginx with PHP FPM.

Creating an Application

Connect to the server and create your app(s):

dokku apps:create my-app-name

Preparing Your Application for Deployment

Do the following steps on your local development machine:

1. Add a file named Procfile to the root of your application and specify the startup command.

web: vendor/bin/heroku-php-nginx -C nginx_app.conf --verbose

2. Add a file named nginx_app.conf to the root of your application repo, with the following contents. Some of the settings are optional.

# Permalinks
location / {
  index index.php index.html;
  try_files $uri $uri/ /index.php?$args;
# Adds 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;
# Max upload size
client_max_body_size 100M;
# Optimizations
fastcgi_buffers 8 32k;
fastcgi_buffer_size 64k;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# Compression
gzip on;
gzip_min_length 1000;
gzip_comp_level 2;
gzip_buffers 4 32k;
gzip_types text/plain application/javascript text/xml text/css image/svg+xml;
gzip_vary on;
# Set time to expire for headers on assets
location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ {
  expires 1y;
# Sitemap url (if using the 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;

3. Use PHP Composer to define PHP extensions that are dependencies for your application.

Be sure you have Composer installed, and add a composer.json to the root of your source control repository and not within a subdirectory.

If your app does not have any library dependencies and your application is compatible with the latest stable version of PHP, add a composer.json file containing empty JSON curly braces - {}. This is necessary in order for the deployed application to be recognized as a PHP application.

To specify a different PHP version:

  "require": {
    "php": "^5.6.0"

Supported PHP Versions

  • 5.5
  • 5.6
  • 7.0

Don't forget to freeze the composer file and add the composer.json and composer.lock files to source control:

composer update

Included Extensions

The following built-in extensions are enabled automatically on Healthcare Blocks and do not need to be specified in composer.json. In addition, any extensions that PHP enables by default, such as DOM, JSON, PCRE or PDO, are also included in the environment.

  • Bzip2
  • cURL
  • FPM
  • mcrypt (5.5 and 5.6 only)
  • MySQL (PDO) (uses mysqlnd)
  • MySQLi (uses mysqlnd)
  • OPcache
  • OpenSSL
  • PostgreSQL
  • PostgreSQL (PDO)
  • Readline
  • Sockets
  • Zip
  • Zlib

Additional extensions are built as "shared" and need to be explicitly referenced in your composer.json. Since Heroku maintains the PHP buildpack used by Dokku, refer to their page for additional details on this topic.

Example composer.json

  "require": {
    "php": "~5.6.0",
    "ext-mbstring" : "*",
    "ext-gd": "*",
    "ext-curl": "0.0.0.*",
    "ext-exif": "0.0.0.*"
  "scripts": {
    "post-install-cmd": [
      "chmod -R 777 wp-content"

4. On the server, define any environment variables, especially addresses for external databases / services, API keys, and any other production-specific setting you don't want to store in your source code.

5. In your source code, copy wp-config.php.sample to wp-config.php, using the environment variables you set above. Example:

// ** 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'));
/** 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', '');
 * Authentication Unique Keys and Salts.
 * Change these to different unique phrases!
 * You can generate these using the {@link 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('LOGGED_IN_SALT',   getenv('LOGGED_IN_SALT'));
define('NONCE_SALT',       getenv('NONCE_SALT'));

6. In most cases, your database will be running on a separate machine via our database-as-a-service plan. You should have received connection information and credentials during the on-boarding process.

Deploy your App

See Deploying via Git topic

Frequently Asked Questions

How do I persist uploaded files, themes, plugins, etc.?

Dokku uses a Docker container to run your WordPress application. By default, containers use an ephemeral filesystem, which is not guaranteed to persist any files that are modified or added after your application is deployed and running. What you'll need to do on the server is define a storage mount. This should be done when deploying your application for the first time.

  1. First, create a directory where your files will be stored on the server. We recommend using any path under the encrypted data volume (/data):
    mkdir -p /data/wp-content/plugins /data/wp-content/themes /data/wp-content/uploads
    chown -R 32767:32767 /data/wp-content
  2. Next, configure your app to leverage the above paths:.
    dokku storage:mount my-app-name /data/wp-content/plugins:/app/wp-content/plugins
    dokku storage:mount my-app-name /data/wp-content/themes:/app/wp-content/themes
    dokku storage:mount my-app-name /data/wp-content/uploads:/app/wp-content/uploads
  3. Lastly, re-deploy your application and confirm that dynamic content is being saved to the proper location. If everything is working correctly, you should see newly uploaded files appear under /data/wp-content on the server.

Important note: if your project code repository tracks changes to wp-content/plugins or wp-content/themes, these directories will get overwritten by the storage mount settings above. So you'll need to either remove them from your code and upload them via the WordPress admin panel, or not create a storage mount for the directory that you'd like to keep under source control.

Additional Documentation

More help topics can be found in the Dokku Getting Started guide.