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.
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
- Basic installation process of LEMP
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.
If you want to have the installation in your hands, follow the manual installation. 👇
adduser admin
echo "admin ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
su - admin
exit
su - admin
mkdir .ssh
nano .ssh/authorized_keys
chmod 700 .ssh/
chmod 600 .ssh/authorized_keys
# 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
sudo echo 'LC_ALL="en_US.UTF-8"' >> /etc/environment
# Log out & in
sudo dpkg-reconfigure tzdata
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
sudo dpkg-reconfigure -plow unattended-upgrades
sudo apt-get -y install mc htop
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
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
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
sudo add-apt-repository -y ppa:nginx/development && sudo apt-get update
sudo apt-get -y install nginx
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
sudo add-apt-repository -y ppa:ondrej/php && sudo apt-get update
sudo apt-get -y install php7.4
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
php -v
worker_processes auto;
events {
use epoll;
worker_connections 1024; # ~ RAM / 2
multi_accept on;
}
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
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
sudo nginx -t && sudo nginx -s reload
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
sudo mkdir -p /var/www/vhosts/new-website.tld/{web,logs,ssl}
$ 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
sudo chown -R new-website:new-website /var/www/vhosts/new-website.tld
sudo chmod -R 0775 /var/www/vhosts/new-website.tld
sudo nano /etc/php/7.4/fpm/pool.d/new-website.tld.conf
[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 = /
- Find how much RAM FPM consumes:
ps -A -o pid,rss,command | grep php-fpm
-> second row in bytes - Eg. ~43904 / 1024 -> ~43MB per one process
- 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
pm.start_servers
== number of CPUspm.min_spare_servers
=pm.start_servers
/ 2pm.max_spare_servers
=pm.start_servers
* 3
sudo service php7.4-fpm restart
ps aux | grep new-site
sudo nano /etc/nginx/sites-available/new-site.tld
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;
}
}
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
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;
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.
sudo apt-get install git
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 👆.
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
apt-get install munin-node munin
- Uncomment
#host 127.0.0.1
in/etc/munin/munin-node.conf
- Append following code to
/etc/munin/munin-node.conf
[nginx*]
env.url http://localhost/nginx_status
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
sudo service munin-node restart
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
- Download the
.ez
plugin to/usr/lib/rabbitmq/lib/rabbitmq_server-{version}/plugins
- Enable the plugin by
sudo rabbitmq-plugins enable {plugin name}
sudo apt-get install supervisor
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/
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
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
- better vhost permissions for reading for other users
- better description of nginx configuration
- script for creating new vhost
- composer
- Let's encrypt (?)
- s3cmd
- automysqlbackup
- SSH/SFTP jail (?)
- TOC created by gh-md-toc
- https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-14-04
- https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-on-ubuntu-14-04
- https://www.digitalocean.com/community/tutorials/how-to-optimize-nginx-configuration
- https://gist.github.com/jsifalda/3331643
- http://serverfault.com/questions/627903/is-the-php-option-cgi-fix-pathinfo-really-dangerous-with-nginx-php-fpm
- https://easyengine.io/tutorials/nginx/tweaking-fastcgi-buffers/
- https://gist.github.com/magnetikonline/11312172
- https://www.digitalocean.com/community/questions/warning-your-environment-specifies-an-invalid-locale-this-can-affect-your-user-experience-significantly-including-the-ability-to-manage-packages
- https://www.digitalocean.com/community/tutorials/how-to-host-multiple-websites-securely-with-nginx-and-php-fpm-on-ubuntu-14-04
- https://www.digitalocean.com/community/tutorials/how-to-create-a-new-user-and-grant-permissions-in-mysql
- https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-12-04
- https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-an-ubuntu-14-04-server
- http://stackoverflow.com/questions/21491996/installing-bower-on-ubuntu-
- http://ithelpblog.com/itapplications/howto-fix-postfixsmtp-network-is-unreachable-error/
- https://www.digitalocean.com/community/tutorials/how-to-create-hot-backups-of-mysql-databases-with-percona-xtrabackup-on-ubuntu-14-04
- https://github.com/jnstq/munin-nginx-ubuntu
- https://letsecure.me/secure-web-deployment-with-lets-encrypt-and-nginx/
- https://www.if-not-true-then-false.com/2011/nginx-and-php-fpm-configuration-and-optimizing-tips-and-tricks/
- http://myshell.co.uk/blog/2012/07/adjusting-child-processes-for-php-fpm-nginx/
- https://jeremymarc.github.io/2013/04/22/nginx-and-php-fpm-for-performance
- http://myshell.co.uk/blog/2012/07/adjusting-child-processes-for-php-fpm-nginx/
- https://serversforhackers.com/video/php-fpm-process-management
- https://overloaded.io/finding-process-memory-usage-linux
- https://gist.github.com/denji/8359866
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.