Register Login

Install Nginx, PHP-FPM, Mysql, PhpMyadmin on EC2 with Amazon Linux AMI

Updated Sep 12, 2019

In this tutorial we are assuming that you have already launched a new instance using the Amazon Linux AMI with the help of public DNS name which is within the internet range.

In order to allow SSH (port 22), HTTP (port 80), and HTTPS (port 443) connections you must configured your security group.

1. Update

Perform a quick software update on your instance to keep all the software packages up to date.

sudo yum -y update
sudo yum install -y gcc make

2. Install Nginx & PHP 7.2

sudo yum install nginx php72-fpm -y

3. Install PHP 7.2 extensions

sudo yum install php72-mcrypt php72-xml php72-mcrypt php72-zip php72-xmlrpc php72-gd php72-curl php72-pdo php72-mysqlnd php72-mbstring php72-gmp -y

Install PHP-APC

sudo yum install -y php-pecl-apc
sudo yum install -y pcre-devel

4. Install Mysql 5.7

sudo yum -y install mysql57-server mysql

5. Start Nginx, PHP-FPM, Mysql Services

sudo service mysqld start
sudo service nginx start
sudo service php-fpm start

6. Add NGINX, PHP-FPM and Mysql service start to boot sequence

sudo chkconfig nginx on
sudo chkconfig php-fpm on
sudo chkconfig mysqld on

7. Test your web server

http://yourpublicip/

Your Default directory location: /usr/share/nginx/html

nginx configuration file location: /etc/nginx/nginx.conf.

Install Nginx, PHP-FPM, Mysql, PhpMyadmin on EC2 with Amazon Linux AMI

8. To set file permissions

Add your user (in this case, ec2-user) to the nginx group using following command.

sudo usermod -a -G nginx ec2-user

9. Now log out then log in back to fetch the new group and then verify your membership.

exit

groups

Output:

ec2-user wheel nginx

10. Change the group ownership of /usr/share/nginx and its content to the nginx group.

sudo chown -R ec2-user:nginx /usr/share/nginx

11. To add group write permissions and to set the group ID on future subdirectories, change the directory permissions of /usr/share/nginx and its subdirectories.

sudo chmod 2775 /usr/share/nginx

find /usr/share/nginx -type d -exec sudo chmod 2775 {} \;

12. To add group write permissions, recursively change the file permissions of /usr/share/nginx and its subdirectories:

find /usr/share/nginx -type f -exec sudo chmod 0664 {} \;

13. To test your lamp server

Create a PHP file in the Nginx document root.

echo "<?php phpinfo(); ?>" > /usr/share/nginx/html/phpinfo.php

In the web browser, type the url of the newly created file.

http://serverpublicIP/phpinfo.php

Install Nginx, PHP-FPM, Mysql, PhpMyadmin on EC2 with Amazon Linux AMI

Now delete the phpinfo.php file. Though this is a very useful information for security reasons which can be exploits trough internet.

rm /usr/share/nginx/html/phpinfo.php

Secure the Database Server

The process to set a root password and remove the insecure features from your installation can be done by using mysql_secure_installation command.

sudo mysql_secure_installation

a. Prompt for root password by default root account does not have password. Press Enter
b. Type Y to set a passwordType Y to remove the anonymous user accounts.
c. Type Y to disable the remote root login.
d. Type Y to remove the test database.
e. Type Y to reload the privilege tables and save your changes.

Install phpMyAdmin

1. Install the required dependencies.

sudo yum install php72-mbstring.x86_64 php72-zip.x86_64 -y

2. Restart Nginx & PHP-fpm

sudo service nginx restart
sudo service php-fpm restart

3. Navigate to the Apache document root at /usr/share/nginx/html

cd /usr/share/nginx/html

4. Select a source package for the latest phpMyAdmin release

wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz

5. Create a phpMyAdmin folder and extract the package into it using the following command.

mkdir phpMyAdmin && tar -xvzf phpMyAdmin-latest-all-languages.tar.gz -C phpMyAdmin --strip-components 1

6. Delete the phpMyAdmin-latest-all-languages.tar.gz

rm phpMyAdmin-latest-all-languages.tar.gz

7. If the MySQL server is not running, start it now.

sudo service mysqld start

8. Open phpMyAdmin

http://serverpublicIP/phpMyAdmin/

Install Nginx, PHP-FPM, Mysql, PhpMyadmin on EC2 with Amazon Linux AMI

Log in to your phpMyAdmin installation with the root user name and the MySQL root password which you have created earlier.

PHP-FPM Configuration

sudo nano /etc/php-fpm-7.2.d/www.conf

Change the given below parameters

user = nginx
group = nginx

listen.owner = nginx
listen.group = nginx

;listen.acl_users = apache,nginx

emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s

Restart php-fpm

sudo service php-fpm restart

Nginx Configuration

Steps to optimize the performance of your NGINX server

sudo nano /etc/nginx/nginx.conf

1.Update Work Process

To update work process check the CPU running on the server and update the value of work_process

Sudo grep ^processor /proc/cpuinfo | wc -l

worker_processes = 1

2.Update worker_connections

Run command
ulimit -n
1024

events {
worker_connections 10240;
multi_accept on;
use epoll;
}

3.Update Buffer Parameter

client_body_buffer_size: This manages the client buffer size which mean you can sent any POST actions to Nginx.

client_header_buffer_size: this directive manages the client header size, usually 1k is a decent size for this directives.

client_max_body_size: this directive allow the maximum size for a client request. In case of maximum size exceeding Nginx will throw 413 error or Request Entity Too Large.

large_client_header_buffers: this directive manages the maximum number and size of buffers for large client headers.

client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 8m;
large_client_header_buffers 2 1k;

4.Update Timeouts

The directives which are responsible for the time is client_body_timeout and client_header_timeout directives. When we sent a request to the server, server waits for a client body or client header to respond. Server will throw Request time out or 408 error if neither a body nor header is sent.

As we all know that Nginx close the connection with the client after some period of time so you must assign the keepalive_timeout to keep alive the timeouts connections with the client.

Finally establish the send_timeout between the two operations of reading, if after this time client will take nothing, then Nginx is shutting down the connection.

client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 15;

Gzip Compression

As we all know that Nginx deals with large amount of network transfer, which can be reduce with the help of Gzip. But be careful while increasing the gzip_comp_level, if its high then the server will begin to waste the cpu cycles.

gzip on;
gzip_static on;
gzip_disable "msie6";
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 8;
gzip_buffers 16 8k;
gzip_proxied any;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
gzip_disable "MSIE [1-6]\.";

## open fd caching
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors off;
## open fd caching

Logging

Every request that hits the VPS to a log file is known as Nginx logs. You need to turn off this functionality if you are using analytics to monitor Nginx logs by simply edit the access_log directive:

access_log off;

Static File Caching

We can definitely to set expire headers for file because that don’t change and served on regular basis.

You can add these directives to the actual Nginx server block.

location ~* \.html$ {
expires 7d;
}

location ~* \.(ogg|ogv|svg|svgz|eot|otf||woff|mp4|mp3|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|exe|ppt|tar|mid|midi|wav|bmp|rtf)(\?ver=[0-9.]+)?$ {
access_log off;
log_not_found off;
expires max;
}

Our Final Nginx configuration file will look like this (/etc/nginx/nginx.conf)

# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
worker_connections 1024;
multi_accept on;
use epoll;
}

http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

# access_log /var/log/nginx/access.log main;
access_log off;

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;

client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 8m;
large_client_header_buffers 2 1k;
client_body_timeout 12;
client_header_timeout 12;
send_timeout 15;

include /etc/nginx/mime.types;

gzip on;
gzip_static on;
gzip_disable "msie6";
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 8;
gzip_buffers 16 8k;
gzip_proxied any;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
gzip_disable "MSIE [1-6]\.";

## open fd caching
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors off;
## open fd caching

default_type application/octet-stream;

# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;

index index.html index.htm;

server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost;
root /usr/share/nginx/html;

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

location / {
}

# redirect server error pages to the static page /40x.html
#
error_page 404 /404.html;
location = /40x.html {
}

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

}

Restart nginx

sudo service nginx restart

Configure Virtual Server

To create a virtual server create a configure file in “/etc/nginx/conf.d” folder

cd /etc/nginx/conf.d

sudo vi yourdomain.com.conf

Copy and paste the given below code

Please change yourdomain.com to your live domain name

server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
root /usr/share/nginx/mydomain/html;

index index.php index.html index.htm;

location ~ \.(php|phar)(/.*)?$ {
fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;

fastcgi_intercept_errors on;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/mydomain/html$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass php-fpm;
}


location / {
try_files $uri $uri/ /index.php;
}

error_page 404 /404.html;
location = /40x.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

Restart Nginx Server

sudo service nginx restart

Generate Wildcard SSL certificate using Let’s Encrypt/Certbot

Wild card SSL Certificate is for all the possible sub-domain.

*.yourdomain.com
Xyz.yourdomain.com
Abc.yourdomain.com

1. Install Git

sudo yum -y install git bc

2. We will install certbot in /opt folder

cd /opt

Clone of Letsencrypt/Certbot repository from Github

sudo git clone https://github.com/certbot/certbot.git

this will create a clone of Letsencrypt/Certbot under /opt/certbot folder

Stop Nginx

sudo service nginx stop

3. Now run given below command from certbot folder

cd certbot
./letsencrypt-auto certonly --manual --preferred-challenges=dns --email abc@abc.com --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d *.yourdomain.in --debug

--debug Option will help in installing required dependency for certbot and letsencrypt

4. Certbot will ask to add DNS TXT record

------------------------------------------------------------------
Please deploy a DNS TXT record under the name
_acme-challenge.yourdomain.com with the following value:

5GFgEqWd7AQrvHteRtfT5V-XXXXXXXXXXXXXX

Before continuing, verify the record is deployed.
------------------------------------------------------------------
Press Enter to Continue

Add the given TXT record in DNS of your domain.

5. Check your TXT record

Open mxtoolbox url

https://mxtoolbox.com/SuperTool.aspx

Enter “_acme-challenge.yourdomain.com” in TXT Lookup box and press enter.

If it resolve to “5GFgEqWd7AQrvHteRtfT5V-XXXXXXXXXXXXXX” its mean that your TXT record entered is correct.

6. After adding this DNS TXT record to your domain press enter and continue.

7. Your Certificate is ready

Congratulations! Your certificate and chain have been saved at:

/etc/letsencrypt/live/yourdomain.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/yourdomain.com/privkey.pem
Your cert will expire on 2019-12-06. To obtain a new or tweaked
version of this certificate in the future, simply run
letsencrypt-auto again. To non-interactively renew *all* of your
certificates, run "letsencrypt-auto renew"
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

8. Create dhparam.pem file

cd /etc/nginx/conf.d/

openssl dhparam -out dhparams.pem 2048

Above command will create dhparams.pem under /etc/nginx/conf.d/ folder

9. Add SSL Certificate on nginx configuration file

sudo vi /etc/nginx/conf.d/yourdomain.com.conf

And now we are running our domain on SSL we need to change our yourdomain.com.conf file, our new config file might look like this:

server {
listen 80 default_server;
listen [::]:80 default_server;
server_name yourdomain.com www.yourdomain.com;
return 301 https://www.yourdomain.com$request_uri;
}

server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name yourdomain.com www.yourdomain.com;
root /usr/share/nginx/yourdomain.com/html;

add_header Strict-Transport-Security "max-age=31536000";
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_dhparam /etc/nginx/conf.d/dhparams.pem;

# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# # It is *strongly* recommended to generate unique DH parameters
# # Generate them with: openssl dhparam -out /etc/pki/nginx/dhparams.pem 2048
# #ssl_dhparam "/etc/pki/nginx/dhparams.pem";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP;
ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
index index.php index.html index.htm;

location ~ \.(php|phar)(/.*)?$ {
fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;

fastcgi_intercept_errors on;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/mydomain/html$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass php-fpm;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT /usr/share/nginx/html;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param HTTPS $https;
fastcgi_param REDIRECT_STATUS 200;
fastcgi_buffer_size 128k;
fastcgi_buffers 256 16k; # 4096k total
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
}
gzip on;
gzip_static on;
gzip_disable "msie6";
gzip_vary on;
gzip_min_length 1;
gzip_comp_level 8;
gzip_buffers 16 8k;
gzip_proxied any;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
gzip_disable "MSIE [1-6]\.";

#
location / {
try_files $uri $uri/ /index.php;
}
#
error_page 404 /404.html;
location = /40x.html {
}
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
location ~* \.html$ {
expires 7d;
}
location ~* \.(ogg|ogv|svg|svgz|eot|otf||woff|mp4|mp3|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|exe|ppt|tar|mid|midi|wav|bmp|rtf)(\?ver=[0-9.]+)?$ {
access_log off;
log_not_found off;
expires max;
}
}

Restart Nginx, PHP-FPM & mySQL

sudo service nginx restart
sudo service php-fpm restart
sudo service mysqld start

Open the website in the browser

https://www.yourdomain.com


×