How To Install WordPress with LEMP on Ubuntu 16.04
Introduction
WordPress is the most popular CMS (content management system) on the internet. It allows you to easily set up flexible blogs and websites on top of a MySQL backend with PHP processing. WordPress has seen incredible adoption and is a great choice for getting a website up and running quickly. After setup, almost all administration can be done through the web frontend.
In this guide, we’ll focus on getting a WordPress instance set up on a LEMP stack (Linux, Nginx, MySQL, and PHP) on an Ubuntu 16.04 server.
Prerequisites
In order to complete this tutorial, you will need access to an Ubuntu 16.04 server.
You will need to perform the following tasks before you can start this guide:
- Create a sudo user on your server: We will be completing the steps in this guide using a non-root user with sudo privileges. You can create a user with sudo privileges.
- Install a LEMP stack: WordPress will need a web server, a database, and PHP in order to correctly function. Setting up a LEMP stack (Linux, Nginx, MySQL, and PHP) fulfills all of these requirements.
- Secure your site with SSL: WordPress serves dynamic content and handles user authentication and authorization. TLS/SSL is the technology that allows you to encrypt the traffic from your site so that your connection is secure. The way you set up SSL will depend on whether you have a domain name for your site.
I. Install a LEMP stack:
Step 1: Install the Nginx Web Server
1 2 |
sudo apt-get install nginx sudo systemctl enable nginx |
Step 2: Install MySQL to Manage Site Data
1 2 3 |
sudo apt-get install mysql-server sudo systemctl enable mysql sudo mysql_secure_installation |
Step 3: Install PHP for Processing
1 2 3 |
sudo apt-get install mcrypt curl php7.0-cli php7.0-cgi php7.0-fpm php7.0-mysql php7.0-curl php7.0-gd php7.0-intl php-pear php-imagick php7.0-imap php7.0-mcrypt php-memcache php7.0-pspell php7.0-recode php7.0-sqlite3 php7.0-tidy php7.0-xmlrpc php7.0-xsl php7.0-mbstring php-gettext sudo systemctl enable php7.0-fpm sudo nano /etc/php/7.0/fpm/php.ini |
We will change both of these conditions by uncommenting the line and setting it to “0” like this:
1 |
cgi.fix_pathinfo=0 |
1 |
sudo nano /etc/php/7.0/fpm//php.ini |
1 |
upload_max_filesize = 20M |
1 |
sudo systemctl restart php7.0-fpm |
II. Configure LEMP Stack
Step 1: Create a MySQL Database and User for WordPress
1 2 3 4 5 |
mysql -u root -p CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; GRANT ALL ON wordpress.* TO 'wordpressuser'@'localhost' IDENTIFIED BY 'password'; FLUSH PRIVILEGES; exit; |
Step 2: Set Up Nginx Server Blocks (Virtual Hosts)
1 2 3 |
sudo mkdir -p /var/www/vhost/example.com/public_html sudo chown -R www-data.www-data /var/www/vhost/example.com/public_html sudo chmod -R 755 /var/www |
Create Server Block File
1 2 |
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example.com.conf ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/example.com.conf |
Step 3: Adjust Nginx’s Configuration to Correctly Handle WordPress
1 |
sudo nano /etc/nginx/nginx.conf |
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 |
user www-data; worker_processes 2; pid /run/nginx.pid; events { worker_connections 1024; # multi_accept on; } http { ## # Basic Settings ## sendfile on; # tcp_nopush on; # tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; client_max_body_size 13m; include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } |
1 |
sudo nano /etc/nginx/sites-available/example.com.conf |
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
## fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:500m inactive=60m; fastcgi_cache_key "$scheme$request_method$host$request_uri"; fastcgi_cache_use_stale error timeout invalid_header http_500; # server { listen 80; # SSL configuration # listen 443 ssl; # # Self signed certs generated by the ssl-cert package # ssl_certificate /etc/ssl/certs/ssl-cert-example.com.pem; ssl_certificate_key /etc/ssl/private/ssl-cert-example.com.key; # Enable HSTS. This forces SSL on clients that respect it, most modern browsers. The includeSubDomains flag is optional. add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"; # Set caches, protocols, and accepted ciphers. This config will merit an A+ SSL Labs score as of Sept 2015. ssl_session_cache shared:SSL:20m; ssl_session_timeout 10m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:CAMELLIA256-SHA:CAMELLIA128-SHA256; root /var/www/vhost/example.com/public_html; # Add index.php to the list if you are using PHP index index.php index.html index.htm index.nginx-debian.html; server_name example.com www.example.com; location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. try_files $uri $uri/ /index.php?$args; } # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # # location ~ \.php$ { location ~ [^/]\.php(/|$) { include snippets/fastcgi-php.conf; fastcgi_split_path_info ^(.+?\.php)(/.*)$; if (!-f $document_root$fastcgi_script_name) { return 404; } fastcgi_cache_bypass $no_cache; fastcgi_no_cache $no_cache; fastcgi_cache WORDPRESS; fastcgi_cache_valid 200 60m; fastcgi_buffers 32 32k; fastcgi_buffer_size 32k; fastcgi_pass unix:/run/php/php7.0-fpm.sock; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { allow all; log_not_found off; access_log off; } # 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; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # location ~ /\.ht { deny all; } location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { expires max; log_not_found off; } set $no_cache 0; # POST requests and urls with a query string should always go to PHP if ($request_method = POST) { set $no_cache 1; } if ($query_string != "") { set $no_cache 1; } # Don't cache uris containing the following segments if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") { set $no_cache 1; } # Don't use the cache for logged in users or recent commenters if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") { set $no_cache 1; } } |
1 2 |
sudo mkdir -p /var/run/nginx-cache sudo chown -R www-data.www-data /var/run/nginx-cache |
1 2 |
sudo nano /etc/ssl/certs/ssl-cert-example.com.pem sudo nano /etc/ssl/private/ssl-cert-example.com.key |
Now, we can check our configuration for syntax errors by typing:
1 |
sudo nginx -t |
If no errors were reported, reload Nginx and PHP-fpm by typing:
1 2 |
sudo systemctl restart nginx sudo systemctl restart php7.0-fpm |
Step 4: Download and Configure WordPress
1 2 3 4 5 6 |
cd /tmp wget https://wordpress.org/latest.tar.gz tar xzvf latest.tar.gz cp /tmp/wordpress/wp-config-sample.php /tmp/wordpress/wp-config.php sudo cp -a /tmp/wordpress/. /var/www/vhost/example.com/public_html chown -R www-data.www-data /var/www/vhost/example.com/public_html |
DONE
Source
.