Ubuntu Yii2 web server with Nginx+Apache Jun 26, 2017

Yii2 Ubuntu

Nginx and Apache are two popular PHP web servers. Running both of them with Nginx in front of apache (Nginx reverse proxy) will improve performance significantly. This tutorial will show you how to configure your Ubuntu server for Yii2 framework environments.

Prerequisites

  • Ubuntu Server 16.04 LTS "xenial"
  • Root account

Step 1 - Update your OS and install basic program

apt-get update
apt-get upgrade
apt-get install unzip
add-apt-repository -y ppa:ondrej/php
apt-add-repository ppa:ondrej/apache2
add-apt-repository ppa:nginx/stable

Step 2 - Install Apache and PHP

apt-get install apache2 libapache2-mod-fastcgi php7.1-fpm

Step 3 - Install Apache modules

Install mod_aclr2

apt-get install apache2-dev gcc
wget http://files.directadmin.com/services/custombuild/mod_aclr2-1.0.0.tar.gz
tar -xzvf mod_aclr2-1.0.0.tar.gz
apxs -c mod_aclr2.c
apxs -i -a -n aclr mod_aclr2.la

Install mod_rpaf

wget https://github.com/gnif/mod_rpaf/archive/stable.zip
unzip stable.zip
cd mod_rpaf-stable
make
make install

Step 4 - Install PHP modules (for Yii2)

apt-get install -y php-intl php-xml php-mysql php-gd php-zip php-mcrypt php-gmp php-imagick
apt-get install -y php-mbstring
apt-get install -y php-mongodb
apt-get install -y libssh2-1 php-ssh2

Step 5 - Config Apache

Create mod_aclr.conf configuration file

nano /etc/apache2/mods-available/aclr.conf

Add the following lines

AccelRedirectSet On
AccelRedirectSize 1k

Create rpaf.load file for loading the module

nano /etc/apache2/mods-available/rpaf.load

Then add the following line

LoadModule rpaf_module /usr/lib/apache2/modules/mod_rpaf.so

Create rpaf.conf configuration file

nano /etc/apache2/mods-available/rpaf.conf

Add the following code block, replace SERVER_IP with your server public/private IP

<IfModule mod_rpaf.c>
RPAF_Enable On
RPAF_Header X-Real-Ip
RPAF_ProxyIPs SERVER_IP
RPAF_SetHostName On
RPAF_SetHTTPS On
RPAF_SetPort On
</IfModule>

Enable Apache's modules

a2enmod aclr
a2enmod rpaf
a2enmod rewrite
a2enmod headers
a2enmod ssl
a2enmod proxy
a2enmod proxy_fcgi
a2enmod actions
a2enmod proxy_fcgi setenvif
a2enconf php7.1-fpm

Step 6 - Changing Apache ports

nano /etc/apache2/ports.conf

Change Listen 80 to Listen 8080 and Listen 443 to Listen 8081

nano /etc/apache2/sites-available/000-default.conf

Change <VirtualHost *:80> to <VirtualHost *:8080>

nano /etc/apache2/sites-available/default-ssl.conf

Change <VirtualHost _default_:443> to <VirtualHost _default_:8081>

Open /etc/apache2/apache2.conf, add the following code block right under <Directory /var/www/> code block

<Directory /home/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>

Finally enable the default ssl site and reload Apache

a2ensite default-ssl
service apache2 reload

Visit http://SERVER_IP:8080 and https://SERVER_IP:8081 to test it.

Step 7 - Install Nginx

apt-get install nginx

Step 8 - Config Nginx

nano /etc/nginx/sites-available/default

Delete all content of the file.

We will redirect all HTTP requets to HTTPS, add the code block below

server { 
listen 80 default_server;
listen [::]:80 default_server;
return 301 https://$host$request_uri;
}

Next, add the code block for HTTPS

server {
listen 443 default_server http2;
listen [::]:443 default_server http2;

ssl on;
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

root /var/www/html;
index index.php index.html index.htm index.nginx-debian.html;
server_name _;

location / {
proxy_pass https://{IP}:8081;
proxy_buffering off;
proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Accel-Internal /nginx_static_files;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
}

location /nginx_static_files/ {
alias /var/www/html/;
internal;
}

location ~ /(\.ht|\.user\.ini) {
deny all;
}
}

Remove nginx version in the response header field.

nano /etc/nginx/nginx.conf

Uncomment server_tokens off;

Reload everything

service nginx reload
service apache2 reload
service php7.0-fpm reload

Visit http://SERVER_IP and https://SERVER_IP to test it, then you can block ports 8080 and 8081 using firewall.

Restore original visitor IP from Cloudflare: create new file in /etc/nginx/conf.d/cloudflare.conf with the following lines

set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 199.27.128.0/21;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2c0f:f248::/32;
set_real_ip_from 2a06:98c0::/29;

# use any of the following two
real_ip_header CF-Connecting-IP;
#real_ip_header X-Forwarded-For;

Step 9 - Install database

We use MariaDB instead of MySQL

apt-get install software-properties-common
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://ftp.yz.yamagata-u.ac.jp/pub/dbms/mariadb/repo/10.2/ubuntu xenial main'
apt update
apt install mariadb-server

Step 10 - Secure web server with Let's Encrypt

Install Certbot

add-apt-repository ppa:certbot/certbot
apt-get update
apt-get install certbot

Add new configuration file 

nano /etc/apache2/conf-available/letsencrypt.conf

Add the following line

Alias /.well-known /var/www/html/.well-known

Enable it and reload apache

a2enconf letsencrypt
service apache2 reload

Install certificate for server's hostname, note that replace {HOSTNAME} with your server hostname

certbot certonly --webroot --webroot-path=/var/www/html -d {HOSTNAME}

Update Apache default SSL site

nano /etc/apache2/sites-available/default-ssl.conf

Comment out SSLCertificateFile and SSLCertificateKeyFile, then add this below SSLEngine on

SSLCertificateFile /etc/letsencrypt/live/{HOSTNAME}/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/{HOSTNAME}/privkey.pem
SSLCACertificateFile /etc/letsencrypt/live/{HOSTNAME}/chain.pem

Next update Nginx default site

Nano /etc/nginx/sites-available/default

Comment out ssl_certificate and ssl_certificate_key, then add this below ssl on;

ssl_certificate /etc/letsencrypt/live/{HOSTNAME}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{HOSTNAME}/privkey.pem;

Generate Strong Diffie-Hellman Group

openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Add new configuration snippet

nano /etc/nginx/snippets/ssl-params.conf

Add this content

ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001] valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

Update Nginx conf file

nano /etc/nginx/nginx.conf

Comment out ssl_protocols and ssl_prefer_server_ciphers, then add this line right after that

include /etc/nginx/snippets/ssl-params.conf;

Reload services

systemctl reload {nginx,apache2}

Set Up Auto Renewal

crontab -e

Add this line at the end

15 3 * * * /usr/bin/certbot renew --quiet --renew-hook "/bin/systemctl reload {nginx,apache2}"

Step 11: Enable firewall

ufw default deny incoming
ufw default allow outgoing

ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp

sudo ufw disable
sudo ufw enable

That's it!

(Part 2 coming soon)

Advertisement

Latest Updates