Setting up a LEMP server for simple projects. Instructions for the smallest. Part two

This article is a continuation of the previous article https://habr.com/ru/company/nixys/blog/645451/. The article is a training material for novice administrators, as well as for developers who would like to get acquainted with the world of project administration. If you are an experienced administrator, you can safely skip this material.

The purpose of this series of articles is to describe the preparation of the server with the stack LEMP (Linux, Nginx, MySQL, PHP), I note that as PHP interpreter is used here Apache2, but not php-fpm, as practice shows, many developers still need a file.htaccess, work with which php-fpm out of the box does not support.

For our part, we transfer the rules from the file .htaccess v Nginx at the need to install PHP-FPM, but it also takes some time, it is often easier and faster for developers to make the necessary rules for current sites exactly in .htaccess file. The articles also describe the deployment of the stack and the raising of working sites on it. The instruction is suitable for small Bitrix projects, as well as for projects deployed under any popular CMS.

Despite the fact that the topic is already covered in sufficient detail on the web, we decided to describe in detail the general standards of administration from scratch, since we regularly receive a large number of basic questions from people who are somehow related to our field.

The purpose of the articles is not to show how to deploy an ideal environment, but only to point out the nuances in operation and protect beginners from basic configuration mistakes.

Table of contents:

Basic Nginx Setup
Apache2 basic setup
Basic MySQL setup.

Basic Nginx Setup

After the basic configuration of the main components of the server, it’s time to start configuring the web server, let’s start with Nginx. The package is already in the standard repositories Debian, so we perform a simple installation:

apt update
apt install nginx

Nginx in our configuration will be the entry point http/https traffic and process static data. After installation, we begin to configure the web server, for this we go to the file /etc/nginx/nginx.conf and bring it to the following form:

user www-data;
worker_processes auto;
worker_priority -15;
include /etc/nginx/modules-enabled/*.conf;
 
error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;
 
events {
        worker_connections  1024;
}
 
http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
 
        log_format nixys '$remote_addrt"$host"t[$time_local]t$statust"$request"t$request_time ($upstream_response_time)t$bytes_sentt"$http_referer"t"$http_user_agent"';
        log_format nixys-debug '$remote_addrt"$host"t[$time_local]t$statust"$request"t"req_time: $request_time"t"bytes_sent: $bytes_sent"n'
                            	'tttttttt"req_file: $request_filename"t"$http_user_agent"t"$http_referer"n'
                                'tttttttt"Request completed: $request_completion"n'
                                'tttttttt"Body request: $request_body"n';
 
    	access_log  /var/log/nginx/access.log nixys;
 
        sendfile	on;
        tcp_nodelay on;
 
    	gzip on;
        gzip_proxied any;
        gzip_comp_level 4;
        gzip_vary on;
        gzip_types text/css text/plain application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
 
    	server_tokens off;
 
    	server_names_hash_bucket_size 33;
        reset_timedout_connection on;
 
        client_header_timeout 15;
        client_body_timeout   15;
        send_timeout       	5;
        keepalive_timeout  30 15;
    	include /etc/nginx/conf.d/*.conf;
    	include /etc/nginx/sites-enabled/*;
}

Let’s go over the main changes we’re adding to the default configuration:

worker_priority -15;

This line increases the priority of processes Nginx in system. This is necessary so that processing priority is given to processes under high load. Nginx, which will allow you to display static site data

worker_connections  1024;

Be sure to enable data compression:

gzip on;
gzip_proxied any;
gzip_comp_level 4;
gzip_vary on; gzip_types text/css text/plain application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;

I would also like to note the following log format:

    	log_format nixys '$remote_addrt"$host"t[$time_local]t$statust"$request"t$request_time ($upstream_response_time)t$bytes_sentt"$http_referer"t"$http_user_agent"';
    	log_format nixys-debug '$remote_addrt"$host"t[$time_local]t$statust"$request"t"req_time: $request_time"t"bytes_sent: $bytes_sent"n'
                           	'tttttttt"req_file: $request_filename"t"$http_user_agent"t"$http_referer"n'
                                'tttttttt"Request completed: $request_completion"n'
                                'tttttttt"Body request: $request_body"n';

Here we define two log formats for Nginx. Log format Nixys will be the default, and will be used for all virtual hosts. The logs connected with it look like this:

31.31.192.22 "site.ru"   [18/Dec/2021:06:26:50 +0500]	200 	"GET / HTTP/1.1"    	0.028 (0.028)   13069   "-" 	"Mozilla/5.0 (compatible; InterfaxBot/1.0; email:swabuse@interfax.ru)" 	

Representing logs in this way is extremely convenient for analysis, let’s expand the log line for understanding:

31.31.192.22 – IP address of the client

site.ru – virtual host name

18/Dec/2021:06:26:50 +0500 – request arrival time

200 – response code received as a result of the request execution

0.028 – Nginx request processing time

(0.028) – processing time of the request from the side, which Nginx passed the request (if necessary). In our case, this will reflect the time for which Apache2 handled the connection.

13069 is the size of the transferred data in bytes

“Mozilla/5.0 (compatible; InterfaxBot/1.0; email:swabuse@interfax.ru)” – user-agent passed by the client.

For our part, we consider this logging format the most successful, as it allows you to analyze the situation as much as possible in case of problems in the operation of the site.

After making these changes, you need to reread the web server files. For any operation reload or restart service Nginx be sure to test the configuration for errors using the command nginx -t, many administrators forget about this at the beginning of their work, which can lead to downtime in the project:

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If everything is OK, then reread the web server configuration:

service nginx reload

And be sure to check the status:

service nginx status
● nginx.service - A high performance web server and a reverse proxy server

   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled
   Active: active (running) since Sun 2021-12-19 19:55:16 MSK; 36min ago
 	Docs: man:nginx(8)
  Process: 2913 ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload (code=exited, status=0/SUCCESS)
 Main PID: 2246 (nginx)
	Tasks: 3 (limit: 1171)
   Memory: 9.3M
   CGroup: /system.slice/nginx.service

           ├─2246 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;

           ├─2914 nginx: worker process

           └─2915 nginx: worker process

Please note that after restarting any service, be sure to check the status of its operation!

On this basic setup Nginx can be considered complete.

Apache2 basic setup

Go to setting Apache2. Install the necessary packages:

apt install apache2 libapache2-mpm-itk

If you did everything according to the article, then Apache2 immediately after installation it will not start and will give an error:

Action 'start' failed.
The Apache error log may have more information.
apache2.service: Control process exited, code=exited, status=1/FAILURE
Failed with result 'exit-code'.
Failed to start The Apache HTTP Server.

The fact is that the default web server runs on the same port as the one running Nginx. Therefore, we need to change the standard 80 web server port 81. To do this, edit the file /etc/apache2/ports.conf and change the port:

-Listen 80
+Listen 81

In our case Apache2 works with the module mpm_prefork, so we enable the module with the command:

a2enmod mpm_prefork

After we need to set the parameters for the work of the workers, you can configure these parameters as you like, depending on the load of the project; they are in the file /etc/apache2/mods-enabled/mpm_prefork.conf, the basic setup looks like this:

<IfModule mpm_prefork_module>
        StartServers        	5
        MinSpareServers     	3
        MaxSpareServers     	10
        MaxRequestWorkers   	50
        MaxConnectionsPerChild  2000
        LimitUIDRange       	0 65535
      	LimitGIDRange       	0 65535
</IfModule>

So that each time you check the syntax Apache2 the message that the server name was not declared did not pop up, we declare it in the file apache2.conf

ServerName MAIN_DOMAIN_NAME

Where MAIN_DOMAIN_NAME this is the server’s primary site name.

You will also need to bring default web server virtual host to the form:

<VirtualHost *:81>
    	ServerName default
    	ServerAdmin webmaster@localhost
    	DocumentRoot /usr/share/apache2/default-site
 
    	ErrorLog ${APACHE_LOG_DIR}/error.log
    	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Change the port it’s running on default virtual host is required according to /etc/apache2/ports.conf. In the future, you will see that the logs of each site will be located in a separate directory, however, the logs of the standard virtual host will be located according to these settings in /var/log/apache2.

It is also very important to set up the correct display external IP address clients in logs apache2, for this you need to activate the following modules using the commands:

a2enmod remoteip
a2enmod rewrite

If after that in the logs apache2 sites featured 127.0.0.1, then you must also make the following changes to the log format:

--- apache2.conf_old	2016-07-06 18:30:37.423038360 +0500

+++ apache2.conf    	2016-07-06 18:27:32.874586631 +0500

@@ -204,8 +204,8 @@

 # Use mod_remoteip instead.

 LogFormat "%v:%p %h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" vhost_combined
-LogFormat "%h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" combined
-LogFormat "%h %l %u %t "%r" %>s %O" common
+LogFormat "%a %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" combined
+LogFormat "%a %l %u %t "%r" %>s %O" common
 LogFormat "%{Referer}i -> %U" referer
 LogFormat "%{User-agent}i" agent

Next, you need to configure the security of the web server, for this we make changes to the file /etc/apache2/conf-available/security.conf:

diff --git a/etc/apache2/conf-available/security.conf b/etc/apache2/conf-available/security.conf
index 599333b..73e4a81 100644

--- a/etc/apache2/conf-available/security.conf
+++ b/etc/apache2/conf-available/security.conf
@@ -22,9 +22,7 @@
# and compiled in modules.
# Set to one of:  Full | OS | Minimal | Minor | Major | Prod
# where Full conveys the most information, and Prod the least.

-#ServerTokens Minimal
-ServerTokens OS
-#ServerTokens Full
+ServerTokens Prod

#

# Optionally add a line containing the server version and virtual host
@@ -33,8 +31,7 @@ ServerTokens OS

# documents or custom error documents).

# Set to "EMail" to also include a mailto: link to the ServerAdmin.
# Set to one of:  On | Off | EMail

-#ServerSignature Off
-ServerSignature On
+ServerSignature Off

 

#
# Allow TRACE method

@@ -44,7 +41,6 @@ ServerSignature On

#
# Set to one of:  On | Off | extended
TraceEnable Off
-#TraceEnable On

 

#
# Forbid access to version control directories
 

We also globally deny access to the .svn, .git, .hg directories:

-#<DirectoryMatch "/.svn">
-#   Require all denied
-#</DirectoryMatch>

+<DirectoryMatch "/.(svn|git|hg)">
+   Require all denied
+</DirectoryMatch>

The final touch in setting up the web server will be setting the rights to the directory with apache2:

chmod 750 /etc/apache2

After completing all these steps, you need to check the syntax Apache2:

apache2ctl -t
Syntax OK

After restarting the web server:

service apache2 restart

And as usual, check the status of the job:

service apache2 status

● apache2.service - The Apache HTTP Server
   Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2021-12-19 21:12:12 MSK; 1s ago
 	Docs: https://httpd.apache.org/docs/2.4/
  Process: 3727 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
 Main PID: 3731 (apache2)
	Tasks: 6 (limit: 1171)

initial setup Apache2 can also be considered complete.

Basic MySQL setup.

Let’s move on to installation and configuration MySQL, in our case it will be the version 5.7. Before starting the installation, add the repository key with the command:

wget -q -O- http://repo.mysql.com/RPM-GPG-KEY-mysql | apt-key add -

After adding the desired repository to the package manager apt, for this to the end of the file /etc/apt/sources.list add lines like:

deb http://repo.mysql.com/apt/debian/ buster mysql-5.7
deb-src http://repo.mysql.com/apt/debian/ buster mysql-5.7

Please note that our server is based on the system Debian 10 (buster), in case you set MySQL to another distribution version Debian or ubuntu, then you will need to take into account the name of the distribution in the list of repositories.

After we update the available packages in the repositories and install MySQL:

apt update
apt install mysql-server

The installation will ask the user to enter the password twice root.

You may need a module to work with python, install it with the command:

apt install python-mysqldb

After installation, we proceed to the basic setup. Default ulimit The (maximum) limit for open files on the system for a process is 1024which is very small, especially for work DBMS, increase the file limit to 8192 across systemctl:

systemctl edit mysql

Insert the following text:

[Service]
LimitNOFILE = 8192

Reread limits and reboot MySQL:

systemctl daemon-reload
systemctl restart mysql

Specify the default DBMS encoding, in our case it is UTF8, for this we make changes to the file /etc/mysql/my.cnf:

diff --git a/mysql/my.cnf b/mysql/my.cnf

[mysqld]
+character-set-server = utf8
+collation-server = utf8_unicode_ci

Default MySQL only listens to local IP the address 127.0.0.1. If you need connections to the DBMS from the outside, you will need to open the port 3306 at the server firewall level, as well as specify MySQL listen on all server interfaces For this parameter bind address specify the following value:

bind-address = 0.0.0.0

Here in the file my.cnf specify the basic parameters for the operation of the DBMS:

max_allowed_packet  	= 32M
thread_stack        	= 512K
thread_cache_size   	= 64
open_files_limit    	= 8192
max_connections     	= 100
query_cache_limit   	= 4M
query_cache_size    	= 16M

These parameters can be adjusted according to the needs of the project.

For tables innodb set storage in separate files to avoid possible problems associated with file growth ibdata1:

innodb_file_per_table

And set a buffer for innodb it is usually equal 60-80% server RAM. For example, for a server with the amount of RAM 4GB we can buffer 3GB random access memory:

innodb_buffer_pool_size = 3GB

The value can also be adjusted as needed.

As a security, we restrict access to MySQL for system users:

chmod 750 /etc/mysql
chown root:mysql /etc/mysql

We restart the DBMS and check the status of the work:

service mysql restart
service mysql status

So that each time you log into the console MySQL do not enter a password root user, create a file in the home directory root and give it security permissions:

touch /root/.my.cnf
chmod 600 /root/.my.cnf

The generated file should have the following content:

[client]
password = MYSQL_ROOT_PASSWORD

Where MYSQL_ROOT_PASSWORD, this is the password for the root user.

Now to connect to the console MySQL from root just enter the command mysql:

mysql

Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 40559777
Server version: 5.7.31-34 Percona Server (GPL), Release '34', Revision '2e68637'

Copyright (c) 2009-2020 Percona LLC and/or its affiliates
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

mysql>

On this basic setup MySQL can be considered complete.

For optimization mysql you can use utility mysql tuner. It is in the standard repositories. Its essence is that with the help of scripts, parameters and current indicators are analyzed. mysql. If there are non-optimized parameters, the utility will offer to change them. Below is an example of the analysis output mysql tuner:

-------- Recommendations -----------------------------------------------------

General recommendations:

    Run OPTIMIZE TABLE to defragment tables for better performance
    Reduce your overall MySQL memory footprint for system stability
    Adjust your join queries to always utilize indexes
    When making adjustments, make tmp_table_size/max_heap_table_size equal
    Reduce your SELECT DISTINCT queries without LIMIT clauses

Variables to adjust:

  *** MySQL's maximum memory usage is dangerously high ***
  *** Add RAM before increasing MySQL buffer variables ***

    query_cache_size (> 16M)
    join_buffer_size (> 16.0M, or always use indexes with joins)
    tmp_table_size (> 128M)
    max_heap_table_size (> 128M)
    innodb_buffer_pool_size (>= 11G)

Conclusion:

The last third article will describe:

  • Installing and configuring PHP

  • The process of creating and configuring virtual hosts for web servers.

  • Issuing SSH and FTP access for the site

  • Setting up mail records so that mail sent from the server does not fall into SPAM.

In the comments to the previous article, I saw a lot of criticism regarding the content and level of the material. I do not agree that articles of this level are unnecessary to the community. As the practice of our company shows, a lot of clients are not yet ready to containerize their project, and therefore the demand for information of this kind is still high. This material is not a panacea, but only a basic instruction that should clarify the basic points and indicate to the administrator the features that need or should not be done at the beginning of the journey.

Thank you for your attention!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *