DEV Community

Santosh Venkatraman πŸ––
Santosh Venkatraman πŸ––

Posted on

Configure nginx to host multiple subdomains

This post has been cross-posted from my blog

Configuring nginx for subdomains in the same machine was confusing for me. So I am writing this tutorial primarily for (self)reference but people can find it useful. Without much ado, let's get started.

For those of you who don't know what nginx is exactly, head over to this freeCodeCamp article as a starting point.

I assume you're on a linux machine and you know what nginx means.

First and foremost, install nginx -

sudo apt-get install nginx
Enter fullscreen mode Exit fullscreen mode

Second head over to /etc/nginx/sites-available/default by opening it on vim/nano. You would come across something like this -

# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.

# Default server configuration
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:
    # Read up on ssl_ciphers to ensure a secure configuration.
    # See:
    # 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 are using PHP
    index index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;

    # pass PHP scripts to FastCGI server
    #location ~ \.php$ {
    #   include snippets/fastcgi-php.conf;
    #   # With php-fpm (or other unix sockets):
    #   fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    #   # With php-cgi (or other tcp sockets):
    #   fastcgi_pass;

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #location ~ /\.ht {
    #   deny all;

# Virtual Host configuration for
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#server {
#   listen 80;
#   listen [::]:80;
#   server_name;
#   root /var/www/;
#   index index.html;
#   location / {
#       try_files $uri $uri/ =404;
#   }.
Enter fullscreen mode Exit fullscreen mode

From the above you can gather the following points -

  • server {} - that tells nginx that "Hey this is how I think you should configure the server"
  • listen 80 - translates to "Listen to port 80, which is the default port for web clients"
  • root /var/www/html; - nginx understands that HTML file/files from that location can be served
  • index index.html index.htm index.nginx-debian.html; - this indicates that these kind of files should be served in a decreasing order of priority (left to right).
  • server_name _; - this conveys that _ is the server name. Assuming our domain to be, the server name would be That's because when a request is received for, nginx should whether to process it or not.
  • location / {} - this means that all requests must be handled by this server config. There is an option to handle specific requests as well. For example, requests starting with /server_1 can load server_1.html and all other requests can load default.html.

Next obvious question is - how do I configure subdomains?

It's not that complicated. It involves 7 steps -

  • Copy the default configuration and rename it as
cp /etc/nginx/sites-available/default /etc/nginx/sites-available/
Enter fullscreen mode Exit fullscreen mode

Note: You don't necessarily have to name the file It's easier if you follow a convention that makes it easy for everybody involved.

  • Open it and remove the term default_server besides listen 80 and the line below it. This is crucial.
  • Change the server_name as & change the HTML root that's being used
  • Then link that file to a file in nginx's sites-enabled directory. This is for nginx to understand that configuration is enabled in the configuration.
sudo ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/
Enter fullscreen mode Exit fullscreen mode
  • Write a HTML file inside /var/www/html for
  • Restart the nginx server
  • If you're using a DNS provider like Cloudflare, add the box's IP to it with an A record If not, then add the box's IP and to /etc/hosts.
  • Load on the browser to check how it loads. If everything is fine, you will see the HTML that you wrote for this subdomain.

Extend the same approach for any other domain or subdomain that you require.

Top comments (3)

kp profile image

Hi Santosh,

I've been struggling with setting up nginx subdomains on my linode instance and setting up CNAME redirects.

What I need is to be able to do:

  1. First set up wildcard subdomains on my server (, so that users can go to,, etc.
    My server is running nuxt.js on port 4001 (default port is 3000 but I chose to use 4001 as a non-standard port), so I guess I have to use reverse proxies:
    proxy_pass localhost:4001;

  2. Then for my users I need to set up CNAME redirects from to, and from to, so that if I visit , it would serve the contents (without redirecting me) of For testing purposes I have an additional domain ( that we could use.

However, I've not been able to get step 1 working. Any ideas?

Below is my nginx config from sites-available/

server {
    index index.html index.htm;

    location / {
        # WARNING: https in proxy_pass does NOT WORK!! I spent half a day debugging this.
        #proxy_pass https://localhost:4001;
        proxy_pass http://localhost:4001;
        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;


    # Kunal: create a custom 404 nginx page, from
    error_page 404 /custom_404.html;

    location = /custom_404.html {
        root /etc/nginx/sites-available/custom_nginx_error_pages;

    listen [::]:4001 ssl http2; # managed by Certbot, modified by Kunal to add http2
    listen 4001 ssl http2; # managed by Certbot, modified by Kunal to add http2
    #Install SSL certificates and configure https:// on a per-domain-basis by running:
    #sudo certbot --nginx
    #(when prompted, be sure to select the option to set up redirects from http to https and effectively "disable" http)
    ssl_certificate /etc/letsencrypt/live/; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

server {
    if ($host = {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    listen 80 default_server;
    listen [::]:80 default_server;
    return 404; # managed by Certbot
Enter fullscreen mode Exit fullscreen mode
dgloriaweb profile image

Hi, I've set this up to use and port 8081 (not sure if this is required).
If I call the usual request that worked on localhost, I get 404 error in postman.
Note, I've added the A record on Digitalocean as hostname:, will direct to: .
I would like to use the same domain name with a subdomain or alias or anything like that. Thanks.

tythos profile image
Brian Kirkpatrick

Great stuff. Seems like every day I learn about a new nginx feature that changes everything.