Image

linux

LEMP: NGINX

How to install NGINX on Ubuntu

9 min read
Last update: November 28, 2021
When I offer to create new user, I call it `jack`, you can use any other username.

1. NGINX & firewall

If you don't allow NGINX on firewall, your domain cannot be loaded.

sudo apt update ; sudo apt install -y nginx ; sudo ufw allow 'Nginx HTTP' ; sudo ufw allow 'Nginx HTTPS' ; sudo ufw allow 'Nginx Full'
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # SSL configuration
        #
        # listen 443 ssl default_server;
        # listen [::]:443 ssl default_server;
        #
        # Note: You should disable gzip for SSL traffic.
        # See: https://bugs.debian.org/773332
        #
        # Read up on ssl_ciphers to ensure a secure configuration.
        # See: https://bugs.debian.org/765782
        #
        # Self signed certs generated by the ssl-cert package
        # Don't use them in a production server!
        #
        # include snippets/snakeoil.conf;

        root /var/www/html;

        # Add index.php to the list if you are using PHP
        index index.php index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
                autoindex on;
        }

        # pass PHP scripts to FastCGI server
        #
        #location ~ \.php$ {
        #       include snippets/fastcgi-php.conf;
        #
        #       # With php-fpm (or other unix sockets):
        #       fastcgi_pass unix:/run/php/php7.3-fpm.sock;
        #       # With php-cgi (or other tcp sockets):
        #       fastcgi_pass 127.0.0.1:9000;
        #}
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        }

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #       deny all;
        #}
}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#       listen 80;
#       listen [::]:80;
#
#       server_name example.com;
#
#       root /var/www/example.com;
#       index index.html;
#
#       location / {
#               try_files $uri $uri/ =404;
#       }
#}

2. MySQL

Install MySQL

sudo apt install -y mysql-server ; sudo mysql_secure_installation
sudo apt install -y mariadb-server ; sudo mysql_secure_installation
About installation
  • Choose password level, I advice LOW to avoid problems with password.
  • Define password
  • Select Yes for all questions after this.

Connect to MySQL CLI

sudo mysql -u root -p

Redefine validate_password.policy if necessary and root password if necessary

mysql
SET GLOBAL validate_password.policy=LOW;
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'super_secret_password';
FLUSH PRIVILEGES;
mariadb
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('password');
FLUSH PRIVILEGES;

It's not a good idea to have one user to manage all databases, root user is useful to create database and users but only with MySQL CLI and not with phpMyAdmin because phpMyAdmin have online access. It's a good idea to create ONE user BY database and give rights about this database only to this NEW user (and root of course). And, the most important, in your application, give new user for credentials. With this solution, your credentials can only manage ONE database, it's more secure if someone find credentials.

Here, it's an example of this solution, my_project_database and my_project_user can be same.

mysql
CREATE DATABASE my_project_database;
CREATE USER 'my_project_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'secret_password';
GRANT ALL ON my_project_database.* TO 'my_project_user'@'localhost';
mariadb
CREATE DATABASE `my_project_database`;
CREATE USER 'my_project_user'@localhost IDENTIFIED BY 'super_secret_password';
GRANT ALL privileges ON my_project_database.* TO 'my_project_user'@localhost;
FLUSH PRIVILEGES;

Give all rights to one user, except root but root will be disable for phpMyAdmin.

CREATE USER 'my_user'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'my_user'@'localhost' WITH GRANT OPTION;
exit

Disable root for phpMyAdmin

Open phpMyAdmin config

sudo vim /usr/share/phpmyadmin/config.inc.php

Find $cfg['Servers'][$i]['auth_type'] = 'cookie'; line and add this line $cfg['Servers'][$i]['AllowRoot'] = FALSE;

/usr/share/phpmyadmin/config.inc.php
if (!empty($dbname)) {
  /* Authentication type */
  $cfg['Servers'][$i]['auth_type'] = 'cookie';
  $cfg['Servers'][$i]['AllowRoot'] = FALSE; // add this line
  // ...
}

Now root user is forbidden with phpMyadmin but allowed with MySQL CLI.

3. PHP

This will install LTS version of PHP, if you want to upgrade it, check this guide

sudo apt install -y php-fpm php-mysql
sudo apt install -y php7.4-mbstring php7.4-mysql php7.4-common php7.4-mysql php7.4-xml php7.4-curl php7.4-gd php7.4-imagick php7.4-cli php7.4-dev php7.4-imap php7.4-mbstring php7.4-opcache php7.4-soap php7.4-zip php7.4-intl php7.4-bz2

3. a. PHP 8.0+

Install PPA for PHP

sudo apt install software-properties-common ; sudo add-apt-repository ppa:ondrej/php
sudo apt update ; sudo apt install -y lsb-release ca-certificates apt-transport-https software-properties-common gnupg2 gnupg gnupg1 ; echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/sury-php.list ; wget -qO - https://packages.sury.org/php/apt.gpg | sudo apt-key add - ; sudo apt update

Press Enter to add repository to APT source list.

Install PHP 8.0 FPM for NGINX.

sudo apt update ; sudo apt -y install php8.0-fpm

Check PHP 8.0 status.

systemctl status php8.0-fpm

Install extension for PHP 8.0

sudo apt install -y php8.0-mbstring php8.0-mysql php8.0-common php8.0-mysql php8.0-xml php8.0-curl php8.0-gd php8.0-imagick php8.0-cli php8.0-dev php8.0-imap php8.0-mbstring php8.0-opcache php8.0-soap php8.0-zip php8.0-intl php8.0-bz2

4. Virtual Host

sudo usermod -a -G www-data $USER

NGINX is setup but now, we have to setup Virtual hosts (or VHost). We take a basic example with just PHP 7.2 and an index.php, but it's same concept for any PHP app like Laravel or Symfony.

Create NGINX conf for this app

sudo vim /etc/nginx/sites-available/my-domain.localhost

Insert these infos and save file

server {
  listen 80;
  root /var/www/my-domain;
  index index.php index.html index.htm index.nginx-debian.html;
  server_name my-domain.localhost;

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

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

  location ~ /\.ht {
    deny all;
  }
}

Setup rights on web server folder /var/www, create root folder for the app and index.php

sudo chown -R $USER:www-data /var/www ; sudo mkdir /var/www/my-domain ; sudo touch /var/www/my-domain/index.php ; sudo vim /var/www/my-domain/index.php

Fill index.php with basic infos

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Domain</title>
</head>
<body>
  <div style="text-align: center; font-weight: bold; font-family: sans-serif; margin: 5rem 0">
    This is my new domain!
    <br/>
    <?php
      echo $_SERVER['SERVER_SOFTWARE'];
    ?>
  </div>
</body>
</html>

Make symbolic link with NGINX conf and sites-enabled to enable this conf, check NGINX configuration and reload NGINX to refresh web server

sudo ln -s /etc/nginx/sites-available/my-domain.localhost /etc/nginx/sites-enabled ; sudo nginx -t ; sudo service nginx reload

And now, you can access to you domain to http://my-domain.localhost

Next step: install and configure phpMyAdmin

Allow big files uploading

NGINX default conf allow 2 Mo files max in upload, if you want to change it follow these steps

  • For NGINX
sudo vim /etc/nginx/nginx.conf

Change or add this line

http {
  # ...
  client_max_body_size 500M;
}
  • For PHP

Check PHP version used by your application, php -v give you just PHP CLI version, if don't setup VHost, it's PHP version of your app but if you have a VHost you have to check PHP version of conf. And update current php.ini

# for example if current version is 7.4
sudo vim /etc/php/7.4/fpm/php.ini

Search and change these lines

post_max_size = 500M
# ...
upload_max_filesize = 500M

Restart NGINX and PHP

sudo service nginx restart
sudo service php7.4-fpm restart

You can check with phpinfo()

PHP version and NGINX

When you execute php command into your terminal, you have a current PHP version than you can check it with php -v. But yours VHosts can always use old version of PHP, you will have to update NGINX conf for each VHost if you want to change their version of PHP (it's optional). You can keep VHost with old version of PHP, if you let this version on your system, it's useful to update version if you use modern syntax in your PHP app, for example type of parameters is available with latests PHP versions.

Following steps talks about VHost, if you don't know how it's works, read [*4. Virtual Host*](/guides/linux/lemp/#_4-virtual-host) before.

If you want to update a VHost NGINX conf, check it in /etc/nginx/sites-available/ and edit it, like:

sudo vim /etc/nginx/sites-available/my-domain

You will have some infos but search this line

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

In this example, this VHost use PHP 7.2 version but if you installed PHP 7.4, you can update it

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

And your app will use new PHP version.

If you change PHP version, it can be missing some extensions, if your app display an error about extension check this part : [*missing extension*](/guides/linux/phpmyadmin/#missing-extension)

Troubles

List virtual hosts with Nginx

grep server_name /etc/nginx/sites-enabled/* -RiI

Uninstall NGINX

sudo apt-get purge nginx nginx-common
sudo apt-get autoremove

VHost works on Chrome but not on Firefox

open Preferences -> Advanced -> Network open Settings and check manual proxy config and set proxy HTTP 127.0.0.1 and port 80