Use this Tutorial to Migrate Websites from Shared Hosting to VPS.
From having multiple domains on a shared server achieving a server response time of 3 seconds, I migrated them across to a single server; getting a server response time to under 0.3 seconds. Also with a PageSpeed Insights score of 100%.
Create a LEMP Stack Server configured with:
- Linux(debian Jessie)/
- NGINX(pagespeed module)/
- MariaDB/
- PHP7 – with
- Multiple WordPress websites configured with
- Letsencrypt(https), and
- Cloudflare CDN.
Introduction
Tutorial to Migrate Website(s) from Shared Hosting to VPS.
This tutorial will show you a comprehensive process to migrate your existing websites from a shared hosting server to a VPS, with far greater speed and security than your current setup. This walk-through is also created for the purposes of anyone wanting to build their site(s) server from scratch.
After much research on this subject myself, I came across various websites that were either giving instructions on very simple tutorials, or offering paid services to complete server transfers/migrations.
This invariably led me to dig around and do my research in finding the missing pieces, in terms of getting past the technical stop/start, trial and error scenarios; to then be fully confident in doing this multiple times.
So in my case, without mentioning the name of my previous shared server provider(s), I felt that when I had outage issues, I could not interrogate/fix the given problems-as you may already know there are certain resource limitations when having a website on a shared server.
In addition, there are also security issues with shared hosting, as you are effectively sharing servers with everyone else, you will ostensibly experience downtime.
The main benefits for migrating are:
Cost – VPS service is only $5/month with multiple websites running.
Speed – I migrated from a LAMP(Apache) stack to creating LEMP (Linux, NGINX, MariaDB, PHP)stack. You can also deploy your sites with Cloudflare free cloud services.
Flexibility – You are solely responsible for looking after your server, not at the mercy of on-call technicians when there is significant downtime, chasing ticket updates- stabbing in the dark to interrogate a technical problem without the correct tools at your disposal.
Security – Also with logging into your server, you can fully secure your websites by integrating a free https secure connection for your visitors.
With all this in mind, if you follow this tutorial, you can have multiple sites with NGINX (which is very fast), Cloud based services to fulfil CDN requirements. You will have a free https site, also running with Google page speed module, an open-source server module that optimises your site automatically.
All this achieved with only $5/month. No brainer!!
Server Basics
Before you begin – I would recommend creating an SSH Key pair on your “Local Machine”:
1 |
ssh-keygen |
After you have completed this you will create your VPS instance. I would recommend choosing Debian Jessie as the image, a size of 512MB would suffice for the price of $5, and the Data-centre region.
Now choose a New SSH Key:
Here you will copy the output from your local machine Key you generated earlier:
1 |
cat ~/.ssh/id_rsa.pub |
Into the New SSH Key Option:
Server Setup
Now “Create” your VPS and you will be assigned a unique IP address. As you will have the pre-shared key you created earlier it will make your connection more secure.
To Login you will want to
1 |
ssh root@yourserver_ip |
For added security, you will now need to create a user of your choice:
1 |
adduser yourusername |
For elevated root user privileges – add the user to the sudo group:
1 |
usermod -a -G sudo yourusername |
On your local machine you will now want to apply the same SSH to the new user
1 |
ssh-copy-id youusername@yourserver_ip |
Back into your server terminal session, you will want to disable the root user login:
1 |
nano /etc/ssh/sshd_config |
scroll down to:
1 |
#PermitRootLogin yes |
change this to:
1 |
PermitRootLogin no |
CTRL+X & Y – ENTER to save
1 |
systemctl restart ssh |
Quit your session and re-login with you new user:
1 |
ssh yourusername@yourserver_ip |
Furthermore, you can optionally, change your default port to something different in “/etc/ssh/sshd_config” and alter port#(up to 65535). Under these conditions you have to login using:
1 |
ssh -p port# yourusername@yourserver_ip |
Now you will want to create a basic firewall, to inhibit brute force attacks. There are many options to do so such as fail2ban, or UFW. There are also options to install Nginx-Naxsi meaning (Nginx Anti XSS & SQL Injection), but at the moment of writing this-it cannot be installed coupled with Nginx pagespeed module.
1 |
sudo apt-get update |
1 |
sudo apt-get install ufw |
1 |
sudo ufw enable |
1 |
sudo ufw allow 22 |
Now we configure the Timezone & NTP synchronisation
1 |
sudo dpkg-reconfigure tzdata |
1 2 |
sudo apt-get update sudo apt-get install ntp |
For performance, I recommend creating a swap file, as we have a VPS instance of 512MB RAM, we will create a file of 1GB.
1 |
sudo fallocate -l 1G /swapfile |
Ensure this is only accessible to root users:
1 |
sudo chmod 600 /swapfile |
Mark the file as swap space and enable:
1 2 |
sudo mkswap /swapfile sudo swapon /swapfile |
To ensure this change is permanent, for instance on a reboot type:
1 2 |
sudo cp /etc/fstab /etc/fstab.bak echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab |
Lets tweak the performance settings of the server swap file:
1 |
sudo sysctl vm.swappiness=10 |
You will want to also make this permanent with additionally adding cache pressure. Simply at the bottom of this file:
1 |
sudo nano /etc/sysctl.conf |
input these values:
1 2 |
vm.swappiness=10 vm.vfs_cache_pressure=50 |
CTRL+X & Y – ENTER to save
At this stage I would create a Snapshot/Backup of your server.
Building the LEMP Stack
Lets start by building NGINX with PageSpeed Module:
1 |
sudo apt-get update && sudo apt-get install build-essential |
For those that have NGINX already installed and want to remove NGINX before you install PSM:
1 2 |
sudo service nginx stop sudo apt-get remove '^nginx.*' |
New install
1 |
sudo apt-get install build-essential zlib1g-dev libpcre3-dev libssl-dev libxslt1-dev libxml2-dev libgd2-xpm-dev libgeoip-dev libgoogle-perftools-dev libperl-dev |
Add the NGINX deb to the list:
1 |
sudo nano /etc/apt/sources.list.d/nginx.list |
Paste these
1 2 |
deb http://nginx.org/packages/debian/ jessie nginx deb-src http://nginx.org/packages/debian/ jessie nginx |
CTRL+X & Y – ENTER to save
1 |
sudo apt-get update |
Add the key when prompted for a missing one
1 2 |
wget -q "http://nginx.org/packages/keys/nginx_signing.key" -O-| sudo apt-key add - sudo apt-get update |
Now install zip for the Page Speed Module
1 |
sudo apt-get install zip |
Now as per the official Google NGINX Pagespeed Module add these commands
1 2 |
bash <(curl -f -L -sS https://ngxpagespeed.com/install) \ --nginx-version latest |
Now add the additional modules when prompted(newer versions of Nginx psm may not need some of these modules):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
cd nginx-${NGINX_VERSION}/ ./configure --sbin-path=/usr/sbin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --http-log-path=/var/log/nginx/access.log \ --error-log-path=/var/log/nginx/error.log \ --lock-path=/var/lock/nginx.lock \ --pid-path=/run/nginx.pid \ --user=www-data \ --group=www-data \ --with-debug \ --with-pcre-jit \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_realip_module \ --with-http_auth_request_module \ --with-http_addition_module \ --with-http_dav_module \ --with-http_flv_module \ --with-http_geoip_module \ --with-http_gunzip_module \ --with-http_gzip_static_module \ --with-http_image_filter_module \ --with-http_mp4_module \ --with-http_perl_module \ --with-http_random_index_module \ --with-http_secure_link_module \ --with-http_v2_module \ --with-http_sub_module \ --with-mail \ --with-mail_ssl_module \ --with-stream \ --with-stream_ssl_module \ --with-threads \ --with-file-aio \ --with-http_ssl_module \ --with-http_xslt_module \ --with-http_degradation_module \ --with-pcre \ --with-google_perftools_module \ --add-module=${DIRECTORY}/headers-more-nginx-module-${HEADERS_VERSION} \ --add-module=${DIRECTORY}/ngx_pagespeed-release-${PAGESPEED_VERSION}-beta |
As we are manually building NGINX Pagespeed Module we now have to create an INIT script:
1 |
sudo nano /etc/init.d/nginx> |
Now add this to the script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
#! /bin/sh ### BEGIN INIT INFO # Provides: nginx # Required-Start: $all # Required-Stop: $all # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts the nginx web server # Description: starts nginx using start-stop-daemon ### END INIT INFO PATH=/usr/local/nginx:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/local/nginx/sbin/nginx NAME=nginx DESC=nginx test -x $DAEMON || exit 0 # Include nginx defaults if available if [ -f /etc/default/nginx ] ; then . /etc/default/nginx fi set -e case "$1" in start) echo -n "Starting $DESC: " start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \ --exec $DAEMON -- $DAEMON_OPTS echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \ --exec $DAEMON echo "$NAME." ;; restart|force-reload) echo -n "Restarting $DESC: " start-stop-daemon --stop --quiet --pidfile \ /usr/local/nginx/logs/$NAME.pid --exec $DAEMON sleep 1 start-stop-daemon --start --quiet --pidfile \ /usr/local/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS echo "$NAME." ;; reload) echo -n "Reloading $DESC configuration: " start-stop-daemon --stop --signal HUP --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \ --exec $DAEMON echo "$NAME." ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|force-reload}" >&2 exit 1 ;; esac exit 0 |
CTRL+X & Y – ENTER to save
Next create a file with permissions for Nginx cache files:
1 2 |
sudo mkdir /var/ngx_pagespeed_cache sudo chown www-data:www-data /var/ngx_pagespeed_cache |
To find where NGINX is installed type:
1 |
whereis nginx |
Output should be:
nginx: /etc/nginx /usr/local/nginx
Now lets configure our conf file with the Pagespeed configuration:
1 |
sudo nano /usr/local/nginx/conf/nginx.conf |
Paste this into the bottom of the file:
1 2 3 4 5 6 7 |
pagespeed on; pagespeed FileCachePath "/var/cache/ngx_pagespeed/"; location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" { add_header "" ""; } location ~ "^/pagespeed_static/" { } location ~ "^/ngx_pagespeed_beacon |
1 |
1 |
quot; { } pagespeed RewriteLevel CoreFilters; } |
CTRL+X & Y – ENTER to save
To Prevent excessive disk I/O You can further in depth optimise the nginx.conf file, depending on your requirements with recommended buffer size values.
NB: the “client_max_body_size” is the limit to which plugins/themes can be uploaded in your WP directory.
1 2 3 4 5 6 |
client_body_buffer_size 128k; client_max_body_size 10m; client_header_buffer_size 1k; large_client_header_buffers 4 4k; output_buffers 1 32k; postpone_output 1460; |
Now reboot the system and type:
1 |
systemctl status nginx |
You should see:
● nginx.service – LSB: starts the nginx web server
Loaded: loaded (/etc/init.d/nginx)
Active: active (exited)
Mark nginx to be blocked from further updates via apt-get
1 |
sudo dpkg --get-selections | grep nginx |
For every nginx component listed run sudo apt-mark hold
Additional commands useful for interrogation of NGINX
1 2 3 4 5 |
sudo tail -f /usr/local/nginx/logs/error.log sudo /etc/init.d/nginx start sudo /etc/init.d/nginx stop sudo /etc/init.d/nginx restart sudo /etc/init.d/nginx reload |
Reload the configuration and Curl:
1 2 |
sudo /etc/init.d/nginx reload curl -I -p http://localhost |
The output should printout the page speed installed:
1 2 3 4 5 6 7 8 |
HTTP/1.1 200 OK Server: nginx/1.11.6 Content-Type: text/html Connection: keep-alive Vary: Accept-Encoding Date: Wed, 01 Feb 2017 00:39:19 GMT X-Page-Speed: 1.11.33.4-0 Cache-Control: max-age=0, no-cache |
Troubleshooting
First check to see if HTTP connections on Port 80 is in use:
1 |
sudo ufw status |
If it is not enabled then do so with this command:
1 |
sudo ufw allow 80 |
Or alternatively you can use:
1 |
sudo ufw allow http |
or:
1 |
sudo ufw allow 'Nginx HTTP' |
For those that have issues with this error:
1 |
‘Failed to start nginx.service: Unit nginx.service is masked.’ |
The fix for this is to:
1 |
cd /etc/systemd/system |
1 |
sudo rm nginx.service |
Reboot the system &:
1 |
systemctl status nginx |
For users that are replacing their existing NGINX configurations, as mentioned previously; it was recommended to Stop the NGINX service before we integrated the new NGINX Pagespeed Module. If you didn’t apply this command, the error you can get is:
1 |
[emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use) |
Type this command to see the status of Nginx to see which processes may still be running, listening on port 80:
1 |
ps -ef | grep nginx |
1 |
netstat -npl | grep 80 |
Find the PID number and now type:
1 |
sudo kill PID# |
Now try:
1 2 3 |
sudo systemctl enable nginx.service sudo systemctl start nginx.service sudo systemctl status nginx.service |
Assuming you have an active Nginx service Loaded and enabled, check in your browser:
http://yourserver_ip
Install PHP7
1 |
sudo apt-get install php7.0-cli php7.0-curl php7.0-dev php7.0-zip php7.0-fpm php7.0-gd php7.0-xml php7.0-mysql php7.0-mcrypt php7.0-mbstring php7.0-opcache -y |
Open up the main php conf file
1 |
sudo nano /etc/php/7.0/fpm/pool.d/www.conf |
CTRL + W (to find “pm.max_children”) ENTER
Change this value and also max requests on both lines respectively to:
1 2 |
pm.max_children = 9 pm.max_requests = 200 |
This amendment is based on the calculation of using a server with 512 Mb memory and 220 Mb could be used for PHP-FPM, so if every process uses 24 Mb RAM, server max_children value is
220 / 24 = 9.17 (hence the value rounded off to 9).
Checking the activity of Memory usage you can simply type “htop” or “top”, sans the quotations, to interrogate real-time child processes usage.
Tweak some settings to secure php, by disallowing script execution:
1 |
sudo nano /etc/php/7.0/fpm/php.ini |
Find the line with cgi.fix_pathinfo, ensuring to omit the “;”, and replace with
1 |
cgi.fix_pathinfo=0 |
Also find these lines with CTRL + W, ENTER, and amend accordingly:
1 2 3 4 |
date.timezone = America/New_York upload_max_filesize = 8M max_execution_time = 60 max_input_vars = 5000 |
CTRL+X & Y – ENTER to save
1 |
sudo systemctl restart php7.0-fpm |
Install MariaDB
1 |
sudo apt-get install mariadb-server mariadb-client -y |
Lets tweak some basic settings for a wordpress install:
1 |
sudo nano /etc/mysql/my.cnf |
change these lines to:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# * Fine Tuning # key_buffer = 16M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 8 # This replaces the startup script and checks MyISAM tables if needed # the first time they are touched myisam-recover = BACKUP #max_connections = 100 #table_cache = 64 #thread_concurrency = 10 # # * Query Cache Configuration # query_cache_limit = 1M query_cache_size = 20M |
Migrate your files & upload to new Server:
I shall assume that you are not granted SSH login access to your account – Log into your Shared Hosting account and navigate to your CPANEL – “Site Backup Pro” page.
The important files we need are the database sql.zip files, WP-config.php file and your WP-content folder.
Depending on whether your Hosting provider permits, you can download your full MySql, also your Website files. Download both if you can or a Full Cpanel Backup.
If you cannot do this then you will have to manually download from your PHPMyadmin database in your CPanel:
If you have limitations in accessing your website files through backup pro, simply navigate to your website files option and download the ‘WP-content’ folder, and the ‘WP-config.php’ file. If you cannot see the files listed in your “Public_HTML directory” then you need to ask your hosting provider for elevated root privilege to access/view/modify and ultimately download this file.
Additionally, if you dont have access to PHPAdmin you can use these commands to do a mysqldump of the website database. First you need to create a new file
1 |
nano ~/.my.cnf |
Now insert these lines unique to your credentials, and save:
1 2 3 |
[mysqldump] user = mysqluser password = mysqlpassword |
Alter the permissions of the new file:
1 |
chmod 600 ~/.my.cnf |
Now run this command as you will now not be prompted for password:
1 |
mysqldump --databases database_name -u mysqluser --hex-blob > backup_database_name.sql |
I gave this recommendation, as sometimes mysqldumps can have errors when using command “mysqldump -p”. This isnt the most secure option, but we are migrating anyway, and you can undo this option afterwards, so onwards you can now zip this file and SFTP to your new server.
Now you have these files you can upload them to your server /tmp directory with scp on your local machine:
1 |
scp your.sql.zip yourusername@yourserver_ip:/tmp |
1 |
scp wp-content.zip yourusername@yourserver_ip:/tmp |
Now navigate to your tmp folder in your server:
1 |
cd /tmp |
1 |
sudo unzip your.sql.zip |
1 |
sudo rm -r your.sql.zip |
Now open the “wp-config.php” file you downloaded and copy the details highlighted:
1 2 3 4 5 6 7 8 9 |
// ** MySQL settings – You can get this info from your web host ** // /** The name of the database for WordPress */ define(‘DB_NAME’, ‘YOUR_DATABASE_NAME‘); /** MySQL database username */ define(‘DB_USER’, ‘YOUR_DATABASE_USER‘); /** MySQL database password */ define(‘DB_PASSWORD’, ‘YOUR PASSWORD‘); |
Now login to your MariaDB (MySQL drop in)
1 |
sudo mysql -u root -p |
Paste/replace the details related to your wp-config.php file
1 2 3 4 5 |
CREATE USER YOUR_DATABASE_USER@localhost IDENTIFIED BY 'PASSWORD'; CREATE DATABASE YOUR_DATABASE_NAME; GRANT ALL PRIVILEGES ON YOUR_DATABASE_NAME.* TO YOUR_DATABASE_USER@localhost IDENTIFIED BY 'PASSWORD'; FLUSH PRIVILEGES; quit; |
1 |
show databases; |
1 |
use YOUR_DATABASE_NAME; |
1 |
select database(); |
Now we source the .sql folder we uploaded and unzipped earlier from the /tmp folder. Feel free to delete this zip file after execution of this command:
1 |
source /tmp/your.sql; |
1 |
quit; |
1 |
sudo service php7.0-fpm restart |
Create NGINX server block(s):
There are other permutations you can create these files in Nginx such as yourdomain.com.conf, and creating all your domains in the same Nginx .conf server block. Like apache structure, we will create the folders for our sites config, if you are familiar with this construction:
1 |
sudo mkdir -p /etc/nginx/sites-available |
1 |
sudo mkdir -p /etc/nginx/sites-enabled |
1 |
sudo nano /etc/nginx/sites-available/yourdomain.com |
What we need to do now is ensure our site is listening to port 80, and the Pagespeed Module is added to our site server block. We will also add be factoring in cache for all necessary filetypes. In addition, we are securing our wordpress install to prevent standalone, maliciously planted code to be executed from any of the WP-content(uploads folder), WP-config.php, WP-includes and also XML RPC if for example you want to install Jetpack. Paste this into your new file and replace with your domain:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
server { server_name www.yourdomain.com yourdomain.com; listen 80; port_in_redirect off; access_log /var/log/nginx/yourdomain.com.access.log; error_log /var/log/nginx/yourdomain.com.error.log error; root /var/www/yourdomain.com/; index index.php index.html index.htm; location / { try_files $uri $uri/ /index.php?$args; } # Cache static files for as long as possible location ~*.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf|cur)$ { expires max; log_not_found off; access_log off; } location /xmlrpc.php { deny all; } # Deny public access to wp-config.php location ~* wp-config.php { deny all; } location ~* /wp-includes/.*.php$ { deny all; access_log off; log_not_found off; } location ~* /wp-content/.*.php$ { deny all; access_log off; log_not_found off; } pagespeed on; pagespeed FileCachePath "/var/cache/ngx_pagespeed/"; location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" { add_header "" ""; } location ~ "^/pagespeed_static/" { } location ~ "^/ngx_pagespeed_beacon |
1 |
1 |
quot; { } location ~ \.php$ { try_files $uri =404; include fastcgi_params; fastcgi_pass unix:/run/php/php7.0-fpm.sock; fastcgi_split_path_info ^(.+\.php)(.*)$; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } |
CTRL+X & Y – ENTER to save
Now we need to symlink our sites-available to our sites enabled folder:
1 |
sudo ln -s /etc/nginx/sites-available/yourwebsite.com /etc/nginx/sites-enabled/yourwebsite.com |
Now we need to make sure our nginx.conf file is looking at our new site created in the sites-enabled folder by opening:
1 |
sudo nano /usr/local/nginx/conf/nginx.conf |
and looking for these lines:
1 2 |
include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; |
Also as Nginx uses the default user www-data, as we did so earlier whilst building Nginx, ensure that this is added at the top of this nginx.conf file:
1 |
user www-data; |
CTRL+X & Y – ENTER to save
1 |
sudo /etc/init.d/nginx reload |
NB: Repeat this section to create an additional server block for multiple websites.
If you always want to see if your site is now actually configured with Pagespeed module navigate to this address and put your domain details in:
Create WordPress install:
Here we download the latest WordPress install to our /var/www/ folder we will create, and open up again our sites wp-config.php, and find/replace with the details we added earlier to our database:
1 2 3 4 5 6 7 8 |
sudo mkdir -p /var/www/yourwebsite.com cd /var/www/yourwebsite.com sudo wget http://wordpress.org/latest.tar.gz sudo tar --strip-components=1 -xvf latest.tar.gz sudo rm latest.tar.gz sudo chown -R www-data:www-data /var/www/yourwebsite.com sudo cp /var/www/yourwebsite.com/wp-config-sample.php wp-config.php sudo nano /var/www/yourwebsite.com/wp-config.php |
Not only adding the details of our database/user/password, but also the authenticated unique key and salts.
Secondly you may have change the name of your table prefix to make it more secure, so also change this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
/** The name of the database for WordPress */ define('DB_NAME', 'YOUR_DATABASE_NAME'); /** MySQL database username */ define('DB_USER', 'YOUR_DATABASE_USER'); /** MySQL database password */ define('DB_PASSWORD', 'PASSWORD'); /** MySQL hostname */ define('DB_HOST', 'localhost'); /** 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 https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org 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 */ define('AUTH_KEY', 'YOUR_KEY'); define('SECURE_AUTH_KEY', 'YOUR_KEY'); define('LOGGED_IN_KEY', 'YOUR_KEY'); define('NONCE_KEY', 'YOUR_KEY'); define('AUTH_SALT', 'YOUR_KEY'); define('SECURE_AUTH_SALT', 'YOUR_KEY'); define('LOGGED_IN_SALT', 'YOUR_KEY'); define('NONCE_SALT', 'YOUR_KEY'); /**#@-*/ /** * 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_YOUR_prefix'; |
Now we secure ownership and sub-directory permissions:
1 2 3 |
sudo chown -R www-data:www-data /var/www/yourwebsite.com sudo find /var/www/yourwebsite.com -type d -exec chmod 755 {} + sudo find /var/www/yourwebsite.com -type f -exec chmod 644 {} + |
Now we want to replace our previously uploaded ‘WP-Content’ folder with the the new WordPress install we downloaded.
1 2 3 4 5 6 |
cd /tmp sudo mv wp-content.zip /var/www/yourwebsite.com/ cd /var/www/yourwebsite.com/ sudo rm -r wp-content sudo unzip wp-content.zip sudo rm -r wp-content.zip |
Update your DNS records to point to your new server and restart PHP & Nginx:
1 2 |
sudo service nginx restart sudo service php7.0-fpm restart |
If you want to update your Core-Wordpress/Themes/Plugins via command line you can also do if this using WP-CLI, without logging in through ‘yourdomain.com/wp-admin’.
Simply Curl to install WP-CLI:
1 2 3 |
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar chmod +x wp-cli.phar cd /var/www/yourdomain.com |
1 2 3 |
wp plugin update --all wp theme update --all wp core update |
Now you will want to change permissions back to your ‘yourusername’ and subdirectory folder permissions. This will prevent anyone from changing anything via ‘wp-login’:
1 2 |
sudo chown -R yourusername /var/www/yourdomain.com sudo chmod -R 755 /var/www/yourdomain.com/wp-content/uploads |
Install Free SSL/TLS Certificate from Let’s Encrypt:
First we will open our firewall port to accept https connections:
1 |
sudo ufw allow https |
or
1 |
sudo ufw allow 443 |
Now to add the Debian Jessie backports repository and the certbot to configure our SSL certificate:
1 2 3 |
sudo echo 'deb http://ftp.debian.org/debian jessie-backports main' | sudo tee /etc/apt/sources.list.d/backports.list sudo apt-get update sudo apt-get install certbot -t jessie-backports |
Now add this snippet to your website server block configuration file in:
1 |
sudo nano /etc/nginx/sites-available/yourdomain.com |
with
1 2 3 |
location ~ /.well-known { allow all; } |
now reload the configuration:
1 |
sudo /etc/init.d/nginx reload |
Request the cert:
1 |
sudo certbot certonly -a webroot --webroot-path=/var/www/yourdomain.com -d yourdomain.com -d www.yourdomain.com |
should give you the printout:
1 2 3 4 5 6 7 |
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/yourdomain.com/fullchain.pem. Your cert will expire on 2017-05-09. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" |
Now recheck the certificate was created in the correct folders that we will add to our server block again:
1 |
sudo ls -l /etc/letsencrypt/live/yourdomain.com |
With the printout:
1 2 3 4 |
lrwxrwxrwx 1 root root 38 Feb 8 12:34 cert.pem -> ../../archive/yourdomain.com/cert1.pem lrwxrwxrwx 1 root root 39 Feb 8 12:34 chain.pem -> ../../archive/yourdomain.com/chain1.pem lrwxrwxrwx 1 root root 43 Feb 8 12:34 fullchain.pem -> ../../archive/yourdomain.com/fullchain1.pem lrwxrwxrwx 1 root root 41 Feb 8 12:34 privkey.pem -> ../../archive/yourdomain.com/privkey1.pem |
For added security we will generate the Diffie–Hellman key exchange:
1 |
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048 |
it will printout this, but will take a couple of minutes to finish:
1 2 3 |
Generating DH parameters, 2048 bit long safe prime, generator 2 This is going to take a long time ..................................................................................+.........................................+.................................................................................. |
You may want your site to still listen to http and https connections so you can request 301 redirects to https, whilst having you main server block listening to port 443 with ssl http2. Here you will be adding the ssl certificate chain where you created earlier.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
server { listen 80; listen [::]:80; server_name www.yourdomain.com yourdomain.com; return 301 https://www.yourdomain.com$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name yourdomain.com; return 301 https://www.yourdomain.com$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name www.yourdomain.com; port_in_redirect off; access_log /usr/local/nginx/logs/yourdomain.com.access.log; error_log /usr/local/nginx/logs/yourdomain.com.error.log error; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; root /var/www/yourdomain.com/; index index.php; |
Now we will setup our auto-renewal using cron script to execute every month:
1 |
sudo nano /etc/cron.monthly/renew-ssl-certificates |
Input your site details:
1 |
/opt/certbot/letsencrypt-auto certonly -c /etc/certbot/yourdomain.com --renew-by-default |
1 |
sudo /etc/init.d/nginx reload |
Now when you login to yourdomain.com, you will need to change the https://www.yourdomain.com/wp-admin/options-general.php ‘WordPress & Site addressURL’ options to https, to now reflect your changes.
In addition, if you are getting ‘Mixed Content’ warnings you can use the plugin SSL Insecure Content Fixer.
Finally check your domain in a web browser to find the grade of your certificate https connection:
Cloudflare CDN setup:
I left this task to the end because there were conflicting issues when integrating cloudflare DNS records prior to configuring your SSL certificate. In relation to this , you can setup a free account with Cloudflare and you will be prompted to change your DNS records in your DNS provider. When you are done with adding your domain you will need to make a couple of changes:
As well as having your DNS records updated in your server for the ‘A’, ‘CNAME’ & ‘NS’ included, you will be asked for them in Cloudflare too. There are other caching and minify options, but you will also need to create a ‘page rule’ as above to ‘Always use HTTPS’, when http version of your site is loaded.
19 Comments
Hello would you mind letting me know which web host you’re using?
I’ve loaded your blog in 3 completely different browsers and I must say this
blog loads a lot faster then most. Can you recommend a good web hosting provider
at a reasonable price? Cheers, I appreciate it!
Digital ocean. If you want more simplicity try bluehost.
Greate pieces. Keep posting such kind of info on your site.
Im really impressed by your site.
Hello there, You’ve performed an excellent job. I will definitely digg it and in my opinion recommend to my friends.
I am sure they’ll be benefited from this web site.
glad you like it. Quick reminder as of may 20, I had to update my lets encrypt to v2.
Good day! I know this is kinda off topic but I’d figured I’d ask.
Would you be interested in exchanging links or maybe guest writing a blog post or vice-versa?
My website covers a lot of the same subjects as yours and I believe we
could greatly benefit from each other. If you’re interested feel free to shoot me an email.
I look forward to hearing from you! Excellent blog by the way!
Thank you for the good writeup. It in fact was
a amusement account it. Look advanced to far added agreeable
from you! By the way, how can we communicate?
Thanks for finally writing about > Get 100/100 Google PageSpeed Insights
score with WordPress < Loved it!
Hello, I think your site might be having browser compatibility issues.
When I look at your blog site in Chrome, it looks fine but when opening in Internet Explorer,
it has some overlapping. I just wanted to give you a quick heads up!
Other then that, fantastic blog!
Everything is very open with a precise clarification of the challenges.
It was truly informative. Your website is extremely
helpful. Thank you for sharing!
Great post. I was checking constantly this blog and I am impressed!
Extremely useful information specifically the ultimate section :
) I maintain such info a lot. I used to be seeking this
particular info for a long time. Thank you and best of luck.
I like it whenever people come together and share
opinions. Great website, keep it up!
Wonderful blog! I found it while searching on Yahoo News.
Do you have any suggestions on how to get listed in Yahoo News?
I’ve been trying for a while but I never seem to get there!
Cheers
I do not even know the way I ended up right here, but I believed this put up
used to be good. I don’t recognise who you might be however certainly
you are going to a famous blogger should you are not already.
Cheers!
Hello there, I discovered your website by way of Google even as looking for a
comparable topic, your site came up, it seems to be good. I’ve bookmarked
it in my google bookmarks.
Hi there, simply became aware of your weblog via Google,
and found that it is really informative. I am gonna be careful for
brussels. I’ll be grateful when you proceed this in future.
Many other folks shall be benefited out of your writing.
Cheers!
Howdy! Do you know if they make any plugins to
assist with Search Engine Optimization? I’m
trying to get my blog to rank for some targeted keywords but I’m not seeing very good results.
If you know of any please share. Cheers!
Excellent pieces. Keep writing such kind of information on your site.
Im really impressed by your site.
Hey there, You’ve performed an excellent job. I will definitely
digg it and for my part suggest to my friends. I’m confident they will be benefited from this website.
Generally I don’t read post on blogs, but I wish to say that this write-up very pressured me to
try and do so! Your writing taste has been surprised
me. Thank you, very great article.
Thanks on your marvelous posting! I truly enjoyed reading it,
you could be a great author. I will ensure that I bookmark your blog
and definitely will come back down the road.
I want to encourage you to ultimately continue your great writing, have a nice holiday
weekend!
What’s up to every one, the contents existing at this web site are actually awesome for people experience,
well, keep up the nice work fellows.