Setup a WordPress Blog in DigitalOcean using Dokku

Setup a WordPress blog in DigitalOcean using Dokku

Now you can easily setup a WordPress Blog in a Digitalocean’s $5 droplet using Dokku ( Let’s do it?

What I am going to show in this article is what I’ve done in my droplet.


Please, install  and/or configure:
Dokku 0.8.0 on 16.04 > $5/month Droplet

Add your SSH keys


Composer (locally)

Do-dokku-wordpress repo (locally)

Highly Recommended

Visual Studio Code: Code editing. Redefined!

Download VS-Code

Step 0

After create your droplet, copy your IP and paste in your browser, so you can add your key (pbcopy < ~/.ssh/

And choose the way that you want your applications to be referenced. By default, the application will be served like this:

If you select the “Use virtualhost naming for apps” check box, your apps will be accessible using a virtualhost instead:

Getting Started

If you already have downloaded the repo to your computer, open the project folder using VS-Code and edit the composer.json file:

 "name": "Playcode",
 "description": "Blog",
 "license": "GPL-2.0",
 "authors": [
 "name": "Juan Suarez",
 "email": ""
 "minimum-stability": "stable",
 "require": {
     "php": ">=5.6.30",
     "ext-mbstring": "*",
     "ext-gd": "*",
     "johnpbloch/wordpress": ">=4.7.3"
 "extra": {
 "wordpress-install-dir": "public/wordpress"

Then let’s create a php.ini file:

upload_max_filesize = 64M;
post_max_size = 64M;
safe_mode = off;

Add some parameters to our nginx.conf:

# Set index
index index.php;

# Global restrictions configuration file.
# Designed to be included in any server {} block.
location = /favicon.ico {
 log_not_found off;
 access_log off;

location = /robots.txt {
 allow all;
 log_not_found off;
 access_log off;

# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
 deny all;

# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:uploads|files)/.*\.php$ {
 deny all;

location / {
 try_files $uri $uri/ /index.php?$args;

# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;

# Directives to send expires headers and turn off 404 error logging.
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
 access_log off; log_not_found off; expires max;

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

Modify our Procfile:

web: vendor/bin/heroku-php-nginx -C nginx.conf -i php.ini --verbose public/

Edit our public/wp-config.php:

 * The base configuration for WordPress
 * The wp-config.php creation script uses this file during the
 * installation. You don't have to use the web site, you can
 * copy this file to "wp-config.php" and fill in the values.
 * This file contains the following configurations:
 * * MySQL settings
 * * Secret keys
 * * Database table prefix
 * @link
 * @package WordPress

// ** MySQL settings - You can get this info from your web host ** //
$url = parse_url(getenv('DATABASE_URL'));

/** The name of the database for WordPress */
define('DB_NAME', str_replace('/','',$url['path']));

/** MySQL database username */
define('DB_USER', $url['user']);

/** MySQL database password */
define('DB_PASSWORD', $url['pass']);

/** MySQL hostname */
define('DB_HOST', $url['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 
 * Use your own salt:
define('AUTH_KEY', 'put your unique phrase here');
define('SECURE_AUTH_KEY', 'put your unique phrase here');
define('LOGGED_IN_KEY', 'put your unique phrase here');
define('NONCE_KEY', 'put your unique phrase here');
define('AUTH_SALT', 'put your unique phrase here');
define('SECURE_AUTH_SALT', 'put your unique phrase here');
define('LOGGED_IN_SALT', 'put your unique phrase here');
define('NONCE_SALT', 'put your unique phrase here');


 * WordPress Database Table prefix.
 * You can have multiple installations in one database if you give each
 * a unique prefix. Only numbers, letters, and underscores please!
$table_prefix = 'wp_';

 * For developers: WordPress debugging mode.
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 * For information on other constants that can be used for debugging,
 * visit the Codex.
 * @link
define('WP_DEBUG', false);

//define('FORCE_SSL_ADMIN', true);
//define('FORCE_SSL_LOGIN', true);

/* That's all, stop editing! Happy blogging. */

/** Absolute path to the WordPress directory. */
if ( !defined('ABSPATH') )
 define('ABSPATH', dirname(__FILE__) . '/wordpress');

if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') 

/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');

/** Defines custom paths */
//$protocol = stripos($_SERVER['SERVER_PROTOCOL'], 'https') === true ? 'https://' : 'http://'; If you will use letsencrypt like me, force https always:
$protocol = 'https://';

define('WP_SITEURL', $protocol . getenv('DOMAIN_NAME') . '/wordpress');
define('WP_HOME', $protocol . getenv('DOMAIN_NAME'));
define('WP_CONTENT_DIR', dirname(__FILE__) . '/wp-content');
define('WP_CONTENT_URL', $protocol . getenv('DOMAIN_NAME') . '/wp-content');
define('UPLOADS', dirname(__FILE__) . '/uploads');

// Don't use or you can't install any plugins
// define('WP_TEMP_DIR', dirname(__FILE__) . '/temp');


Execute composer update and push our repo (delete the .git hidden folder first):

composer update

git init 

git remote add dokku dokku@YOURDOMAIN_OR_IP:YOURAPPNAME

git add . && git commit -m 'init' && git push dokku master

Server Side

In my case I like to use in order to connect and manage my server/droplet (you can easily edit files using the editor of codeanywhere). Go ahead and create a sftp/ssh connection with your server.

As a first step, update/upgrade the server:

apt-get update
apt-get upgrade

Install Dokku MariaDB Plugin:

dokku plugin:install mariadb

Create a DB Container:

dokku mariadb:create DBNAME

Link the new DB Container with your App:

dokku mariadb:link DBNAME APPNAME

Create WordPress folders and mount Dokku Storage:

mkdir /var/lib/dokku/data/storage/uploads
mkdir /var/lib/dokku/data/storage/plugins
mkdir /var/lib/dokku/data/storage/themes

chmod -R 755 /var/lib/dokku/data/storage/uploads
chmod -R 755 /var/lib/dokku/data/storage/plugins
chmod -R 755 /var/lib/dokku/data/storage/themes

dokku storage:mount APPNAME /var/lib/dokku/data/storage/APPNAME/plugins/:/app/wordpress/wp-content/plugins/
dokku storage:mount APPNAME /var/lib/dokku/data/storage/APPNAME/themes/:/app/wordpress/wp-content/themes/
dokku storage:mount APPNAME /var/lib/dokku/data/storage/APPNAME/uploads/:/app/wordpress/wp-content/uploads/

Install Letsencrypt Plugin:

dokku plugin:install

Set Letsencrypt Email:

dokku config:set --no-restart APPNAME

Add all possible domain names (in my case I have a primary one and the app one):

dokku domains:add APPNAME

Set the DOMAIN_NAME env var:

dokku config:set APPNAME

Execute Letsencrypt command:

dokku letsencrypt APPNAME

Add the cron-job to let the plugin renew the ssl certificate for you:

dokku letsencrypt:cron-job --add

And voilà you can navigate to your domain and continue the Wordpress installation! 🙂




Do-dokku-wordpress repo

Keep up with my guides and how-tos like this by liking my Facebook Page. If you have any questions about Dokku, please join the discussion below!