Table of Contents
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
<VirtualHost *:80> ServerName site1 DocumentRoot /var/www/site1.com </VirtualHost>
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 <Directory> directive is used:
<VirtualHost *:80> ServerName site1.com DocumentRoot /var/www/site1.com <Directory /var/www/site1.com/> # Directives here </Directory> </VirtualHost>
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:
<VirtualHost *:80> ServerName site1.com DocumentRoot /var/www/site1.com <Directory /var/www/site1.com/> DirectoryIndex index.html index.php </Directory> </VirtualHost>
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.
<VirtualHost *:80> ServerName site1.com DocumentRoot /var/www/site1.com <Directory /var/www/site1.com/> Options +Indexes </Directory> </VirtualHost>
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:
<VirtualHost *:80> ServerName site1.com DocumentRoot /var/www/site1.com <Directory /var/www/site1.com/> Require 192.168.0.0/24 </Directory> </VirtualHost>
NOTE: The Require directive inside a Directory stanza, allows access only from a specific subnet, for example 192.168.0.0/24.
In NginX:
<VirtualHost *:80> ServerName site1.com DocumentRoot /var/www/site1.com <Directory /var/www/site1.com/> <RequireAll> Require all granted Require not 192.168.0.0/24 </RequireAll> </Directory> </VirtualHost>
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 <RequireAll> 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.
<VirtualHost *:80> ServerName site1.com DocumentRoot /var/www/site1.com ErrorLog "/var/log/httpd/site1.com-error.log" </VirtualHost>
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.
<VirtualHost *:80> 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" </VirtualHost>
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"