How to Setup Multiple WordPress Sites with LEMP on WebDock

How to Setup Multiple WordPress Sites with LEMP on WebDock

WordPress is on of the most used CMS (content management system) that allows user to create blogs, e-commerce sites, portfolio, news site, headless servers and many more. WordPress needs a web server (Apache, Nginx, LiteSpeed), database (MariaDB, MySQL) and PHP.

In this tutorial we are going to deploy multiple WordPress sites on WebDock. WebDock is a fast and cheap VPS provider that fits everyone’s need and provides semi managed and ummanged VPS servers. WebDock provides their own control panel where you can manage your VPS servers like, installing LEMP stack, WordPress, phpMyAdmin, MonogDB, CertBot, FTP etc. Hence I described it as semi managed. But the problem is their control panel does not support multiple WordPress installations and they suggest to have single site per server. This is the reason this tutorial about installing multiple WordPress with LEMP in a single VPS server exists.

Create a Server

Create a new server and select Clean OS instead of The Perfect Server. Since WebDock does not support multiple sites in a single server we should manage our server ourselves to avoid accidental changes from WebDock control panel. And this is they way I recommend if you want to have multiple sites or web apps in your VPS. A web server can run at 512 MB RAM too but I recommend to have at least 2 GB of RAM for multiple WordPress sites.

choose clean os

WebDock only supports Ubuntu for now hence we will get Ubuntu Focal 20.4 as our server. Give a name and slug and spin up your server.

server created

Congratulations you have your server running and ready to deploy our site.

Setup SSH

At bottom of the dashboard click on add shell user then provide username and password and press ADD USER. You don’t need to change other options and you should not if you don’t know what are you doing.

add user

After adding user to your server you need to login to the server in order to make changes and to do so you need to add SSH key first. SSH is generated in you local machine and a copy of public key is uploaded to server so that server knows who is trying to connect.

Generate SSH Key

To create SSH key, in your local machine in terminal use ssh-keygen.

~$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/user/.ssh/id_rsa):
Code language: Shell Session (shell)

If you already have SSH key then a overwrite message will be shown and you don’t need to create a new key. Then it will ask for passphrase. Adding passphrase is recommended.

~$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/user/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/user/.ssh/id_rsa Your public key has been saved in /home/user/.ssh/id_rsa.pub The key fingerprint is: SHA256:6H5M8HkmTD1BPkPCA67a8CdWR7KKx8b4kN6fTMndQhQ user@myPc The key's randomart image is: +---[RSA 3072]----+ | .oE.o | | . o=. | | o oo+. | | ..<em>. oo | | . . +=S. . | | @ = =</em>.o | | * @ *oo+. | | . B * .o. | | . o.=. | +----[SHA256]-----+
Code language: Shell Session (shell)

This is what you see after completing generating SSH key.

Copy Public Key

As our key is saved in ~/.ssh/id_rsa.pub we can get public key using cat.

~$ cat ~/.ssh/id_rsa.pub
Code language: Shell Session (shell)

It will give result like this;

~$ cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC7DFwx4hgyBKvhqd5ss56YIhU2PMgO1NEQ4Kln8dnHit6eLF4HKzCPfsIhkeWUGu4VdqS4Zg+U04Xvx/TG1z3N9klnvV7pHeZaxGciUT8+Ii6YUWosBUX/Ki8ZfC+QgmzkGmQwIefXzxOMijqa1j7CJH8JFigQYCw9B6LIwNhageQjPyPy68ido/XDuqI1xtbr/aJcuYxE2IHVzsNzMAoJlNEVjrhwTp0y78bWW2RodftPPNT670MwrFfiP+iqck1zQ/n+VwB9wW67cFlE/HX6Invc13i/psjn6UJcpKEDW3tHvvpX6Y/Nik79dSSTAX9lAAuOKwe3VJ6YQBSPpE0JInVE0veO+xEJkTnXz+kUWgQQT+PxfHSIE63v0mIAiPTW3WnFkZkjW23BZX+2Tty6xPyHuXJGtaiyyaZ+F4/A51jZ3yXR2G7pLOy9PdeDl1j3Doy466UX86p0zpPEG5KpRuis/JMve5vvPQBwppoBHCQTdkb2ApvA2XL3vtxoMyk= user@myPc
Code language: Shell Session (shell)

Copy all the output content and save to WebDock.

Then assign key to the user.

Login to Server using SSH

We can get server IP address from the servers list.

server ip

To login into server using SSH;

~$ ssh admin@45.148.30.37
Code language: Shell Session (shell)

Install LEMP Stack

L: We already installed Linux.

Install Nginx (pronounce as Engine-X)

admin@webdocktutor:~$ sudo apt update admin@webdocktutor:~$ sudo apt install nginx
Code language: Shell Session (shell)

Browse to your IP http://your_ip_address, for me it is http://45.148.30.37. We can see nginx Welcome page. Which means nginx is installed correctly.

welcome to nginx

Install MariaDB

MariaDB or MySQL can be installed for database used by WordPress.

admin@webdocktutor:~$ sudo apt install mariadb-server
Code language: Shell Session (shell)

After installing we need to setup MariaDB for the first time.

admin@webdocktutor:~$ sudo mysql_secure_installation
Code language: Shell Session (shell)

Create new root password and select yes for other options.

Create new user and database for WordPress site. Login into mariadb.

admin@webdocktutor:~$ sudo mariadb
Code language: Shell Session (shell)

Now create wordpress1 user and wordpress2 user for 2 WordPress installation. If you don’t want to install 2 WordPress sites you don’t need to create wordpress2 user. You can have your own names and don’t need to have exact wordpress name. Don’t forget ; after sql command. If you forgot ; and have pressed enter, MySQL shell will go to new line. You can enter forgotten ; and hit enter again to continue.

MariaDB [(none)]> CREATE DATABASE wordpress1; MariaDB [(none)]> CREATE DATABASE wordpress1;
Code language: Shell Session (shell)

To view newly created database you can use SHOW DATABASES command.

MariaDB [(none)]> SHOW DATABASES;
Code language: Shell Session (shell)

Create new users for wordpress1 and wordpress2 databases.

MariaDB [(none)]> GRANT ALL ON wordpress1.* TO 'wordpress1user'@'localhost' IDENTIFIED BY 'password1' WITH GRANT OPTION;
Code language: Shell Session (shell)
MariaDB [(none)]> GRANT ALL ON wordpress2.* TO 'wordpress2user'@'localhost' IDENTIFIED BY 'password2' WITH GRANT OPTION;
Code language: Shell Session (shell)

We created users wordpress1user and wordpress2user and gave them full privileges to their respective databases wordpress1 and wordpress2. You can always have users and database as your own choice. For example, you can give wordpress1user access to both database without need to create wordpress2user. But for security we created users for each databases.

Keep these root password, usernames and passwords at safe place. We need it later and also we may need in future.

Flush the privileges to ensure that they are available in the current session.

MariaDB [(none)]> FLUSH PRIVILEGES;
Code language: Shell Session (shell)
MariaDB [(none)]> exit;
Code language: Shell Session (shell)

Login again to MariaDB and see databases if they are available or not. They should appear.

admin@webdocktutor:~$ sudo mariadb
Code language: Shell Session (shell)
MariaDB [(none)]> SHOW DATABASES;
Code language: Shell Session (shell)
MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | wordpress1 | | wordpress2 | +--------------------+ 5 rows in set (0.001 sec)
Code language: Shell Session (shell)

It is not necessary to write sql command in all capital letters. To exit;

MariaDB [(none)]> exit;
Code language: Shell Session (shell)

Install PHP

Nginx uses php-fpm to process PHP. Install php-fpm and php-mysql:

admin@webdocktutor:~$ sudo apt install php-fpm php-mysql
Code language: Shell Session (shell)

So LEMP stack is installed. Now we need to setup nginx to run php. By default it is does not run php.

Configure NGINX to use PHP-FPM

In nginx config file there are server blocks that defines web servers. These server blocks need domain name to work. WebDock gives a subdomain for all servers and in my case it is webdocktutor.vps.webdock.io. You can find yours in sever overview page named as alias.

You can use this domain name to test your nginx configuration.

All web files are saved inside /var/www/ and here is html folder inside it which we already seen by browsing our IP address http://ip-address.

In this tutorial I am assuming that we have domain names, mycoolsite.com and mycoolblog.com. So all configuration from now will be based on these 2 domain names.

For our 2 WordPress sites, create 2 folders with the same name as our domain names, which is, mycoolsite.com and mycoolblog.com. So that our new directories are /var/www/mycoolsite.com/and /var/www/mycoolblog.com/. Inside those directories we will place WordPress files and setup nginx config to server them.

Configure NGINX config file for multiple sites

Nginx saves all config in /etc/nginx/nginx.conf but as we are in Ubuntu server config files are available in separate folder to match Apache config directories. Generally all available sites/servers config files are kept inside /etc/nginx/sites-available/ and to enable those sites symbolic link to available sites must be added to /etc/nginx/sites-enabled/.

If you take a look at /etc/nginx/sites-available/ you will find a file named default which is responsible to serve files under /var/www/html/. So what we need to do to setup our WordPress sites? Well, we will remove the symbolic link of default from /etc/nginx/sites-enabled/ and create our own config file then create a link.

To remove default site use:

admin@webdocktutor:~$ sudo rm /etc/nginx/sites-enabled/default
Code language: Shell Session (shell)

This will remove symbolic link but not the actual config file under /etc/nginx/sites-available/ and that is how is should be done.

Now create a new config file to make WordPress (PHP) working:

admin@webdocktutor:~$ sudo nano /etc/nginx/snippets/wordpress.conf
Code language: Shell Session (shell)

And put this inside wordpress.conf:

# /etc/nginx/snippets/wordpress.conf # this should be used inside server block index index.php; location / { # try to serve static file if not found then directory then php # include the "?$args" part so non-default permalinks doesn't break when usi> try_files $uri $uri/ /index.php?$args; } # php-fpm location ~ \.php$ { include fastcgi_params; # you may need to change this fastcgi_pass to match your php version fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; fastcgi_intercept_errors on; # The following parameter can be also included in fastcgi_params file fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } # favicon.ico location = /favicon.ico { log_not_found off; access_log off; } # robots.txt related location = /robots.txt { # wordpress dynamically generates robots.txt try_files $uri $uri/ /index.php?$args; allow all; log_not_found off; access_log off; } # sitemap related location ~* \.(xml|xsl)$ { # wordpress dynamically generates sitemap.xml try_files $uri $uri/ /index.php?$args; log_not_found off; access_log off; } # static assets caching location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { expires max; log_not_found off; } # RESTRICTIONS # 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; }
Code language: Nginx (nginx)

You may need to have a look in location ~ \.php$ {} block since it may be different in your setup. Because it is for php7.4.

Now we need to create virtual host and use above config. To create virtual hosts for our 2 different domain names create config files inside sites-available folder.

admin@webdocktutor:~$ sudo nano /etc/nginx/sites-available/mycoolsite.com
Code language: Shell Session (shell)

Then pust this config:

server { root /var/www/mycoolsite.com; server_name mycoolsite.com; listen 80; listen [::]:80; # WordPress core include snippets/wordpress/wordpress.conf; }
Code language: Nginx (nginx)

Similarly for another domain name:

admin@webdocktutor:~$ sudo nano /etc/nginx/sites-available/mycoolblog.com
Code language: Shell Session (shell)
server { root /var/www/mycoolblog.com; server_name mycoolblog.com; listen 80; listen [::]:80; # WordPress core include snippets/wordpress/wordpress.conf; }
Code language: Nginx (nginx)

So now when you browse these domains it will try to server the content from directory specified as root. If you browse you domains now you will get 404 not found error since we haven’t placed anything in those directories.

Now it’s time to install WordPress. Navigate to /tmp directory and download WordPress.

cd /tmp wget https://wordpress.org/latest.tar.gz
Code language: Shell Session (shell)

Extract the files:

tar -zxvf latest.tar.gz
Code language: Shell Session (shell)

Change files permission to www-data user/group so that we won’t get any permission error when using WordPresss.

sudo chown -R www-data:www-data wordpress
Code language: Shell Session (shell)

Now opy files to /var/www/mycoolsite.com and /var/www/mycoolblog.com

sudo cp -a wordpress/. /var/www/mycoolsite.com/ sudo cp -a wordpress/. /var/www/mycoolblog.com/
Code language: Shell Session (shell)

Now create a symlink from sites-available to sites-enabled.

sudo ln -s /etc/nginx/sites-available/mycoolblog.com /etc/nginx/sites-enabled/ sudo ln -s /etc/nginx/sites-available/mycoolsite.com /etc/nginx/sites-enabled/
Code language: Shell Session (shell)

Check nginx configuration:

sudo nginx -t
Code language: Shell Session (shell)

If everything is ok reload nginx:

sudo nginx -s reload
Code language: Shell Session (shell)

Now visit those domains/urls, mycoolblog.com and mycoolsite.com you will find WordPress installation screen. Provide necessary info, database name, username, password we have created previously.

I hope you find this aricle helpful.

Leave a Reply