Files
nginx-configs/README.md
T
hikari db36f98578
Test nginx configuration / Static Analysis (push) Successful in 5s
Test nginx configuration / nginx Syntax Check (push) Successful in 18s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 2m39s
refactor: restructure nginx config into per-app files (#1)
## Summary

- Added `push.sh` script to deploy configs to prod via `sudo rsync` (with `--delete` for exact mirroring)
- Split the monolithic `conf.d/server.conf` (1,682 lines, 96 server blocks) into 28 per-app files under `sites-available/`, with corresponding symlinks in `sites-enabled/`
- Extracted custom `nginx.conf` settings (`log_format` directives, `server_names_hash_bucket_size`) into dedicated `conf.d/logging.conf` and `conf.d/tuning.conf` files, leaving `nginx.conf` as close to stock as possible

## Test plan

- [x] `sudo nginx -t` passes on prod after the sites-available restructure

 This PR was created with help from Hikari~ 🌸

Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Reviewed-on: #1
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
2026-03-07 02:05:29 -08:00

152 lines
5.1 KiB
Markdown

# Nginx Configs
This repository holds the nginx configuration for NHCarrigan's production server, with scripts for deploying and pulling changes.
## Directory Structure
```
nginx/nginx/ # Maps directly to /etc/nginx/ on the server
├── nginx.conf # Global settings (workers, gzip, TLS, logging)
├── conf.d/
│ ├── cloudflare_ips.conf # Real-IP trust for Cloudflare ranges (auto-updated by cron)
│ ├── logging.conf # Custom log formats (custom_format + json_analytics)
│ └── tuning.conf # Performance tweaks (server_names_hash_bucket_size)
├── sites-available/ # One .conf file per logical group of sites
│ └── *.conf
├── sites-enabled/ # Symlinks to active configs in sites-available/
│ └── * -> ../sites-available/*.conf
└── ... # Standard nginx package files (mime.types, proxy_params, etc.)
```
## Adding a New Site
1. **Identify the right file.** Each `sites-available/*.conf` has a comment at the top describing what belongs there. Pick the most appropriate file, or create a new one if the site does not fit anywhere.
2. **Add the server block**, following this template for a proxied app:
```nginx
server {
listen 443 ssl;
server_name yourapp.nhcarrigan.com;
ssl_certificate /etc/letsencrypt/live/yourapp.nhcarrigan.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourapp.nhcarrigan.com/privkey.pem;
location / {
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:<PORT>;
proxy_redirect off;
}
}
```
Or this template for a static site:
```nginx
server {
listen 443 ssl;
server_name yoursite.nhcarrigan.com;
ssl_certificate /etc/letsencrypt/live/yoursite.nhcarrigan.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yoursite.nhcarrigan.com/privkey.pem;
root /home/naomi/yoursite;
location / {
index index.html;
}
}
```
3. **Keep server blocks sorted alphabetically** by `server_name` within the file. The CI sort check will fail if they are out of order. Note that hyphenated names sort before the bare domain in C locale (e.g. `app-api` before `app`).
4. **If you created a new `.conf` file**, create the corresponding symlink in `sites-enabled/`:
```bash
cd nginx/nginx/sites-enabled
ln -s ../sites-available/newfile.conf newfile.conf
```
5. **Get the SSL certificate** on the server before deploying:
```bash
sudo certbot certonly --nginx -d yourapp.nhcarrigan.com
```
6. **Run the tests** locally to verify everything passes:
```bash
bash test.sh
```
7. **Deploy** (see below).
## Removing a Site
1. Delete the server block from the relevant `sites-available/*.conf` file.
2. If the entire `.conf` file is now empty, delete the file and its `sites-enabled/` symlink.
3. Run `bash test.sh` to confirm nothing is broken.
4. Deploy.
## Deploying Changes
Push the local `nginx/nginx/` directory to the server (the `--delete` flag removes any files on the server that no longer exist locally):
```bash
bash push.sh
```
Then reload nginx to apply the changes:
```bash
ssh prod "sudo systemctl reload nginx"
```
To pull the current server config back into this repository:
```bash
bash pull.sh
```
## Testing
The test suite runs static analysis checks against the config files without requiring a live nginx instance:
```bash
bash test.sh
```
The following checks are run:
| # | Check |
|---|-------|
| 1 | No deprecated TLS versions (TLSv1 / TLSv1.1) |
| 2 | No duplicate `server_name` values |
| 3 | Every `sites-available/*.conf` has a `sites-enabled` symlink |
| 4 | No broken symlinks in `sites-enabled` |
| 5 | No orphaned symlinks in `sites-enabled` |
| 6 | No port-80 listeners in custom server blocks |
| 7 | `ssl_certificate` and `ssl_certificate_key` counts match per file |
| 8 | All plain-HTTP `proxy_pass` targets are local |
| 9 | All SSL cert paths use `/etc/letsencrypt/live/` |
| 10 | Certs use `fullchain.pem` / keys use `privkey.pem` |
| 11 | No raw IP addresses as `server_name` |
| 12 | `conf.d` contains only expected files |
| 13 | Server blocks are sorted alphabetically by `server_name` within each file |
CI additionally runs an nginx syntax check (`nginx -t`) using stub SSL certificates, catching any configuration errors that static analysis cannot detect.
## Feedback and Bugs
If you have feedback or a bug report, please [log a ticket on our forum](https://support.nhcarrigan.com).
## Contributing
If you would like to contribute to the project, you may create a Pull Request containing your proposed changes and we will review it as soon as we are able! Please review our [contributing guidelines](CONTRIBUTING.md) first.
## Code of Conduct
Before interacting with our community, please read our [Code of Conduct](CODE_OF_CONDUCT.md).
## License
This software is licensed under our [global software license](https://docs.nhcarrigan.com/#/license).
Copyright held by Naomi Carrigan.
## Contact
We may be contacted through our [Chat Server](http://chat.nhcarrigan.com) or via email at `contact@nhcarrigan.com`.