Nginx Virtual Hosts Configuration

Nginx Virtual Hosts Configuration

Nginx virtual hosts will enable you to host multiple websites on your server. All websites will share the same IP address. This can be done by making a unique virtual host file on your Nginx webserver for each domain.


a. Adjust DNS Records For Your Domain

1. Before we go through the configuration of Nginx virtual hosts, we should adjust the DNS Settings. So, go to your DNS settings in your domain registrar panel. Then, create an A Record for your domain that you would like to host on your server as below. Note that we will use the domain: gainbybrain.com as an example. You can use the same domain that’s connected to the email server (vpsprof.com) as we connected only the mail subdomain (mail.vpsprof.com). In other words, vpsprof.com is free to point to your WordPress website on the same server.

DNS Record TypeHostContent, Value or the AnswerTTL (Time To Live)
A@144.91.72.551 min (or the minimum allowed)
DNS Record TypeHostContent, Value or the AnswerTTL (Time To Live)
Awww144.91.72.551 min (or the minimum allowed)

We already explained how to configure DNS records here: DNS Settings (Add A Record part). Your two A records should be like the two A records below. Note that the @ sign refers to the domain format: https://gainbybrain.com while the www refers to the domain format: www.gainbybrain.com. In this article, any request that comes with or without https and with or without www, will be directed to https://gainbybrain.com (or https://vpsprof.com if you use vpsprof.com instead of gainbybrain.com).

Your DNS records should look like below:

Adjust DNS Records for Nginx Virtual Hosts

b. Obtain SSL Certificate

1. Install the software-properties-common if not installed, by running the below command on PuTTY SSH client or any Linux terminal:

root@mail:~# apt install software-properties-common

2. Update your repository by running the following command:

root@mail:~# apt update

3. Install the Certbot by running the following command:

root@mail:~# apt install certbot python3-certbot-nginx
Install Certbot Nginx Server

Sometimes, you get a prompt to confirm the installation by typing: y, or: Y.

4. Request the SSL certificate by running the below command:

root@mail:~# certbot --nginx certonly -d gainbybrain.com

If you don’t want the traffic on https://www.gainbybrain.com to be redirected to https://gainbybrain.com, include www in the certificate request as below:

root@mail:~# certbot --nginx certonly -d gainbybrain.com -d www.gainbybrain.com

Request SSL Certificate Enter Email

Enter your email address then hit Enter key.

5. You will be asked to agree on terms if you use Letsencrypt for the first time.

Request SSL Certificate Terms Agreement

Type: A, or: a, then hit Enter key.

6. You will be asked if you would like to share your email.

Request SSL Certificate Share Email Address

We will choose no, so type: N, or: n, then hit Enter key.

Request SSL Certificate Success

And here we go, you should see a congratulations! notice which means that the certificate has been installed successfully 🙂

7. Reboot Nginx server to take the effect of the changes by running the command:

root@mail:~# service nginx reload

If Nginx configuration is OK but it doesn’t reboot for no reason, you can reboot the whole server, it should fix the problem.

d. Manage Nginx Virtual Hosts Directories (sites-available and sites-enabled)

1. We will create a sites-available file then load it with server directives code. But, we’ve two cases related to the existence of iRedMail on your server, each case is different because iRedMail comes with built-in configurations that we should use.

First Case: If iRedMail is Installed

Run the below command to open a virtual host file for your domain. For example, we will make virtual host for the domain: gainbybrain.com. Note that the file has .conf extension which is used to define the virtual host files.

root@mail:~# nano /etc/nginx/sites-available/gainbybrain.com.conf

Then, add the below lines inside the file. Note that you need to replace the domain (gainbybrain.com) in bold in the file with your own domain and the directory (sitebase) with your own directory name in case you haven’t updated the website on the golden box on top.

# HTTP
server {

    server_name gainbybrain.com www.gainbybrain.com;

    # Redirect http://www.site to https://site
    if ($host = www.gainbybrain.com) {
        return 301 https://$host$request_uri;
    }

    # Redirect http://site to https://site
    if ($host = gainbybrain.com) {
        return 301 https://$host$request_uri;
    }

    # Redirect all insecure http:// requests to https://
    return 301 https://$host$request_uri;
}

# HTTPS
server {

    # ipv4 with http2

    ## For Nginx version < 1.25.1
    listen 443 ssl http2;

    ## For Nginx version >= 1.25.1
    #listen 443 ssl;
    #http2 on;

    # ipv6 with http2
    #listen [::]:443 ssl http2;

    # SSL Certificate
    ssl_certificate /etc/letsencrypt/live/gainbybrain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/gainbybrain.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # Website URL and Directory
    server_name gainbybrain.com www.gainbybrain.com;
    root /var/www/html/sitebase;
    index index.php index.html;

    ## Below are iRedMail included
    #include /etc/nginx/templates/misc.tmpl;
    #include /etc/nginx/templates/ssl.tmpl;
    #include /etc/nginx/templates/iredadmin.tmpl;
    #include /etc/nginx/templates/roundcube.tmpl;
    #include /etc/nginx/templates/sogo.tmpl;
    #include /etc/nginx/templates/netdata.tmpl;

    # Connect Nginx to PHP
    include /etc/nginx/templates/php-catchall.tmpl;

    #include /etc/nginx/templates/stub_status.tmpl;

    # Don't allow pages to be rendered in an iframe on external domains.
    add_header X-Frame-Options "SAMEORIGIN";

    # MIME sniffing prevention
    add_header X-Content-Type-Options "nosniff";

    # Enable cross-site scripting filter in supported browsers.
    add_header X-Xss-Protection "1; mode=block";

    # Prevent access to hidden files
    location ~* /\.(?!well-known\/) {
        deny all;
    }

    # Prevent access to certain file extensions
    location ~\.(ini|log|conf)$ {
        deny all;
    }

    # Enable WordPress Permanent Links
    # If we don’t add the below, website directories will get 404 error (like: site/admin or  site/sample-page)
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

Second Case: If iRedMail is Not Installed

Open a virtual host file for your domain. Replace the domain: gainbybrain.com with your own domain.

root@iRedMail-doesnt-exist:~# nano /etc/nginx/sites-available/gainbybrain.com.conf

If you already installed PHP, Nginx and MariaDB separately by following the articles: Install PHP on Ubuntu, Install Nginx on Ubutu and Install MariaDB on Ubuntu, add the below lines inside the file. Note that you need to replace the domain (gainbybrain.com) in bold in the file with your own domain and the directory (sitebase) with your own directory name in case you haven’t updated the website on the golden box on top.

# HTTP
server {

    server_name gainbybrain.com www.gainbybrain.com;

    # Redirect http://www.site to https://site
    if ($host = www.gainbybrain.com) {
        return 301 https://$host$request_uri;
    }

    # Redirect http://site to https://site
    if ($host = gainbybrain.com) {
        return 301 https://$host$request_uri;
    }

    # Redirect all insecure http:// requests to https://
    return 301 https://$host$request_uri;
}

# HTTPS
server {

    # ipv4 with http2
    
    ## For Nginx version < 1.25.1
    listen 443 ssl http2;

    ## For Nginx version >= 1.25.1
    #listen 443 ssl;
    #http2 on;

    # ipv6 with http2
    #listen [::]:443 ssl http2;

    # SSL Certificate
    ssl_certificate /etc/letsencrypt/live/gainbybrain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/gainbybrain.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # Website URL and Directory
    server_name gainbybrain.com www.gainbybrain.com;
    root /var/www/html/sitebase;
    index index.php index.html;

    # Connect Nginx to PHP
    location ~ \.php$ {
        fastcgi_pass    unix:/run/php/php7.4-fpm.sock;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include         fastcgi_params;
    }

    # Don't allow pages to be rendered in an iframe on external domains.
    add_header X-Frame-Options "SAMEORIGIN";

    # MIME sniffing prevention
    add_header X-Content-Type-Options "nosniff";
    # Enable cross-site scripting filter in supported browsers.
    add_header X-Xss-Protection "1; mode=block";

    # Prevent access to hidden files
    location ~* /\.(?!well-known\/) {
        deny all;
    }

    # Prevent access to certain file extensions
    location ~\.(ini|log|conf)$ {
        deny all;
    }

    # Enable WordPress Permanent Links
    # If we don’t add the below, website directories will get 404 error (like: site/admin or  site/sample-page)
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

2. Make symbolic link between the virtual host in sites-available directory and sites-enabled directory by running the command. After running this command, the file will be copied to sites-enabled directory and linked at the same time.

root@mail:~# ln -s /etc/nginx/sites-available/gainbybrain.com.conf /etc/nginx/sites-enabled

If you want to disable any website, just delete its virtual hosts file from the sites-enabled directory. If you want to enable it, then make a symbolic link again by running the command above.

Create Symbolic Link for Nginx Virtual Hosts Sites-Enabled Directory

3. Let’s make sure that Nginx has no problems by running the below command:

root@mail:~# nginx -t

4. In case no errors appear, restart Nginx by running the command for the changes to take effect.

root@mail:~# service nginx restart

In case you got Nginx warning like below:

nginx: [warn] the "listen ... http2" directive is deprecated, use the "http2" directive instead in /etc/nginx/sites-enabled/gainbybrain.com.conf:24

It happens because for Nginx versions >= 1.25.1, the format changed. The old format is like this:

listen 443 ssl http2;

And the new format is like below:

listen 443 ssl;
http2  on;

You can find your Nginx version by running the command:

root@mail:~# nginx -v

GZIP Compression

You can enable GZIP compressoin on your website by adding the below code to HTTPS server block at the end of the file gainbybrain.com.conf

    ## https://kinsta.com/blog/enable-gzip-compression/
    # enables GZIP compression
    gzip on;

    # compression level (1-9)
    # 6 is a good compromise between CPU usage and file size
    gzip_comp_level 6;

    # minimum file size limit in bytes to avoid negative compression outcomes
    gzip_min_length 256;

    # compress data for clients connecting via proxies
    gzip_proxied any;

    # directs proxies to cache both the regular and GZIP versions of an asset
    gzip_vary on;

    # disables GZIP compression for ancient browsers that don't support it
    gzip_disable "msie6";

    # compress outputs labeled with the following file extensions or MIME-types
    # text/html MIME-type is enabled by default and need not be included
    gzip_types
    application/atom+xml
    application/geo+json
    application/javascript
    application/x-javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rdf+xml
    application/rss+xml
    application/vnd.ms-fontobject
    application/wasm
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/eot
    font/otf
    font/ttf
    image/bmp
    image/svg+xml
    text/cache-manifest
    text/calendar
    text/css
    text/javascript
    text/markdown
    text/plain
    text/xml
    text/vcard
    text/vnd.rim.location.xloc
    text/vtt
    text/x-component
    text/x-cross-domain-policy;

If you want to copy a large portion of text from a file (like the gzip code above) while using PuTTY, it’s better to run cat command instead of copying the code from nano file because when you highlight the text with the mouse and try to scroll down, it won’t go down but it works with cat command:

root@mail:~# cat /etc/nginx/sites-available/gainbybrain.com.conf

5. Now, let’s test by visiting the website: https://gainbybrain.com, you need to visit your own domain.

If iRedMail is not installed and you already installed PHP, Nginx and MariaDB separately by following the articles: Install PHP on Ubuntu, Install Nginx on Ubutu and Install MariaDB on Ubuntu, you may get the error below:

Your PHP installation appears to be missing the MySQL extension which is required by WordPress.
Missing PHP-MySQL Extension after Nginx Virtual Hosts Configuration

But don’t worry, the solution is very easy! Just install MySQL extension by running the below command:

root@iRedMail-doesnt-exist:~# apt install php7.4-mysql

Don’t forget to enable the APT repository for the PHP before running the command above:

root@iRedMail-doesnt-exist:~# add-apt-repository ppa:ondrej/php

And once you finish, disable it to avoid upgrading PHP version automatically when running apt-upgrage:

root@iRedMail-doesnt-exist:~# add-apt-repository ppa:ondrej/php --remove
Install PHP-MySQL Extension

You don’t need to restart Nginx server. Now test the WordPress, it works! You can start the installation now.

WordPress Works and Ready to Start

If you need to enable the HTML format for the WooCommerce transnational emails, you should install the php-xml module by running the command:

root@iRedMail-doesnt-exist:~# apt install php8.0-xml

If the php-xml module is not installed on your server, the WooCommerce Email type in the WooCommere Settings (Emails) will show only “Plain text” option like this:
Email type -> Plain text.

Once you install the php-xml module, you will see:
Email type -> Plain text, HTML, Mutipart