Skip to main content

Directory Structure

Learning Focus

Leave this lesson with a working understanding of directory structure that you can apply immediately in production.

Knowing where every file lives is essential for fast troubleshooting and clean config management.

Yazi Navigation

Browse the config tree interactively:

yazi /etc/nginx/

Use l to open dirs, h to go back, q to quit.


Full Layout

/etc/nginx/
├── nginx.conf # Main config — global settings, includes
├── conf.d/ # Drop-in server block configs (*.conf auto-loaded)
│ └── default.conf # Default server block (RHEL-family)
├── sites-available/ # All site configs (Debian/Ubuntu pattern)
│ └── example.com.conf # Inactive until symlinked to sites-enabled
├── sites-enabled/ # Symlinks to active sites
│ └── example.com.conf -> ../sites-available/example.com.conf
├── snippets/ # Reusable config fragments
│ ├── fastcgi-php.conf # FastCGI PHP pass snippet
│ └── snakeoil.conf # Self-signed cert snippet (Debian)
├── modules-enabled/ # Dynamic module configs (Debian)
├── modules-available/ # Available module configs
├── fastcgi_params # FastCGI parameter set (classic)
├── fastcgi.conf # FastCGI params + SCRIPT_FILENAME
├── uwsgi_params # uWSGI parameter set
├── scgi_params # SCGI parameter set
├── mime.types # MIME type → file extension mappings
├── koi-win # Legacy charset maps
├── koi-utf # Legacy charset maps
└── win-utf # Legacy charset maps

/var/log/nginx/
├── access.log # All HTTP requests
└── error.log # Errors — check this FIRST

/var/www/html/ # Default web root (Debian/Ubuntu)
/usr/share/nginx/html/ # Default web root (RHEL/AlmaLinux)

/run/nginx.pid # Master process PID (or /var/run/nginx.pid)
/usr/sbin/nginx # Nginx binary

/usr/lib/nginx/modules/ # Dynamic modules (.so files)
/etc/nginx/modules-enabled/ # Symlinks to enabled module configs (Debian)

Key Files — What They Do

nginx.conf — Master Config

The entry point for all configuration. It sets global worker settings, the events {} block, and includes the http {} block with all site configs.

# View it
sudo cat /etc/nginx/nginx.conf

# Edit it
sudo vim /etc/nginx/nginx.conf

# Search for include statements (see what gets loaded)
grep "include" /etc/nginx/nginx.conf

conf.d/ vs sites-available/ + sites-enabled/

These are two organizational patterns — both valid:

PatternWhereActivation
conf.d//etc/nginx/conf.d/*.confAll .conf files auto-loaded
sites-available/ + sites-enabled//etc/nginx/sites-available/Symlink to sites-enabled/

The symlink pattern lets you keep inactive configs around without loading them.

# Enable a site (Debian pattern)
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

# Disable a site
sudo rm /etc/nginx/sites-enabled/example.com

# Verify which sites are enabled
ls -la /etc/nginx/sites-enabled/

snippets/ — Reusable Fragments

Store repeated config blocks here and include them:

# In a server block
include /etc/nginx/snippets/fastcgi-php.conf;
include /etc/nginx/snippets/ssl-params.conf;

fastcgi_params vs fastcgi.conf

Both set FastCGI parameters for PHP-FPM. The difference:

  • fastcgi_params — does not include SCRIPT_FILENAME (you must add it manually)
  • fastcgi.conf — includes SCRIPT_FILENAME (usually prefer this)
# Using fastcgi.conf (simpler)
include fastcgi.conf;

# Using fastcgi_params (you must also add):
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

CLI Exploration Commands

# Full config tree
sudo find /etc/nginx -type f | sort

# List all active configs (everything included)
sudo nginx -T | head -100

# Find all server_name directives across all configs
sudo grep -rn "server_name" /etc/nginx/

# Find all listen directives
sudo grep -rn "^[[:space:]]*listen" /etc/nginx/

# Find all root/alias directives
sudo grep -rn "root\|alias" /etc/nginx/conf.d/ /etc/nginx/sites-enabled/

# Find all fastcgi_pass lines (PHP-FPM connections)
sudo grep -rn "fastcgi_pass" /etc/nginx/

# Find all proxy_pass lines (reverse proxy connections)
sudo grep -rn "proxy_pass" /etc/nginx/

# Check which modules are loaded
nginx -V 2>&1 | tr -- - '\n' | grep module

Log Access

# Live error log (most useful for debugging)
sudo tail -f /var/log/nginx/error.log

# Live access log
sudo tail -f /var/log/nginx/access.log

# Filter errors from the last hour
sudo awk -v d="$(date '+%d/%b/%Y:%H')" '$0 ~ d' /var/log/nginx/error.log | grep -i error

# Log size check
du -sh /var/log/nginx/

# Per-site logs (if configured)
ls /var/log/nginx/

PID File

# Get master process PID
cat /run/nginx.pid

# Or
cat /var/run/nginx.pid

# Kill signals to master process (safer than systemctl in some cases)
sudo kill -HUP $(cat /run/nginx.pid) # Graceful reload (same as nginx -s reload)
sudo kill -QUIT $(cat /run/nginx.pid) # Graceful shutdown
sudo kill -TERM $(cat /run/nginx.pid) # Fast shutdown
sudo kill -USR1 $(cat /run/nginx.pid) # Reopen log files

Hands-On Practice

# Verify Nginx is running
sudo systemctl status nginx

# Test config syntax
sudo nginx -t

# Reload without downtime
sudo nginx -s reload

# Check error log
sudo tail -20 /var/log/nginx/error.log

Common Pitfalls

PitfallWhat happensFix
Editing config without reloadingChanges not appliedsudo nginx -s reload after every edit
Not running nginx -t firstReload breaks with syntax errorAlways test syntax before reloading
Wrong socket path for PHP-FPM502 Bad Gatewayls /run/php/ and verify the exact socket filename

What's Next

  • Continue to the next lesson in this module, or go to the module index for an overview.
  • Use the Cheatsheets for quick CLI reference.