Skip to content

lucien144/lemp-stack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Basic installation process of LEMP

Last update: 04/09/2020, tested on Ubuntu 20.04 with PHP7.4

If you are looking for the older versions of the PHP, 👀 at branches php7.2 or php7.1


🔥 Looking for cool t-shirts for web developers?
Check out my Devnull Clothing.


Overview

This document is a list of notes when installing several Ubuntu LEMP instances w/ PHP7.4. With some sort of imagination it can be considered as a step-by-step tutorial of really basic installation process of LEMP. I wrote it mainly for myself, but feel free to use it. The LEMP consists of:

  • Nginx
  • PHP7.4 (php-fpm)
  • MariaDB
  • Optional: git, munin, rabbitmq, supervisor, node.js, Let's Encrypt, postfix

Table of Contents

Essentials

Installation script

To automatically install essentials, you can use the 👉 startup.sh script by downloading it and calling it with sudo sudo ./startup.sh. The file is deleted automatically.

Manual installation

If you want to have the installation in your hands, follow the manual installation. 👇

add new user

adduser admin

allow su without password for this user

echo "admin    ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

try new user

su - admin
exit

add authorized keys for that user

su - admin
mkdir .ssh
nano .ssh/authorized_keys
chmod 700 .ssh/
chmod 600 .ssh/authorized_keys

disable password login for all users

# Optional
echo "PasswordAuthentication no" | sudo tee --append /etc/ssh/sshd_config
sudo systemctl reload sshd

Or disable the password for some users only (admin, user_tld)

# Optional
sudo nano /etc/ssh/sshd_config
> Match User admin,user_tld
>    PasswordAuthentication no
sudo systemctl reload sshd

Fix locale if you are getting "WARNING! Your environment specifies an invalid locale."

sudo echo 'LC_ALL="en_US.UTF-8"' >> /etc/environment
# Log out & in

Set the correct timezone

sudo dpkg-reconfigure tzdata

Configure & Update APT

sudo apt-get -y dist-upgrade ; sudo apt-get -y update ; sudo apt-get -y upgrade
sudo apt-get -y install unattended-upgrades software-properties-common apache2-utils fail2ban

Install security updates automatically

sudo dpkg-reconfigure -plow unattended-upgrades

Install essentials

sudo apt-get -y install mc htop

Replace rm with trash

This is optional but recommended. rm is a dangerous command therefore is recommended to replace it by safer version trash that instead of removing files moving them to a trash. More info here.

$ sudo apt-get -y install trash-cli
$ echo "alias rm='echo \"This is not the command you are looking for. Use <trash> instead.\"; false'" | sudo tee --append

Setup and configure Firewall

Open SSH port only.

sudo ufw allow 22 #OpenSSH
sudo ufw allow 80 #http
sudo ufw allow 443 #https
yes | sudo ufw enable
sudo ufw status

Webserver installation

You can skip steps 1-4 by downloading and running the lemp.sh script:

wget https://raw.githubusercontent.com/lucien144/lemp-stack/master/lemp.sh && chmod u+x lemp.sh
sudo ./lemp.sh

1. Install Nginx

sudo add-apt-repository -y ppa:nginx/development && sudo apt-get update
sudo apt-get -y install nginx

2. Install MariaDB

sudo apt-get -y install mariadb-server # Or MySQL: sudo apt-get install mysql-server
sudo service mysql stop # Stop the MySQL if is running.
sudo mysql_install_db
sudo service mysql start
sudo mysql_secure_installation

3. Install PHP7.4

sudo add-apt-repository -y ppa:ondrej/php && sudo apt-get update
sudo apt-get -y install php7.4

4. Choose and install PHP7.4 modules

sudo apt-cache search php7.4-*
sudo apt-get -y install php7.4-fpm php7.4-curl php7.4-gd php7.4-json php7.4-mysql php7.4-sqlite3 php7.4-pgsql php7.4-bz2 php7.4-mbstring php7.4-soap php7.4-xml php7.4-zip

5. Check the installed PHP version

php -v

6. Configure Nginx

Configure /etc/nginx/nginx.conf

worker_processes auto;
events {
        use epoll;
        worker_connections 1024; # ~ RAM / 2
        multi_accept on;
}

Default vhost

cd /etc/nginx/sites-available
sudo rm default
sudo wget https://raw.githubusercontent.com/lucien144/lemp-stack/master/nginx/sites-available/default
cd /etc/nginx/conf.d
sudo wget https://raw.githubusercontent.com/lucien144/lemp-stack/master/nginx/conf.d/gzip.conf

Setup default settings for all virtual hosts

sudo mkdir -p /etc/nginx/conf.d/server/
cd /etc/nginx/conf.d/server/
sudo wget https://raw.githubusercontent.com/lucien144/lemp-stack/master/nginx/conf.d/server/1-common.conf

Reload Nginx

sudo nginx -t && sudo nginx -s reload

Add new website, configuring PHP & Nginx & MariaDB

Steps 1. - 9. can be skipped by calling the add-vhost.sh. Just download add-vhost.sh, chmod u+x ./add-vhost.sh and call it sudo ./add-vhost.sh. The file is deleted automatically.

$ cd ~ && wget https://raw.githubusercontent.com/lucien144/lemp-stack/master/add-vhost.sh && chmod u+x add-vhost.sh
$ sudo ./add-vhost.sh

1. Create the dir structure for new website

sudo mkdir -p /var/www/vhosts/new-website.tld/{web,logs,ssl}

2. User groups and roles

$ sudo groupadd new-website
$ sudo useradd -g new-website -d /var/www/vhosts/new-website.tld new-website
$ sudo passwd new-website
$ sudo usermod -s /bin/bash new-website

You can switch users by using sudo su - new-website

3. Update permissions

sudo chown -R new-website:new-website /var/www/vhosts/new-website.tld
sudo chmod -R 0775 /var/www/vhosts/new-website.tld

4. Create new PHP-FPM pool for new site

sudo nano /etc/php/7.4/fpm/pool.d/new-website.tld.conf

5. Configure the new pool

[new-website]
user = new-website
group = new-website
listen = /run/php/php7.4-fpm-new-website.sock
listen.owner = www-data
listen.group = www-data
php_admin_value[disable_functions] = exec,passthru,shell_exec,system
php_admin_flag[allow_url_fopen] = off
pm = dynamic
pm.max_children = 5 # The hard-limit total number of processes allowed
pm.start_servers = 2 # When nginx starts, have this many processes waiting for requests
pm.min_spare_servers = 1 # Number spare processes nginx will create
pm.max_spare_servers = 3 # Number spare processes attempted to create
pm.max_requests = 500
chdir = /
5.1 Configuring pm.max_children
  1. Find how much RAM FPM consumes: ps -A -o pid,rss,command | grep php-fpm -> second row in bytes
    1. Reference: https://overloaded.io/finding-process-memory-usage-linux
  2. Eg. ~43904 / 1024 -> ~43MB per one process
  3. Calculation: If server has 2GB RAM, let's say PHP can consume 1GB (with some buffer, otherwise we can use 1.5GB): 1024MB / 43MB -> ~30MB -> pm.max_childern = 30
5.2 Configuring pm.start_servers, pm.min_spare_servers, pm.max_spare_servers
  1. pm.start_servers == number of CPUs
  2. pm.min_spare_servers = pm.start_servers / 2
  3. pm.max_spare_servers = pm.start_servers * 3

6. Restart PHP fpm and check it's running

sudo service php7.4-fpm restart
ps aux | grep new-site

7. Create new "vhost" for Nginx

sudo nano /etc/nginx/sites-available/new-site.tld

8. Configure the vhost

server {
    listen 80;

    root /var/www/vhosts/new-site.tld/web;
    index index.php index.html index.htm;

    server_name www.new-site.tld new-site.tld;

    include /etc/nginx/conf.d/server/1-common.conf;

    access_log /var/www/vhosts/new-site.tld/logs/access.log;
    error_log /var/www/vhosts/new-site.tld/logs/error.log warn;

    location ~ \.php$ {
        try_files $uri $uri/ /index.php?$args;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.4-fpm-new-site.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

9. Enable the new vhost

cd /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/new-site.tld new-site.tld
sudo nginx -t && sudo nginx -s reload

10. MariaDB (MySQL)

sudo mysql
> CREATE DATABASE newwebsite_tld;
> CREATE USER 'newwebsite_tld'@'localhost' IDENTIFIED BY 'password';
> GRANT ALL PRIVILEGES ON newwebsite_tld.* TO 'newwebsite_tld'@'localhost';
> FLUSH PRIVILEGES;

Others

Git Aware Prompt

If you want to have nice git-aware prompt with some handy aliases, use this:

sudo su virtualhostuser
cd ~
wget https://gist.githubusercontent.com/lucien144/56fbb184b1ec01fae1adf2e7abb626b6/raw/0928548acb2ff1618054069f0ae7e60f92d76cc3/install.sh && cat install.sh | bash
bash

More information about aliases and other in this gist.

Git

sudo apt-get install git

Adminer

Adminer is a mostly MySQL database management tool. It's really tiny, simple & easy to use.

cd /etc/nginx/conf.d/server/
sudo wget https://raw.githubusercontent.com/lucien144/lemp-stack/master/nginx/conf.d/server/4-adminer.conf
sudo mkdir -p /var/www/html/adminer/
cd /var/www/html/adminer/
sudo wget https://www.adminer.org/latest.php -O index.php
sudo chmod a+x index.php
sudo htpasswd -c .htpasswd user
sudo nginx -t && sudo nginx -s reload

Adminer is now ready at http://{server.ip}/adminer/

Also, don't forget to change the username 👆.

Postfix (sending emails from PHP)

In case you cannot send emails from PHP and getting error (tail /var/log/mail.log) Network is unreachable, you need to switch Postfix from IPv6 to IPv6.

sudo apt-get install postfix
sudo nano /etc/postfix/main.cf

Now change the line inet_protocols = all to inet_protocols = ipv4 and restart postfix by sudo /etc/init.d/postfix restart.

You can also check if you have opened port 25 by netstat -nutlap | grep 25

Munin

1. Install

apt-get install munin-node munin

2. Configure Munin

  1. Uncomment #host 127.0.0.1 in /etc/munin/munin-node.conf
  2. Append following code to /etc/munin/munin-node.conf
[nginx*]
env.url http://localhost/nginx_status

3. Configure nginx /etc/nginx/sites-available/default

sudo nano /etc/nginx/sites-available/default
# Change listen 80 default_server; to
listen 80

#Change listen [::]:80 default_server; to
listen [::]:80

# Add settings for stub status to server {}
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }

# Add setting to access stats online

    location /stats {
        allow YOUR.IP.ADDRESS;
        deny all;
        alias /var/cache/munin/www/;
    }

4. Install plugins

cd /usr/share/munin/plugins
sudo wget -O nginx_connection_request https://raw.github.com/munin-monitoring/contrib/master/plugins/nginx/nginx_connection_request
sudo wget -O nginx_status https://raw.github.com/munin-monitoring/contrib/master/plugins/nginx/nginx_status
sudo wget -O nginx_memory https://raw.github.com/munin-monitoring/contrib/master/plugins/nginx/nginx_memory

sudo chmod +x nginx_request
sudo chmod +x nginx_status
sudo chmod +x nginx_memory

sudo ln -s /usr/share/munin/plugins/nginx_request /etc/munin/plugins/nginx_request
sudo ln -s /usr/share/munin/plugins/nginx_status /etc/munin/plugins/nginx_status
sudo ln -s /usr/share/munin/plugins/nginx_memory /etc/munin/plugins/nginx_memory

Restart Munin

sudo service munin-node restart

Rabbitmq

Install PHP extension

sudo apt-get install php-amqp

Install RabbitMQ

echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list
wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install rabbitmq-server
sudo service rabbitmq-server status
sudo rabbitmq-plugins enable rabbitmq_management
sudo ufw allow 15672
sudo rabbitmqctl add_user admin *********
sudo rabbitmqctl set_user_tags admin administrator
sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
sudo rabbitmqctl delete_user guest
sudo service rabbitmq-server restart

Installing plugin

  1. Download the .ez plugin to /usr/lib/rabbitmq/lib/rabbitmq_server-{version}/plugins
  2. Enable the plugin by sudo rabbitmq-plugins enable {plugin name}

Supervisor

sudo apt-get install supervisor

Enable the web interface

echo "
[inet_http_server]
port=9001
username=admin
password=*********" | sudo tee --append /etc/supervisor/supervisord.conf

sudo service supervisor reload
sudo ufw allow 9001

The interface should be available on http://{SERVER_IP}:9001/

Node.js & NPM

sudo apt-get install nodejs
sudo apt-get install npm

If you are getting error /usr/bin/env: ‘node’: No such file or directory run

sudo ln -s /usr/bin/nodejs /usr/bin/node

Composer

wget https://raw.githubusercontent.com/composer/getcomposer.org/76a7060ccb93902cd7576b67264ad91c8a2700e2/web/installer -O - -q | php -- --quiet
sudo mv composer.phar /usr/local/bin/composer

Reference: https://getcomposer.org/doc/faqs/how-to-install-composer-programmatically.md

Todo

Reference

Setting PHP-FPM

License

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.