Modular Nginx Configuration: How to Elegantly Manage Multiple Projects with Subdomains

Published: 2025-11-29
Author: DP
Views: 6
Category: Nginx
Content
## The Problem When managing a server that hosts multiple web projects, cramming all configurations into a single `nginx.conf` file quickly becomes messy, difficult to maintain, and hard to troubleshoot. A more elegant and professional approach is to adopt a modular configuration structure, creating separate configuration files for each project. This article, based on a specific set of requirements, will provide a detailed guide on how to build a clean, scalable multi-project configuration for Nginx (using version 1.27.2 as an example). This strategy is widely used in practice by the **DP@lib00** team. **Core Requirements:** 1. All project code is stored in the `/web_root/lib00_projects/` directory, with each project in its own subdirectory (e.g., `projectA`). 2. Each project is accessed via a unique subdomain (e.g., `projectA.wiki.lib00.com`). 3. Nginx listens on a non-standard HTTP port, `55101`. 4. A modular configuration is used, where each project's `server` block is stored in a separate `.conf` file within the `/etc/nginx/project_config/` directory. 5. Provide a configuration solution for testing in a development environment using an IP address (e.g., `192.168.1.2`). --- ## Step 1: Configure the Main `nginx.conf` File The role of the main `nginx.conf` file is to define global settings and act as a "router" that loads all individual project configurations using the `include` directive. This keeps the main file clean and concise. Open or create `/etc/nginx/nginx.conf` and add the following basic content: ```nginx # It's recommended to run Nginx with a non-root user, e.g., www-data user www-data; # Automatically adjust the number of worker processes based on CPU cores worker_processes auto; pid /run/nginx.pid; # Include configurations for dynamic modules if needed # include /etc/nginx/modules-enabled/*.conf; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # Enabling Gzip compression can improve performance # gzip on; # This is the key to modularity! # Nginx will load all files ending with .conf from the specified directory. # We'll place our project configs in a folder named wiki.lib00_project_config include /etc/nginx/wiki.lib00_project_config/*.conf; } ``` **Key Insight:** * **`include /etc/nginx/wiki.lib00_project_config/*.conf;`**: This is the core of the entire modular setup. It tells Nginx to load all `.conf` files from the `wiki.lib00_project_config` directory. This way, whenever you need to add, modify, or delete a project, you only need to work with its corresponding file without touching the main configuration. --- ## Step 2: Create Individual Configuration Files for Projects Now, let's create a separate configuration file for `projectA`. Create the file `/etc/nginx/wiki.lib00_project_config/projectA.conf`: ```nginx server { # Listen on the port we specified in the requirements: 55101 listen 55101; # Bind the project's subdomain server_name projectA.wiki.lib00.com; # Set the website's root directory root /web_root/lib00_projects/projectA; # Set the default index files index index.html index.htm; location / { # Try to find a file in order: $uri (file) -> $uri/ (directory) -> return 404 # This is crucial for handling routing in Single Page Applications (SPAs) try_files $uri $uri/ =404; } # You can add extra configurations for specific projects, like logs, access control, etc. access_log /var/log/nginx/projectA-access.log; error_log /var/log/nginx/projectA-error.log; } ``` If you have another project, `projectB`, simply copy this file to create `projectB.conf` and change the `projectA`-related names and paths to `projectB`. This approach dramatically improves the maintainability of your configuration. --- ## Step 3: Configure IP-Based Access for Development During the development phase, subdomains might not be resolved yet. We often need to access projects using the server's IP address for testing. We can create a dedicated `server` block for this purpose. In the same `/etc/nginx/wiki.lib00_project_config/` directory, create a test configuration file, for example, `dev-test.conf`: ```nginx server { # Listen on the same 55101 port listen 55101; # Key point: Use the server's IP address as the server_name # When a request comes to http://192.168.1.2:55101, Nginx will match this server block server_name 192.168.1.2; # Point the request to projectA's root directory root /web_root/lib00_projects/projectA; index index.html index.htm; location / { try_files $uri $uri/ =404; } # It's a good practice to use separate log files for the test environment access_log /var/log/nginx/dev-test-access.log; error_log /var/log/nginx/dev-test-error.log; } ``` **How It Works:** When a user accesses `http://192.168.1.2:55101`, Nginx checks the `Host` request header. Even if the browser doesn't send a `Host` header or sends the IP address, by explicitly listing the IP in `server_name`, Nginx can accurately route these requests to the `projectA` codebase. --- ## Conclusion By adopting a modular approach using the `include` directive to separate configuration files, we have successfully built a clean, scalable, and easy-to-maintain Nginx configuration structure for a multi-project environment. This practical experience from **wiki.lib00.com** not only makes daily management more efficient but also simplifies troubleshooting. Whether for production or development testing, this structure offers significant convenience.