Header Ads

How to Install PHP 7.0 (LEMP Stack) on Debian 8 VPS

Please find the updated working guide for LEMP stack here : https://dev.slickalpha.blog/2019/11/installing-lemp-stack-on-debian-buster.html
This guide should be used by system administrators for reference. If you are new to Linux or want to your server setup with nginx and php 7.0, click 'contact us' on the taskbar.

Before you continue make sure you have a server instance ready to test installation. Try VULTR for cheap and reliable VPS servers.

This guide includes all commands and codes that can be executed on a Linux terminal to install a LEMP stack on Debian 8, along with phpmyadmin, free ssl certificates, ssh key setup, etc,...

Basic Linux Commands

Print Working Directory


Change Directory (to root)
cd /

List Current Directory

ls -ahl

-a : all the files
-h : human readable
-l : long list

Change Directory (to var)

cd var

Change Directory (to previous)

cd ..

Text Editior (nano)

Prefix a file path or file name with 'nano' and execute command

To save file, press ctrl+y and press enter

Temporarily elevate to root privileges

Prefix a command with 'sudo' and execute command

Prerequisites to install LEMP stack on Debian 8

1. Have deployed Debian 8 image on your new server and have your root password ready

2. Have pointed your domain (example.com) to your server public ip address

3. Have booted your server and is running

4. This guide is for windows users. Install putty for terminal.

Tips & Instructions

1. To copy from here, use ctrl-c, and to paste it on putty, mouse-right-click once on putty

2. Replace all place holders such as 'example.com', 'example_user', 'nothingtosee' and so on with desired strings.

Steps to install LEMP stack on Debian 8

Set preference to ipv4

nano /etc/gai.conf

uncomment "precedence ::ffff:0:0/96 100"

Update & Upgrade Linux

apt-get update

apt-get upgrade

Install sudo (if doesn't exist)

apt-get install sudo

Check if Host File exists

nano /etc/hosts

Set Hostname (replace xhostname)

hostnamectl set-hostname xhostname

Update /etc/hosts (replace example.com with domain)

nano /etc/hosts localhost.localdomain localhost xhostname.example.com xhostname
2600:3c01::a123:b456:c789:d012 xhostname.example.com xhostname

Check Hostname

nano /etc/init.d/hostname.sh


hostname -f

Set Localtime

dpkg-reconfigure tzdata

Install Nginx

sudo apt-get update

sudo apt-get install nginx

Install MySQL DB Server (& set root pass)

sudo apt-get install mysql-server

Secure MySQL DB Server (set Y except root pass)

sudo mysql_secure_installation

Install PHP with FastCGI

$ sudo -s
echo 'deb http://packages.dotdeb.org jessie all' >> /etc/apt/sources.list
echo 'deb-src http://packages.dotdeb.org jessie all' >> /etc/apt/sources.list
cat /etc/apt/sources.list
sudo apt-get update
sudo apt-get install php7.0-cli php7.0-cgi php7.0-fpm php7.0-mysql php7.0-json php7.0-curl
sudo apt-get update

Fix gpg key errors (if any) (replace 010908312D230C5F with the key shown in error)

gpg --keyserver pgpkeys.mit.edu --recv-key 010908312D230C5F

gpg -a --export 010908312D230C5F | apt-key add -

Securing PHP (Edit php.ini, and uncomment and set fix_pathinfo to 0)

sudo nano /etc/php/7.0/fpm/php.ini


sudo systemctl restart php7.0-fpm

Configure Nginx for PHP

sudo nano /etc/nginx/sites-available/default

Uncomment and edit the highlighted part

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

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

server_name your_server_ip;

location / {
try_files $uri $uri/ =404;

location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;

location ~ /\.ht {
deny all;

Check for errors & reload nginx

sudo nginx -t

sudo systemctl reload nginx

File System Access

For adding limited access to example_user to sftp (through filezilla or other ftp clients), two things must be done.
1. Grant/Restrict File level permission (read/write/execute)
2. Secure SSH and SFTP Access (through sshd_config)

Add Limited User Account (replace example_user and enter password for user)

adduser example_user

Create a new group (replace example_group)

addgroup --system example_group

Append the sudo file to grant sudo for limited user (optional)

sudo visudo

# User privilege specification
example_user ALL=(ALL:ALL) ALL

Create new site (replace example.com)

sudo mkdir -p /var/www/example.com/site

Mod limited_user to the group with root directory

usermod -g example_group -d /var/www/example.com/site -s /sbin/nologin example_user

Restrict and give limited user r(4)/w(2)/x(1) permission

sudo chown root:root /var/www/example.com/
sudo chmod -R 755 /var/www/example.com/
sudo chmod -R 775 /var/www/example.com/site

Edit sshd_config

sudo nano /etc/ssh/sshd_config

Comment out following line in sshd_config

#Subsystem sftp /usr/libexec/openssh/sftp-server

Add following lines to sshd_config (replace example.com & example_group)

Subsystem sftp internal-sftp

Match Group example_group
ChrootDirectory /var/www/example.com/site
X11Forwarding no
AllowTcpForwarding no

ForceCommand internal-sftp

Restart ssh to confirm changes

sudo service ssh restart

Create test html page with some sample code for site

nano /var/www/example.com/site/index.html

Create Server Block files for Site (Replace example.com)

sudo apt-get update

sudo nano /etc/nginx/sites-available/example.com

Replace block contents with following and save file. (Replace example.com)

server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/site; index index.php index.html;
location / {
try_files $uri $uri/ =404;
location ~ \.php$ { include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
location ~ /\.ht {
deny all;

Enable the site

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled

Edit nginx.conf and uncomment "server_names_hash_bucket_size 64;"

sudo nano /etc/nginx/nginx.conf

Check for errors

sudo nginx -t

Restart Nginx

sudo systemctl restart nginx

Open the domain on your browser to see our test page

Logoff Limited user and login as root

Install Cron for automated updates

sudo apt-get update
sudo apt-get install cron

Restrict all user access. Allow access for example_user (if necessary)

echo ALL /etc/cron.deny
echo example_user /etc/cron.allow

Install UFW for Firewall

sudo apt-get install ufw

Set 'IPV6=yes' if using ipv6

sudo nano /etc/default/ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing

Allow tcp 22 or 2222 for ssh access

sudo ufw allow 22/tcp
sudo ufw allow www
sudo ufw allow ftp

To update disable and enable (enable turn it on, make sure ssh is enabled)

sudo ufw disable
sudo ufw enable
sudo ufw status verbose

Add the backports repository to server

echo 'deb http://ftp.debian.org/debian jessie-backports main' | sudo tee /etc/apt/sources.list.d/backports.list

Install Certbot to obtain Letsencrypt ssl

sudo apt-get update
sudo apt-get install certbot -t jessie-backports

Edit Nginx for Webroot usage (for the ssl desired site)

sudo nano /etc/nginx/sites-available/example.com

Add following location block & take note of the root mentioned in the file

location ~ /.well-known {
allow all;

sudo nginx -t

sudo systemctl restart nginx

User webroot to request a certificate

sudo certbot certonly -a webroot --webroot-path=/var/www/example.com/site -d example.com -d www.example.com

Enter email & accept terms. Note down the path, similar to '/etc/letsencrypt/live/example.com/'

Check for four files having placed in /etc/letsencrypt/archive with symbolic links in /etc/letsencrypt/live/example.com

· cert.pem: Your domain's certificate
· chain.pem: The Let's Encrypt chain certificate
· fullchain.pem: cert.pem and chain.pem combined
· privkey.pem: Your certificate's private key

sudo ls -l /etc/letsencrypt/live/example.com

To increase security, generate DH bit group

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

Create config snippet to point SSL key and cert

sudo nano /etc/nginx/snippets/ssl-example.com.conf

Add the following lines and save the file
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

sudo apt-get update

Create config snippet with strong encryption settings

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

Copy paste the following text. Risky if error occurs!!!

# from https://cipherli.st/

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver valid=300s;
resolver_timeout 5s;
# Preloading HSTS is disabled. Uncomment to includes the
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

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

Take copy of config

sudo cp /etc/nginx/sites-available/example.com /etc/nginx/sites-available/example.com.bak

Edit the config into two seperate blocks for 80 and ssl-443

sudo nano /etc/nginx/sites-available/example.com

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

server {

# SSL configuration

listen 443 ssl;
listen [::]:443 ssl;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;

. . .

Adjust UFW for ssl

sudo ufw allow https

Delete http if necessary (http pages now will not load)

sudo ufw delete allow www

Check status of ufw

sudo ufw status verbose

Edit default config to return 404

sudo nano /etc/nginx/sites-available/default

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

server_name _;

return 404;

location ~ /\.ht {
deny all;

Check Nginx for errors & restart

sudo nginx -t

sudo systemctl restart nginx

Check ssl-rating for A+

In your browser:


Edit crontab to automate renewal and add the following

sudo crontab -e

30 2 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log
35 2 * * 1 /bin/systemctl reload nginx

Login in to MySQL

mysql -u root -p

Create Database with a new user with permissions

CREATE USER 'webuser' IDENTIFIED BY 'password';

Restart PHP to conclude

sudo systemctl restart php7.0-fpm

To install phpmyadmin

Get the latest pure binary file (.tar.gz) from https://www.phpmyadmin.net/downloads/

wget https://files.phpmyadmin.net/phpMyAdmin/4.7.0/phpMyAdmin-4.7.0-all-languages.tar.gz

tar xvf phpMyAdmin-4.7.0-all-languages.tar.gz

Move and rename the directory (replace 'nothingtosee')

mv phpMyAdmin-4.7.0-all-languages /usr/share/

mv -T /usr/share/phpMyAdmin-4.7.0-all-languages /usr/share/nothingtosee

ls -al /usr/share/

Install dependencies & setup config

sudo apt-get install php7.0-mcrypt php-mbstring php7.0-mbstring php-gettext

sudo phpenmod mcrypt

sudo phpenmod mbstring

sudo cp /usr/share/nothingtosee/config.sample.inc.php /usr/share/nothingtosee/config.inc.php

nano /usr/share/nothingtosee/config.inc.php

Set blowfish secret

locate "$cfg['blowfish_secret'] = '';" and enter a string;

Setup encrypted password to open phymyadmin aka 'nothingtosee'

openssl passwd

Copy the resulting encrypted pass. And remember the original pass which will be used for authentication

Create a file to store the username and password for phpmyadmin

sudo nano /etc/nginx/pma_pass

Replace 'sample_user' with username & 'password' with the encrypted one copied from previous step


Create Symbolic link to phpmyadmin (replace 'nothingtosee' & 'example.com')

sudo ln -s /usr/share/nothingtosee /var/www/example.com/site

Add the phpmyadmin within the working server { } block of the /example.com config (replace 'nothingtosee' & 'example.com')

sudo nano /etc/nginx/sites-available/example.com

location ^~ /nothingtosee/ {
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/pma_pass;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
location ~* ^/nothingtosee/(.+\.(jpg|jpeg|gif|css|png|js|ico|html|xml|t$
root /usr/share/;
#deny all;

Restart Nginx and open the link on your browser and authenticate

sudo service nginx restart


Turn off apache2 and reload nginx (optional)

sudo service apache2 stop && sudo service nginx reload

Adding Public Key Auth for SSH (for each user)

Install and open putty-keygen.exe

Set bits to 4096 and option as SSH-2 RSA and generate

Enter passphrase, save public key, save private key, keep window open

Open putty application, add private key to 'putty connection > ssh > auth', save the session and open session with the desired user (limited/root) and enter password

Create new directory for auth key

mkdir ~/.ssh; touch ~/.ssh/authorized_keys; chmod 700 ~/.ssh

Edit the file and copy public key directly from keygen and paste (ctrl -v)

nano ~/.ssh/authorized_keys

Increase security

chmod 600 ~/.ssh/authorized_keys

Exit and rerun putty, load saved session of desired user.

Make sure private key matches the saved public key for that user.

Enter passphrase to login

Optional Items

To Delete Limited User Account (Optional)

sudo deluser --remove-home username

To Delete any folders (created by mistake)

sudo rm -r -f /path/

Do a update after every action

sudo apt-get update

Restart PHP & Nginx & Update

sudo systemctl restart php7.0-fpm nginx

sudo apt-get update

To change mysql root pass (login to mysql first)

mysql -u root -p

ALTER USER 'root'@'localhost' IDENTIFIED WITH 'mysql_native_password' BY 'password';

To check Nginx status and error log

sudo systemctl status nginx.service

sudo tail -n 20 /var/log/nginx/error.log