`if` or `include` for mode-specific `server` directives?

petecooper nginx-forum at forum.nginx.org
Sat May 16 09:24:42 UTC 2020

I compile Nginx mainline from source and update every release. I run a small
fleet of open source project and some small business Linux servers with
multiple websites per server. There are occasions when a site is taken down
for maintenance (typically minutes or hours of downtime out of peak hours),
or is under development for extended periods, and also when 'normal'
production status is happening. I use a different directory for each mode,
so there is separation of files etc. A typical setup looks like this:

/var/www/sites/example.com/subdomain/live/ (production mode)
/var/www/sites/example.com/subdomain/holding/ (under construction, coming
/var/www/sites/example.com/subdomain/maintenance/ (back soon)

At present, each site is managed by a monolithic
`subdomain.example.com.conf` file with its own `server` block and associated
directives. I manually change the `root` for each state when a site changes
mode. The current modes are:

* live (production) state serves files as usual, no changes.
* holding (under construction) state presents HTTP 503 Service Unavailable
status with relatively long Retry-After response header.
* maintenance (back soon) state presents HTTP 503 Service Unavailable status
with relatively short Retry-After response header.

Each site has a unique variable namespace and its own mode (live, holding,
maintenance), like this:

server {
    set $fqdn_abcd1234 'subdomain.example.com';
    set $status_abcd1234 'live';

I would like to change the operation to include some extra, browser-friendly
functionality and to make better use of site variables.

Two of the three modes above have a Retry-After header, and each of those
has a different time value. This gives me a few potential routes to contend
with, and I would be grateful for your advice on feedback on what is
considered current best practice.

== `if` in the `server` block ==

I will readily admit I have never used `if`, having been scared away by If
Is Evil. My (untested) approach looks like this:

server {
    set $fqdn_abcd1234 'subdomain.example.com';
    set $status_abcd1234 'live';
    root /var/www/sites/example.com/subdomain/$status_abcd1234/;
    if ($status_abcd1234 = 'holding') {
        return 503;
        add_header Retry-After 604800 always;
    if ($status_abcd1234 = 'maintenance') {
        return 503;
        add_header Retry-After 10800 always;

So, two inlined `if` inside a monolithic `server` block file.

== Stub `server` excerpts for each mode ==

Rather than include `root` and `if` checks in the monolithic `server` block
file, I am considering outboarding each mode to its own stub file as a
sidecar to the main `server` block file, like this:

* `subdomain.example.com--live.conf`
* `subdomain.example.com--holding.conf`
* `subdomain.example.com--maintenance.conf`

Each site mode stub would include the relevant `return` and `add_header`
directives as required, plus any other mode-specific things, and be called
by an `include` directive in the main `server` block file. No `if` involved
in this route.

== Something else I haven't thought of ==

You folks are much smarter than me. I am certain I've missed something,
whether it's obvious or not. What else might I be able to do in this
scenario, please?

Given the above routes, which is (subjectively / objectively) better from an
Nginx point of view?

Thank you for reading, and best wishes to you from sunny Cornwall, United


Posted at Nginx Forum: https://forum.nginx.org/read.php?2,288057,288057#msg-288057

More information about the nginx mailing list