I run doclab-nginx as part of my The Doc Labs website setup. This is the detailed operating note for why I use it, how I think about it, how it connects to the rest of the lab, and what I would check when it starts acting wrong.
Table of Contents
What this container does
Nginx is the web front door for my WordPress site. It receives browser traffic, serves static files, and hands PHP requests to the WordPress PHP-FPM container.
The container image is nginx:latest. I document that on purpose because the image tells me where updates come from, what documentation to trust, and what project probably changed if the container starts behaving differently after an update.
Why I use Nginx
I use it because I want the web server separated from the application runtime. That makes the site easier to debug, easier to tune, and easier to move later.
The deeper reason I use containers for this is control. I want every service to have a defined job, defined storage, defined network exposure, and a clear recovery path. If I cannot explain why a container exists, what data it owns, and what depends on it, then the stack becomes clutter instead of infrastructure.
How I set it up
- Mount the WordPress files read/write so Nginx can serve assets from the same codebase WordPress uses.
- Mount the Nginx config as its own file so routing and PHP handling can be changed without rebuilding the image.
- Publish the host web port that the public proxy or tunnel points at.
- Keep PHP execution out of Nginx and send it to the WordPress PHP-FPM container.
The setup pattern is always the same in spirit: the container should be disposable, but the data should not be. The app image can be pulled again. The configuration, media library, database state, workflow history, or uploaded files are the pieces that need to survive.
Docker install shape
This is the public-safe version of the setup shape. It shows the image, port idea, and persistent folders without exposing real secrets, private tokens, API keys, claim strings, or provider credentials.
Nginx fronts the WordPress/PHP-FPM stack. Public config examples should not reveal private upstreams or internal-only routes.
services:
doclab-nginx:
image: nginx:latest
container_name: doclab-nginx
restart: unless-stopped
ports:
- "8088:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- wordpress-html:/var/www/html:ro
On Unraid, the same idea lives in the Docker template: repository/image, WebUI port, appdata config path, storage paths, and environment variables. The container can be replaced; the appdata and service data are the parts that need to survive.
How I use it day to day
- I check it when the site loads slowly, returns gateway errors, or assets do not render.
- I use logs to separate web routing problems from WordPress problems.
- I treat it as the edge layer: headers, redirects, file serving, and PHP pass-through.
Day to day, I try not to treat Docker like a mystery box. I check the service from the app UI, then the container status, then logs, then storage and networking. That order keeps me from randomly restarting things when the real issue is a bad path, a dead dependency, or an expired token.
What it connects to
- WordPress PHP-FPM
- WordPress theme files
- public site routing
- health checks
This matters because most container problems are not isolated. A media request app might be healthy but unable to reach Sonarr. Sonarr might be healthy but unable to reach a downloader. A web app might be healthy but failing because the database is gone. Mapping the connections makes troubleshooting faster.
How I would hook up notifications
- Add an Uptime Kuma HTTP monitor for the homepage.
- Alert on non-200 status codes, long response time, or repeated downtime.
- Route alerts through Telegram, email, Discord, or n8n once the notifier is configured.
My notification rule is simple: alert me when I need to act, not every time something makes noise. For public services, I care about uptime and response time. For automation services, I care about failed jobs and stuck queues. For sensitive services, I care about access, failed updates, and backup verification.
What I monitor
- HTTP status for the homepage
- container health
- Nginx error logs
- disk space for the WordPress mount
The minimum useful monitoring is container state plus one real application check. A container can be running while the app inside is broken, so I prefer checking the actual web endpoint, API health, or workflow behavior whenever possible.
What usually breaks first
- Bad Nginx config
- WordPress container down
- wrong file permissions
- public proxy pointing to the wrong port
When something breaks, I do not start by rebuilding the container. I first ask what changed: an image update, a config edit, a permission change, a moved folder, a full disk, a dead dependency, or an expired credential. Most Docker issues are boring once the dependencies are visible.
Backup and recovery notes
Back up the Nginx config and the WordPress files. The config is small, but it explains how the whole public site is routed.
For recovery, I care about tested restores. A backup that has never been restored is only a guess. The practical goal is to know which folder, volume, database, or config file has to come back first so the service can be rebuilt without panic.
Security notes
Only the web layer should be exposed. Database, cache, and PHP-FPM ports should stay internal unless there is a deliberate reason.
I also avoid publishing secrets in these articles. Public notes can explain the architecture, the purpose, and the operating model without exposing passwords, tokens, private hostnames, tunnel IDs, or anything that gives someone a map to attack the setup.
Bottom line
Nginx earns a place in the lab when it solves a real problem and I can operate it without guessing. The point is not just having a container running. The point is knowing what it does, what depends on it, how I get notified, and how I recover it when something eventually breaks.
How I update it safely
I do not treat container updates like a blind button press. My safe update flow is: check the current container health, read what image is running, confirm backups or appdata are safe, update one service at a time when possible, then verify the web UI, logs, and any connected apps after the container comes back.
- Check whether the container is healthy before touching it.
- Back up appdata or confirm the backup path exists before risky upgrades.
- Update during a quiet window, especially for media and database-backed services.
- Verify the service after update with the UI, logs, and Uptime Kuma or a direct health check.
- If something breaks, roll back the image or restore appdata instead of guessing.