Here is the easiest way to install Wordpress with multi-site functionality on a Debian/Ubuntu server that you own.

You may be surprised that, for me, the most direct way of installing Wordpress is not:

sudo apt install wordpress

This might be considered the most direct way to install Wordpress but it is not the easiest way. It is certainly not the easiest way to get multi-site functionality working in a supportable manner - especially if you own the server your working on.

I found that using apt to install Wordpress required me to comply with the 'Debian way' of configuring Wordpress with multi-site support. I understand that there are different ideals on how software should be organized on a server. I understand that Debian has its own philosophy. The trouble is: I'm not a philosopher. I kind of needed this platform I was building to be immediately comprehensible and just work. In this case I suppose I am more of a pragmatist.

So, enough philosophy. Here are the steps to getting Wordpress multi-site working on Debian/Ubuntu in a jiffy. Let's do this!

OVERVIEW

Firstly, let's get an overview of what we're trying to build.

We're trying to host multiple Wordpress sites on one server. We're going to do it by installing a separate copy of Wordpress for each site. Wordpress is such a small, fairly uncomplicated piece of software that having multiple Wordpress installations running on the same server is simpler than trying to make a single Wordpress installation support multiple sites. This method also gives me the freedom to have different plugins and themes aviable for each site. Each site gets its own users and MySQL tables as well.

Here are the salient details that we need to support for our fictitious setup:

Site Domain Name Site User DB User Password
lab.yourdomain.com wp_lab wp_lab super-secret-password
test.yourdomain.com wp_test wp_test another-super-secret-password

We're going to put our Wordpress installations right in /var/www/html/. Each Wordpress site will be hosted on its own sub-directory like this:

/var/www/html/[site]/public_html

Finally, we'll keep a copy of the Wordpress source files in case we ever need to wipe and re-install.

So, let's begin:

Update Your Server

As always, we need to make sure we've got the latest package database and everything is up to date:

sudo apt update
sudo apt upgrade

The above may take some time.

INSTALL MYSQL

apt is the right way to install the big stuff like your SQL and web servers and PHP. Let's install the SQL server first:

sudo apt install mysql-server mysql-client

MySQL is in-place. Time to configure it.

SETUP MYSQL DATABASES

Log into your new MySQL installation

sudo mysql

Create the Wordpress databases and users for each of your hosted sites:

CREATE DATABASE wp_lab;
CREATE USER 'wp_lab' IDENTIFIED BY 'super-secret-password';
GRANT ALL PRIVILEGES ON wp_lab.* TO 'wp_lab';

You want to repeat the above for every new site that you'll be hosting on your server.

INSTALL APACHE2 AND PHP

Next, we have to install the web server. Again, apt is the appropriate tool to use for that.

sudo apt install apache2
sudo apt install php php-mysql php-curl php-gd php-mbstring php-xml php-xmlrpc php-soap php-intl php-zip

We've also gone ahead and installed PHP and a few libraries that any self-respecting Wordpress site couldn't do without.

DOWNLOAD AND INSTALL WORDPRESS

Now, let's get the Wordpress source. Wordpress is small enough of a body of software that there are few disadvantages to simply downloading the source and sitting it where you want it. It is, after all, just a glorified PHP script. So, that's what we're going to do.

We're going to create a directory to hold the source in our home directory (~/).

mkdir -p ~/wordpress_src/
cd ~/wordpess_src/
sudo wget http://wordpress.org/latest.tar.gz
sudo tar -xvzf latest.tar.gz

Rename that tarball to something that will help you keep track of the sources as you periodically update your installations:

mv latest.tar.gz wordpress-[date].tar.gz

Place Wordpress in Each of Your Target Sites' Document Roots

sudo mkdir -p /var/www/html/{site}/public_html
sudo cp -r ~/wordpress_src/wordpress/* /var/www/html/{site}/public_html/
sudo chown -R www-data:www-data /var/www

We created a folder for each site we're building and then we copied the Wordpress source into the directory.

This means you should have a setup something like this:

/var/www/html
├── lab.yourdomain.com
│   └── public_html
│       ├── index.php
│       ├── license.txt
│       ├── readme.html
│       ├── wp-activate.php
│       ├── wp-admin
│       ├── wp-blog-header.php
│       ├── wp-comments-post.php
│       ├── wp-config-sample.php
│       ├── wp-config.php
│       ├── wp-content
│       ├── wp-cron.php
│       ├── wp-includes
│       ├── wp-links-opml.php
│       ├── wp-load.php
│       ├── wp-login.php
│       ├── wp-mail.php
│       ├── wp-settings.php
│       ├── wp-signup.php
│       ├── wp-trackback.php
│       └── xmlrpc.php
├── index.html
└── test.yourdomain.com
    └── public_html
        ├── index.php
        ├── license.txt
        ├── readme.html
        ├── wp-activate.php
        ├── wp-admin
        ├── wp-blog-header.php
        ├── wp-comments-post.php
        ├── wp-config-sample.php
        ├── wp-config.php
        ├── wp-content
        ├── wp-cron.php
        ├── wp-includes
        ├── wp-links-opml.php
        ├── wp-load.php
        ├── wp-login.php
        ├── wp-mail.php
        ├── wp-settings.php
        ├── wp-signup.php
        ├── wp-trackback.php
        └── xmlrpc.php

As you can see, each site has their own wp-admin, wp-content and wp-includes directories. Each site is their own living, breathing Wordpress site. This makes it easy to administer each site as their own self-contained thing.

CONFIGURE APACHE

Enable Apache Rewrite Module

For Wordpress' Permalinks to work properly we need to enable Apache's Rewrite module.

sudo a2enmod rewrite

We won't restart Apache yet. Let's build our virtual host configuration files next.

Create Virtual Host Configuration Files for Each Host

We need to build a Virtual Host Apache configuration for each Wordpress site we host.

Let's take the example of our first site: lab.yourdomain.com. We need to build an Apache configuration file for this site.

Create a config file at /etc/apache2/sites-available/lab.yourdomain.com.conf and remember to change the server and folder references:

sudo vim /etc/apache2/sites-available/lab.yourdomain.com.conf

Add the below to the empty file:

<VirtualHost *:80>
    # The primary domain for this host
    ServerName lab.yourdomain.com
    # Optionally have other subdomains also managed by this Virtual Host
    DocumentRoot /var/www/html/lab.yourdomain.com/public_html
    <Directory /var/www/html/lab.yourdomain.com/public_html>
        Require all granted
        # Allow local .htaccess to override Apache configuration settings
        AllowOverride all
    </Directory>
    # Enable RewriteEngine
    RewriteEngine on
    RewriteOptions inherit

    # Block .svn, .git
    RewriteRule \.(svn|git)(/)?$ - [F]

    # Catchall redirect to www.example1.com

    # Recommended: XSS protection
    <IfModule mod_headers.c>
        Header set X-XSS-Protection "1; mode=block"
        Header always append X-Frame-Options SAMEORIGIN
    </IfModule>
</VirtualHost>

Save the file (:wq).

Enable the site:

Now, we need to actually enable the virtual site we've just configured so that Apache will serve it.

sudo a2ensite lab.yourdomain.com.conf

All the Apache plumbing has been done. We can restart apache now.

Restart Apache

sudo systemctl restart apache2

We've basically done it. But we really don't want our sites to be served over insecure HTTP. We need to enable TLS so we can run our sites over HTTPS.

SETUP CERTBOT

We are going to install Certbot, the ACME client that uses Let's Encrypt to acquire a real TLS certificate, so we can serve our site over HTTPS.

We install Certbot:

sudo apt install certbot python-certbot-apache

Then, we run the certbot script. Certbot is smart enough to do all the rest, including building an Apache virtual host file for SSL (port 443) and edit the HTTP host file that we created above to redirect visitors from port 80 to port 443. It's brilliant!

sudo certbot --apache

Follow the prompts. Certbot will figure out what sites are available on your Apache server that need an SSL certificate and allow you to select it. In this case, select lab.yourdomain.com.

Also, when Certbot asks you if it should enable https rewrite go ahead and agree to it.

Once this has been done and you've restarted Apache, you can point your browser to http://lab.yourdomain.com and you'll be automatically redirected to the secure, TLS version of your site.

We've basically done it. Now, for a little optional housekeeping:

SETUP DIRECT WORDPRESS UPDATES

Edit /var/www/html/[site]/public_html/wp-config.php

Add these two lines to the file just above where it says: ** That's all, stop editing! Happy publishing. **

/** Bypass FTP */
define('FS_METHOD', 'direct');

That update will allow you to update your site without having to set up an FTP server.

Save the file and restart Apache one more time

sudo systemctl restart apache2

And that's it. You may now point your browser to: lab.yourdomain.com and you'll be greeted with the Wordpress installation screens. The rest is just standard Wordpress administration which is out of the scope of this article.

Conclusion

We've built our own Wordpress multi-site setup that just works.

To add a new site simply follow these steps:

  1. Create the SQL database for the new Wordpress site. Create user and grant permissions.
  2. Create a new document root for your new site at: /var/www/html/[new_site]/public_html
  3. Copy your Wordpress source into the above folder and set ownership to www-data
  4. Create a new Apache virtual host file at /etc/apache2/sites-available/[new_site].conf
  5. Run Certbot to get the secure HTTPS version of your site working
  6. Modify your Wordpress config so updates work smoothly without FTP

I like this setup for all sorts of reasons. One reason that I hadn't mentioned above was: any Wordpress guy can walk up to my server and immediately know where everything is. I like that. If I set up Wordpress the 'Debian way' it would take a few minutes just to grok the layout of the server. You would have to read the config files just to understand how the virtual host is set up. Who's got time for that?