Part 2: Configuring VPS and DNS

Part 2: Configuring VPS and DNS

October 20, 2024

Since I only own one domain, I want to utilize subdomains to serve different websites. As you can see, this site is hosted under blog.minhperry.de, and the Skyblock site is under skyblock.minhperry.de. This guide will walk you through how to set up multiple subdomains under a single VPS host.

Prerequisites

  • You have already shared your ssh key with your VPS provider.
  • You have basic knowledge of working with the Linux terminal.
  • You already have an nginx server installed, along with certbot for SSL certificates.
  • You have access to your domain’s DNS panel. In this case, I have also proxied it through Cloudflare for extra protection.

This guide is for setting up an Nginx server on an Ubuntu 24.04.1 VPS. I am logged in as the root user, so all sudo commands are omitted here. Add sudo before every command if you are not logged in as root.

DNS Routing

First, create a DNS A record with the following content:

DNS Setup

Setting the name as * will match all subdomains (e.g., *.example.com), but not the top-level domain (TLD) example.com. To match the TLD, you need to use the @ selector. You can also use a CNAME record to alias a subdomain to another domain, rather than pointing to an IP address like an A record.

Adjusting the Firewall

Before anything else, we need to adjust the firewall to allow access to Nginx. Just follow this DigitalOcean guide.

Optionally, you can also deny HTTP traffic by blocking Nginx HTTP access through the firewall, forcing only HTTPS traffic:

bash
ufw deny 'Nginx HTTP'

SSL/TLS and Nginx Configuration

With SSL/TLS, my website can be served safely over the internet, using the HTTPS protocol. Here, I use Let’s Encrypt with the help of Certbot, following this guide:

Step 1: Generating the Wildcard Certificate

bash
sudo certbot certonly --manual --preferred-challenges=dns --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d '*.yourdomain.net'

Follow the prompts and add a DNS TXT record to prove your ownership. The certificate (fullchain.pem) and its private key (privkey.pem) will be stored under /etc/letsencrypt/live/yourdomain.net. This certificate lasts for 90 days, and you can renew it near the end with certbot renew --nginx.

Step 2: Configuring Nginx

If you are not familiar with Nginx, I recommend reading the beginner’s guide first. Otherwise, let’s get straight to the point.

Upon installation, Nginx will drop a default config file in its config folder, which looks like this:

/etc/nginx/sites-available/default
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL configuration
    #
    # listen 443 ssl default_server;
    # listen [::]:443 ssl default_server;
    #
    # Note: You should disable gzip for SSL traffic.
    # See: https://bugs.debian.org/773332
    #
    # Read up on ssl_ciphers to ensure a secure configuration.
    # See: https://bugs.debian.org/765782
    #
    # Self-signed certs generated by the ssl-cert package
    # Don't use them in a production server!
    #
    # include snippets/snakeoil.conf;

    root /var/www/html;

    # Add index.php to the list if you're using PHP
    index index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        # First attempt to serve the request as a file, then
        # as a directory, and fall back to displaying a 404.
        try_files $uri $uri/ =404;
        # proxy_pass http://localhost:8080;
        # proxy_http_version 1.1;
        # proxy_set_header Upgrade $http_upgrade;
        # proxy_set_header Connection 'upgrade';
        # proxy_set_header Host $host;
        # proxy_cache_bypass $http_upgrade;
    }

    # ... and more
}

Here, I wanted all subdomains to default to an Nginx 404 page for now. After removing unnecessary configurations and adding the SSL certificate, here’s the final result:

/etc/nginx/sites-available/default
server {
    # Technically, these can be removed because we don't allow HTTP
    # through port 80, so there's nothing to listen to.
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL configuration
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    # Default Nginx HTML example file
    root /var/www/html;

    # Use the wildcard generated SSL certificate
    ssl_certificate /etc/letsencrypt/live/minhperry.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/minhperry.de/privkey.pem;

    # List of index files to search for
    index index.html index.htm index.nginx-debian.html;

    # Catch-all block for any non-specified domain,
    # since _ is an invalid domain that will never match anything.
    # Refer to https://nginx.org/en/docs/http/server_names.html
    server_name _;

    # For now, return a 404. You can implement a custom mechanism.
    return 404;
}

For each subsequent subdomain, create a text file in the same folder as the default config above. Each file will be responsible for the subdomain. This site uses this configuration:

/etc/nginx/sites-available/blog
server {
    # Listen on IPv4 or IPv6 based on your DNS configuration.
    # However, IPv4 is more widely used, so it's preferred.
    listen 443 ssl;

    # Specify subdomain here. This will match the exact subdomain.
    server_name blog.minhperry.de; 

    # Use the same SSL certificate
    ssl_certificate /etc/letsencrypt/live/minhperry.de/fullchain.pem;  
    ssl_certificate_key /etc/letsencrypt/live/minhperry.de/privkey.pem; 

    # Root where your built index.html is located.
    root /var/www/frontend/blog; 
    index index.html index.htm;

    # If you didn't notice, root is always redirected to /about.
    location = / {
            return 301 /about;
    }

    # Optionally, enable error logging if needed.
    # error_log /var/log/nginx/blog_err.log;
}

One crucial thing is that the specified root folder must be readable by the www-data group in Nginx. You can test this with:

bash
sudo -u www-data stat /absolute/path/to/specified/root

Step 3: “Activating” the Subdomain

Since all configurations are in sites-available, this only informs Nginx that they are available to be served. To activate those subdomains, create a symbolic link of each config in sites-enabled:

bash
ln -s /etc/nginx/sites-available/<data-name> /etc/nginx/sites-enabled/

And that’s it. You’re done. The final result should look like this:

Final tree view