A quick and clear step-by-step guide on setting up a WordPress website on a LEMP stack on Ubuntu. Some of the steps are specific to the DigitalOcean environment, but most of this should be applicable to other hosting providers as well.
Prerequisites:
- Domain name & access to DNS settings.
- Installed and configured LEMP (Linux, Nginx, MySQL, and PHP) stack on Ubuntu.
- ssh access to your server.
- Some familiarity with the command line.
* Optional steps or steps that might differ depending on setup.
Step 1: Domain setup
In this step, we will be setting up your new website domain name to point to the right place (your DigitalOcean account).
- Log in to your domain name registrar.
- Point your domain to DigtalOcean nameservers: ns1.digitalocean.com, ns2.digitalocean.com, ns3.digitalocean.com.
- Log in to your DigitalOcean account and add your domain using GUI.
- Add a CNAME record from www to the root domain in the DNS settings for this domain.
Step 2: Server setup and configuration
This is the most complex step. You will be creating/updating server configuration files, generating certificates, and doing other setup so that your web server can route and execute the requests properly.
- Open the terminal and connect to the server via ssh.
You can use this command: ssh YOUR-USER@SERVER-IP -p SSH-PORT
or just do ssh
YOUR-USER@SERVER-IP if you are using a standard 22 ssh port. Enter your password *(if you are using password-based authentication) or a pin *(if you are using a key that is protected by pin) if/when prompted.
- *You may also want to update Ubuntu. You can do it by running
apt upgrade
. - Go to
/etc/nginx/sites-available/
directory and copy/create a server config file for the new website (I’m doing it by copying and modifying the file from one of the existing websites hosted here by doingcp existing-website.com newwebsite.com
). The contents of the file would look similar to this:
server {
listen 80;
server_name newwebsite.com www.newwebsite.com;
# redirect to https
return 301 https://newwebsite.com$request_uri;
}
server {
listen [::]:443 ssl http2;
listen 443 ssl http2;
server_name www.newwebsite.com;
# redirect www to non-www
return 301 $scheme://newwebsite.com$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name newwebsite.com;
root /var/www/newwebsite.com/public_html;
include global/restrictions.conf;
location / {
index index.html;
try_files $uri $uri/ /index.html;
}
error_log /var/www/newwebsite.com/logs/error.log;
}
- Open the file for editing
vi newwebsite.com
and set the server name, redirect from http to https, redirect from www to non-www, etc. similar to what pictured above. Exit vi and save changesesc + :wq +enter
. - *This file restrictions.conf is optional. It has some useful instructions for NginX specific to WordPress website. Here’s what I have in there:
# Global restrictions configuration file.
# Designed to be included in any server {} block.
location = /favicon.ico {
log_not_found off;
access_log off;
}
# robots.txt fallback to index.php
location = /robots.txt {
# Some WordPress plugin gererate robots.txt file
allow all;
try_files $uri $uri/ /index.php?$args @robots;
access_log off;
log_not_found off;
}
# additional fallback if robots.txt doesn't exist
location @robots {
return 200 "User-agent: *\nDisallow: /wp-admin/\nAllow: /wp-admin/admin-ajax.php\n";
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac) excepted .well-known directory.
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\.(?!well-known\/) {
deny all;
}
# Deny access to any files with a .php extension in the uploads directory for the single site
location /wp-content/uploads {
location ~ \.php$ {
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 ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
access_log off;
log_not_found off;
}
- Go to your web root (should be
/var/www
if you have multiple sites) and createmkdir newwebsite.com
. - *(Optional step for easy testing). Create a temp file to test if it’s being accessed and read properly before installing WordPress into this directory. I’m making an info file
vi info.php
and adding:
<?php
echo phpinfo();
?>
- Exit vi and save changes
esc + :wq +enter
. - *(If you’re using this type of setup. In some cases, you might be using only sites-enabled). Create a symbolic link from sites-enabled to sites-available for the new domain. Go to sites-enabled
cd /etc/nginx/sites-enabled/
then runcp -s ../sites-available/newwebsite.com newwebsite.com
. - Run test for errors:
nginx -t
and correct the errors if there are any (chances are that you missed something in the config file in sites-available directory). - When all-clear restart Nginx
service nginx reload
. - At this point, your website will not have an SSL certificate but should be accessible in a web browser.
- Obtain SSL certificates using certbot:
certbot --nginx -d newwebsite.com -d www.newwebsite.com
. You can learn more about certbot and key renewal process here. If completed successfully, it will also insert paths to certificates in the config file we created above. The end result will look similar to this (make sure certificates are added to both www and non-www sections):
server {
listen 80;
server_name newwebsite.com www.newwebsite.com;
# redirect to https
return 301 https://newwebsite.com$request_uri;
}
server {
listen [::]:443 ssl http2;
listen 443 ssl http2;
server_name www.newwebsite.com;
# redirect www to non-www
return 301 $scheme://newwebsite.com$request_uri;
ssl_certificate /etc/letsencrypt/live/newwebsite.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/newwebsite.com/privkey.pem; # managed by Certbot
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name newwebsite.com;
root /var/www/newwebsite.com/public_html;
include global/restrictions.conf;
location / {
index index.html;
try_files $uri $uri/ /index.html;
}
error_log /var/www/newwebsite.com/logs/error.log;
ssl_certificate /etc/letsencrypt/live/newwebsite.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/newwebsite.com/privkey.pem; # managed by Certbot
}
- *(Optional step for easy testing). Check if your test file gets read and executed properly by opening https://newwebsite.com/info.php in the browser (don’t forget to test www and non-www and http/https variations + different combinations).
Step 3: Database creation
This step should be relatively easy and standard. We will be creating the database that will be used by your new WordPress install.
- Log in to MySQL using the root account. You can do it in the terminal
mysql -u root -p
or using PhpMyAdmin *(if you already have it installed and configured). - Create a database
CREATE DATABASE newwebsite_db DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
for the new website following your naming conventions & note the database name (you’ll need it later). - Create a new user
CREATE USER 'newwebsite_user'@'localhost' IDENTIFIED BY 'password';
and assign it to this new databaseGRANT ALL ON newwebsite_db.* TO 'newwebsite_user'@'localhost';
(note username and password – you’ll need them later).
Step 4: Installing and configuring WordPress
Almost done. Just need to get all the WordPress files, create a WordPress config file and finish the install process using web interface.
- Go to the temp folder in the root directory
cd /tmp
and download the latest WordPress version therecurl -LO https://wordpress.org/latest.tar.gz
. - Extract the files
tar xzvf latest.tar.gz
. - Create a copy of the default config file
cp /tmp/wordpress/wp-config-sample.php /tmp/wordpress/wp-config.php
. - Copy the contents of the folder from the temp folder to your new website directory
cp -a /tmp/wordpress/. /var/www/newwebsite.com
. - Set correct ownership on WordPress files and directories
chown -R www-data:www-data /var/www
. This will allow Nginx to read and write WordPress files./newwebsite.com
- Generate secret keys for the WordPress config. Run:
curl -s https://api.wordpress.org/secret-key/1.1/salt/
. - Copy the keys and insert them into the wp-config.php file by running
vi wp-config.php
and replacing the placeholder which looks like this:
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');
- Copy and insert the database name and user credentials (from the step above) into this wp-config.php file replacing the placeholder:
define( 'DB_NAME', 'wordpress' );
/** MySQL database username */
define( 'DB_USER', 'wordpressuser' );
/** MySQL database password */
define( 'DB_PASSWORD', 'password' );
- Exit vi and save changes
esc + :wq +enter
to wp-config.php. - Complete the install process using the web interface by going to https://newwebsite.com and following the directions (you will be prompted to answer questions about the language, general website info, admin user credentials, etc.).
DONE! Congrats on getting your WordPress website up and running all by yourself!
USEFUL LINKS:
Other articles about CMCs and WordPress