====== 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"