Setup WordPress on VPS (PHP, Nginx)

This tutorial shows how to install WordPress on Linux VPS example with Digital Ocean provider

VPS

  • First, you buy a new VPS on https://www.digitalocean.com. Select smallest configuration $5/m is fine
  • Remember with Digital Ocean: create a new droplet with login by username + password to void Proftp login 530 error

Install

Add user account

ssh root@SERVER_IP_ADDRESS
=> Change root password
adduser nhancv
adduser nhancv sudo
usermod -aG sudo nhancv
su - nhancv
exit
ssh nhancv@SERVER_IP_ADDRESS
  • [Optional] For register SSL to git version control ex: Bitbucket, Github if you store source on there
mkdir ~/.ssh
ssh-keygen -t rsa
# copy ssh to register for git version system: cat ~/.ssh/id_rsa.pub
  • Add authorized key to login via ssh key on client
nano ~/.ssh/authorized_keys
-> copy ~/.ssh/id_rsa.pub on mac client to vps server
exit
# connect to VPS again to get new applied config
  • Config sudo without password
sudo visudo
=> Add to bottom of file
nhancv ALL=(ALL) NOPASSWD: ALL

Install Nginx

sudo apt update
sudo apt install nginx
sudo nano /etc/nginx/nginx.conf

# Increase client max body size by add below command to config file (in http block) and gzip compressor
http {
        ##
        # Basic Settings
        ##
        client_max_body_size 20M;

        ...

        ##
        # Gzip Settings
        ##
        gzip on;
        gzip_disable "MSIE [1-6]\.(?!.*SV1)";
        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_buffers 16 8k;
        gzip_http_version 1.1;
        gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
}

# Check config and restart nginx
sudo nginx -t -c /etc/nginx/nginx.conf
sudo service nginx restart

Install FTP

sudo apt install proftpd

# After install, can test connection with vps credentials
  • Disable Default Root
sudo nano /etc/proftpd/proftpd.conf

UNCOMMENT at line

# Use this to jail all users in their homes
# DefaultRoot                   ~

=> 
# Use this to jail all users in their homes
DefaultRoot 

Install MySQL

sudo apt update
sudo apt install mysql-server
sudo mysql_secure_installation
-> Yes for all
  • The secure config database account.
$ sudo mysql
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Root@123';
mysql> CREATE USER 'admin'@'%' IDENTIFIED BY 'Admin@123';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;
mysql> exit
  • Test connection
# Root
sudo mysql -u root -p

# Admin
sudo mysql -u admin -p
  • Create a database for WordPress
$ sudo mysql -u admin -p
mysql> CREATE DATABASE wordpress_database_nc;
mysql> CREATE USER 'wordpress_user_sql'@'localhost' IDENTIFIED BY 'Admin@123';
mysql> GRANT ALL PRIVILEGES ON wordpress_database_nc.* TO 'wordpress_user_sql'@'localhost' IDENTIFIED BY 'Admin@123';
mysql> FLUSH PRIVILEGES;
mysql> exit
  • Config allows remote access
$ sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf

# Change the line bind-address = 127.0.0.1 to bind-address = 0.0.0.0
bind-address        = 0.0.0.0

# Restart mysql
sudo systemctl restart mysql

Install PHP 7.2, PHP version will display after install php-fpm

sudo apt install curl unzip git php-fpm php-mysql php-gd php-curl

# Config git
git config --global user.name "Nhan Cao"
git config --global user.email nhancv92@gmail.com

# Configure the PHP Processor
sudo nano /etc/php/7.2/fpm/php.ini

# Update cgi fix path
; http://php.net/cgi.fix-pathinfo
cgi.fix_pathinfo=0

# Update upload_max_filesize
; Maximum allowed size for uploaded files.
; http://php.net/upload-max-filesize
upload_max_filesize = 50M

; Maximum size of POST data that PHP will accept.
; Its value may be 0 to disable the limit. It is ignored if POST data reading
; is disabled through enable_post_data_reading.
; http://php.net/post-max-size
post_max_size = 20M


# Restart PHP Processor
sudo systemctl restart php7.2-fpm

Install WordPress

  • Prepare workspace
mkdir -p ~/workspace/
cd ~/workspace/
wget https://wordpress.org/latest.zip -O ~/workspace/wplatest.zip 
  • Extract in Documents
unzip wplatest.zip
cp -r wordpress/ nhancv.com/
cd nhancv.com
mkdir wp-content/uploads
sudo chown www-data:www-data -R *
sudo find . -type d -exec chmod 755 {} \;
sudo find . -type f -exec chmod 644 {} \;
  • Add FTP for WordPress user
sudo useradd wordpress_ftp
sudo passwd wordpress_ftp
sudo usermod -m -d /home/nhancv/workspace/nhancv_com wordpress_ftp
sudo setfacl -R -m u:wordpress_ftp:rwx /home/nhancv/workspace/nhancv_com
sudo service proftpd restart
  • [Optional for dev] Declare virtual host IP in /etc/hosts on macOS client in Dev mode
sudo nano /etc/hosts

- For macOS client
171.16.30.31 nhancv.com

- For ubuntu server
127.0.0.1 nhancv.com
sudo nano /etc/nginx/sites-available/default
# Content
server {
    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;

    server_name _;
    rewrite ^/(.*)$ https://nhancv.com/$1 permanent;
    location / {
        try_files $uri $uri/ =404;
    }
    listen 80 default_server;
    listen [::]:80 default_server;
}
sudo nano /etc/nginx/sites-available/nhancv.com
  • Nginx config for wordpress site
server {
    listen 80;
    listen [::]:80;

    root /home/nhancv/workspace/nhancv.com;
    index index.php index.html index.htm;
    server_name nhancv.com *.nhancv.com;
    # This order might seem weird - this is attempted to match last if rules below fail.
    # http://wiki.nginx.org/HttpCoreModule
    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;
    }
    # Uncomment one of the lines below for the appropriate caching plugin (if used).
    #include global/wordpress-wp-super-cache.conf;
    #include global/wordpress-w3-total-cache.conf;
    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        }
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
    }
    location ~ /\.ht {
        deny all;
    }
}

# Make alias and apply
sudo ln -s /etc/nginx/sites-available/nhancv.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo service nginx reload
  • Access to nhancv.com
  • Complete setup guide on the web
  • Create wp-config.php manually
nano /home/nhancv/workspace/nhancv.com/wp-config.php
sudo chown www-data:www-data /home/nhancv/workspace/nhancv.com/wp-config.php
  • To backup database using MySQL dump
mysqldump -u wordpress_user_sql -p wordpress_database_nc > wordpress_database_nc_bk.sql

Setup SSL for nhancv.com domain

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot python-certbot-nginx
sudo certbot --nginx

# or for create new certificates only
sudo certbot certonly —nginx

# View all certificates information
sudo certbot certificates

Merge wildcard domain to home

- [Optional] Delete old domain cert
sudo certbot delete --cert-name nhancv.com

sudo certbot certonly \
--server https://acme-v02.api.letsencrypt.org/directory \
--manual --preferred-challenges dns -d *.nhancv.com -d nhancv.com

-> Yes -> 
Please deploy a DNS TXT record under the name
_acme-challenge.nhancv.com with the following value:
yB0AXXXXXXORZXTwzeXXXXXXXXXXXXXXXXmOoA1-XXX
Before continuing, verify the record is deployed.

==> Go to domain provider (ex: namecheap.com) -> Select domain -> Manage -> Advance DNS -> 
+ Add new TXT Record type with
+ Host: _acme-challenge
+ Value: yB0AXXXXXXORZXTwzeXXXXXXXXXXXXXXXXmOoA1-XXX
+ Save -> It may take some minutes

To check new config applied, open new terminal: 

$ nslookup -type=TXT _acme-challenge.nhancv.com

-> If you get `*** Can't find _acme-challenge.nhancv.com: No answer` mean the config is not successful. Response for successful: 

    Non-authoritative answer:
    _acme-challenge.nhancv.com    text = "yB0AXXXXXXORZXTwzeXXXXXXXXXXXXXXXXmOoA1-XXX"

When TXT config applied on domain provider, you need back to VPS terminal and enter to complete process. Successful message is 
——>
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/nhancv.com-0001/fullchain.pem

- Update nginx domain with new key file and server_name to *.nhancv.com
- Now you can access to:
nhancv.com
www.nhancv.com
https://nhancv.com
https://www.nhancv.com
  • Backup Nginx config: /etc/nginx/sites-available/default
server {
    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;

    server_name _;
    rewrite ^/(.*)$ https://nhancv.com/$1 permanent;
    location / {
        try_files $uri $uri/ =404;
    }
    listen 80 default_server;
    listen [::]:80 default_server;
}
  • Backup Nginx config for /etc/nginx/sites-available/nhancv.com
server {
    root /home/nhancv/workspace/nhancv.com;
    index index.php index.html index.htm;

    server_name nhancv.com;

    # This order might seem weird - this is attempted to match last if rules below fail.
    # http://wiki.nginx.org/HttpCoreModule
    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;
    }

    # Uncomment one of the lines below for the appropriate caching plugin (if used).
    #include global/wordpress-wp-super-cache.conf;
    #include global/wordpress-w3-total-cache.conf;

    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        }
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/nhancv.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/nhancv.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    listen 80;
    listen [::]:80;

    server_name *.nhancv.com;
    rewrite ^/(.*)$ https://nhancv.com/$1 permanent;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate /etc/letsencrypt/live/nhancv.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/nhancv.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    server_name *.nhancv.com;
    rewrite ^/(.*)$ https://nhancv.com/$1 permanent;
}

Leave a Reply

Your email address will not be published.Required fields are marked *