====== Web Servers - Migrate Apache to Nginx by converting VirtualHosts to Server Blocks ======
Both Apache and Nginx have the ability to serve multiple websites.
* On Apache the various sites to be served are configured using VirtualHosts;
* On Nginx Server Blocks are used instead.
----
===== Install NginX =====
sudo apt update && sudo apt install nginx
----
===== Start and Enable NginX =====
Stat the nginx service and set it to be automatically launched at boot:
sudo systemctl enable --now nginx
**NOTE:** The server listens on port 80 by default, so to verify that it is reachable we can simply navigate to http://localhost with a web browser.
----
===== Convert Apache VirtualHost to NginX Server Block =====
==== Apache VirtualHost Directives ====
ServerName site1
DocumentRoot /var/www/site1.com
**NOTE:** This configuration is usually in **/apache2/sites-available** and have a **.conf** extention.
* For this site to be **activated**, a symlink needs to be created in **/etc/apache2/sites-enabled**.
* The **a2ensite** command is used for this:
sudo a2ensite site1.com.conf
* ***:80**: The IP address to listen on.
* **ServerName**: The hostname that the server uses to identify itself.
* **DocumentRoot**: The root directory which hosts the site document tree.
* In this case, the directory is /var/www/site1.com.
----
==== NginX Server Block ====
server {
listen *:80;
server_name site1.com;
root /var/www/site1.com;
}
**NOTE:** This configuration is usually in **/etc/nginx/sites-available** and have a **.conf** extention.
* For this site to be **activated**, a symlink needs to be created in **/etc/enginex/sites-enabled**.
sudo ln -s /etc/nginx/sites-available/site1.com.conf /etc/nginx/sites-enabled/
* **listen**: The listen directive is used to set to what address and IP the Server Block will respond to and serve the request.
* In this case we only set *:80, which means that the Server Block will respond to request on all IPs on port 80.
* ***:80**: The IP address to listen on. The ***** is a catch-all for all.
* **server_name**: The hostname that the server uses to identify itself.
* **root**: The root directory which hosts the site document tree.
* In this case, the directory is /var/www/site1.com.
----
===== Applying configuration to a specific directory of the website =====
With Apache, the **** directive is used:
ServerName site1.com
DocumentRoot /var/www/site1.com
# Directives here
The corresponding directive for an Nginx server block is **location**:
server {
listen *:80;
server_name site1.com;
root /var/www/site1.com;
location / {
# Directives here
}
}
**NOTE:** For both Apache and NginX, the directives can be repeated in order to fine-tune the configuration.
----
===== Specifying what files should be used as index =====
In Apache use **DirectoryIndex**:
ServerName site1.com
DocumentRoot /var/www/site1.com
DirectoryIndex index.html index.php
In NginX use **index**:
server {
listen *:80;
server_name site1.com;
root /var/www/site1.com;
location / {
index index.html index.php
}
}
**NOTE:** The index.html and index.php files are configured as the index.
----
===== Enabling directory listing output =====
If a site directory is navigated to, but none of the set index files exists in it, the default behavior is to deny access to that directory.
* However, the web server can be configured to allow it to generate and display a list of the files existing in that directory.
In Apache, the **Indexes** option is enabled by using the **+** sign.
ServerName site1.com
DocumentRoot /var/www/site1.com
Options +Indexes
In NginX, the the **autoindex** directive is set to **on**.
server {
listen 80;
server_name site1.com;
root /var/www/site1.com;
location / {
autoindex on;
}
}
----
===== Restricting access to a resource =====
In Apache:
ServerName site1.com
DocumentRoot /var/www/site1.com
Require 192.168.0.0/24
**NOTE:** The **Require** directive inside a Directory stanza, allows access only from a specific subnet, for example 192.168.0.0/24.
In NginX:
ServerName site1.com
DocumentRoot /var/www/site1.com
Require all granted
Require not 192.168.0.0/24
**NOTE:** Those **Require** directives are used to group multiple access rules and they work this way:
^Directive^To be successful^
|RequireAll|No directive must fail and at least one must succeed (directive can also be neutral).|
|RequireAny|At least one directive must succeed.|
|RequireNone|No directive must succeed.|
Why did we use the **** directive?
* This is because when a require directive is negated (we used not), it can only fail or return a neutral result, therefore a request cannot be authorized on the base of a negated require alone.
* What we had to do is to put the negated Require inside a **RequireAll** directive, which in this case will fail since, as we stated above, for it to succeed, no directive inside of it must fail;
* that is why we also put the **Require all granted** inside of it: to give it a change to succeed.
* If we do not do this, the following error would be seen on server restart:
AH01624: directive contains only negative authorization directives
The equivalent configuration for an Nginx Server Block can be obtained via the **allow** and **deny** directives.
To allow access only from the subnet we used in the example above, we would write:
server {
listen *:80;
server_name site1.com;
root /var/www/site1.com;
location / {
deny all;
allow 192.168.0.0/24;
}
}
To deny access to requests coming from the 192.168.0.0/24 subnet, instead:
server {
listen *:80;
server_name site1.com;
root /var/www/site1.com;
location / {
deny 192.168.0.0/24;
}
}
----
===== Specifying dedicated error and access log files =====
In Apache, configure error logs for the specific resource are written into a dedicated file.
ServerName site1.com
DocumentRoot /var/www/site1.com
ErrorLog "/var/log/httpd/site1.com-error.log"
Where the requests received by the server are logged, instead, is managed by the **CustomLog** directive.
* This directive accepts two mandatory arguments:
- The path of the file in which the logs will be written,
- What will be written into the file, defined using a format string.
ServerName site1.com
DocumentRoot /var/www/site1.com
ErrorLog "/var/log/httpd/site1.com-error.log"
CustomLog "/var/log/httpd/site1.com-access.log" "%t %h %>s"
**NOTE:** The format string defines:
^Notation^Meaning^
|%t|The time the request was received.|
|%h|The IP address of the request.|
|%>s|The final status of the request.|
SEE https://httpd.apache.org/docs/2.4/mod/mod_log_config.html#formats for additional formats.
A line in the access log file, in this case, would look like this:
[01/Oct/2021:23:49:56 +0200] 127.0.0.1 200
In NginX, errors are logged using:
server {
listen *:80;
server_name site1.com;
root /var/www/site1.com;
error_log "/var/log/nginx/site1.com-error.log";
}
Access is logged, using the **access_log** directive.
* By default the messages are stored in the default **combined** format, but this can be changed via the **log_format** directive:
server {
listen *:80;
server_name site1.com;
root /var/www/site1.com;
error_log "/var/log/nginx/site1.com-error.log";
access_log "/var/log/nginx/site1.com-access.log";
}
**NOTE:** Using the default log format, an access log line will look like this:
127.0.0.1 - - [01/Oct/2021:23:58:32 +0200] "GET / HTTP/1.1" 200 12 "-" "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:92.0) Gecko/20100101 Firefox/92.0"