Lesson 1 of 11 · Fundamentals
Anatomy of a production web server — processes, files and the configuration actually loaded
Objective
Know how nginx and Apache handle connections, where each configuration file lives, and find the configuration actually loaded before you touch anything.
Key points
- nginx runs with one master process (reads the configuration, opens the ports) and workers that each handle thousands of connections in parallel.
- Apache 2.4 uses an MPM:
event(processes + threads, the modern choice) orprefork(one process per connection, only for the oldmod_php). - The file you edit is not always the one that runs:
includedirectives, links insites-enabledand distribution defaults all add up. nginx -Tdisplays the whole loaded configuration, includes and all;apachectl -Slists the virtual hosts that are really active.- Always test (
nginx -t,apachectl configtest), then reload (reload). Do not restart.
1. What happens when a client connects
┌───────────────────────────────┐
navigateur ───► │ processus maître (root) │ lit nginx.conf, ouvre 80/443
│ ├─ worker 1 (www-data) │ ← accepte et traite les connexions
│ ├─ worker 2 (www-data) │
│ └─ worker N (= nb de cœurs) │
└───────────────────────────────┘
(The browser connects; the master process (root) reads nginx.conf and opens 80/443; the workers (www-data) accept and handle the connections; there are N workers, one per CPU core.)
An nginx worker never blocks on a slow client: it moves on to the next one and comes back when data arrives. This is why a small nginx server can hold tens of thousands of open connections.
ps -o pid,user,cmd -C nginx
# PID USER CMD
# 812 root nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
# 813 www-data nginx: worker process
# 814 www-data nginx: worker process
Apache with the event MPM looks like this: a few processes, each with dozens of threads, and a "listener" thread that keeps idle keep-alive connections without tying up a worker thread.
apachectl -V | grep -i mpm # Server MPM: event
apachectl -M | grep mpm # mpm_event_module (shared)
2. Where the files are
| Item | nginx (Debian/Ubuntu) | nginx (Rocky) | Apache (Debian/Ubuntu) | Apache (Rocky) |
|---|---|---|---|---|
| Main file | /etc/nginx/nginx.conf |
same | /etc/apache2/apache2.conf |
/etc/httpd/conf/httpd.conf |
| Sites | sites-available/ + links in sites-enabled/ |
conf.d/*.conf |
sites-available/ + a2ensite |
conf.d/*.conf |
| Reusable pieces | snippets/ |
default.d/ |
conf-available/ + a2enconf |
conf.d/ |
| Logs | /var/log/nginx/ |
same | /var/log/apache2/ |
/var/log/httpd/ |
| Worker user | www-data |
nginx |
www-data |
apache |
On Debian and Ubuntu, nginx.conf contains these two lines. They alone decide which sites are loaded.
include /etc/nginx/conf.d/*.conf; # only files ending in .conf
include /etc/nginx/sites-enabled/*; # everything in the directory
Direct consequence: a file ancien.conf.bak in conf.d/ is not loaded, but a file ancien.bak in sites-enabled/ is.
3. Read the configuration actually loaded
nginx -t # syntax OK? (reads every include)
nginx -T | less # everything, file by file (# configuration file …)
nginx -T 2>/dev/null | grep -n 'server_name' # which names are served, and in which file
nginx -T 2>/dev/null | grep -E '^# configuration file' # list of files read
apachectl configtest # Syntax OK
apachectl -S # virtual hosts, port by port, and the default site
apachectl -t -D DUMP_INCLUDES # included files
Example output of apachectl -S:
VirtualHost configuration:
*:80 is a NameVirtualHost
default server www.masterlinux.lab (/etc/apache2/sites-enabled/000-default.conf:1)
port 80 namevhost www.masterlinux.lab (/etc/apache2/sites-enabled/000-default.conf:1)
port 80 namevhost intranet.masterlinux.lab (/etc/apache2/sites-enabled/intranet.conf:1)
4. Test, reload, do not cut
nginx -t && systemctl reload nginx # the master rereads, starts new workers,
# the old ones finish their requests and then stop
apachectl configtest && systemctl reload apache2 # (httpd on Rocky): "graceful" restart
restart cuts every connection in progress. reload does not. And if the new configuration is wrong, reload keeps the old one running. This is why you test before.
5. Real case: "I fixed it, but nothing changes"
At the MasterLinux office in Fès, a technician fixes client_max_body_size in /etc/nginx/sites-available/intranet… in a copy, intranet.old, because the link in sites-enabled pointed to the other file. One hour lost. The reflex that would have solved it in 10 seconds:
nginx -T 2>/dev/null | grep -n -B2 -A2 client_max_body_size
ls -l /etc/nginx/sites-enabled/
Common pitfalls
- Editing the wrong file: always check what is loaded with
nginx -Torapachectl -S. - Leaving backups in
sites-enabled/:site.bakis loaded there and creates duplicateserver_nameentries. restartinstead ofreload: it cuts downloads and WebSocket connections in progress.- Reloading without testing: on Apache, a syntax error can stop the service from starting at the next boot.
Lab
nginx is not installed on your lab machine: you work directly on a prepared /etc/nginx tree, as if you were reading the configuration of an unknown server. You will:
- find the file that serves the shop (boutique);
- disable a site cleanly without losing its configuration;
- rebuild by hand what
nginx -Twould display, following the include rules.
Quiz
- Which nginx process opens ports 80 and 443, and which user do the workers run as on Debian?
- Is a file
test.conf.oldinconf.d/loaded? Andtest.oldinsites-enabled/? - Which command displays the whole nginx configuration actually loaded?
- What is the difference between
reloadandrestartfor connected clients? - Which Apache MPM should you prefer with PHP-FPM?
Answers
- The master process (root); the workers run as
www-data. - No for
conf.d/test.conf.old(the pattern is*.conf); yes forsites-enabled/test.old(the pattern is*). nginx -T.reloadlets requests in progress finish with the old workers;restartcuts everything.event.