In a recent blog post, I showed you how I was taking my websites into maintenance mode. Shortly afterwards, I wrote about how using $server_name can have odd consequences. Today, I’m writing about the script I just created which will create those maintenance.html files.
In this post:
- FreeBSD 15.0
- nginx 1.28.2
- bourne shell
The script
This is the script:
[12:17 r720-02-proxy01 dvl /usr/local/www/offline] % cat ~/bin/offline
#!/bin/sh
# Usage: ~/bin/offline foo.bar "$(date -R -v +2H)"
# see -v option on man date: [y|m|w|d|H|M|S]
website=$1
retryafter=$2
OFFLINE_DIR="/usr/local/www/offline"
# slight santization
hostname=$(basename $website)
tmpfile=$(mktemp /tmp/offline.XXXXXX)
cat << EOF >> $tmpfile
html>
<head>
<title>Error 503 Service Unavailable</title>
</head>
<body>
<h1>503 Service Unavailable</h1>
<p>Server is offline for maintenance.</p>
<p>Please retry after ${retryafter}</p>
</body>
</html>
EOF
cat $tmpfile
sudo chown root:wheel $tmpfile
sudo chmod 0644 $tmpfile
sudo mv -i $tmpfile "${OFFLINE_DIR}/${hostname}-maintenance.html"
rm -f $tmpfile
Yes, the rm is not necessary, since the file has already been moved.
To invoke the script, I do something like this:
% ~/bin/offline dev.freshports.org "$(date -R -v +2H)" html> <head> <title>Error 503 Service Unavailable</title> </head> <body> <h1>503 Service Unavailable</h1> <p>Server is offline for maintenance.</p> <p>Please retry after Sat, 14 Mar 2026 14:20:59 +0000</p> </body> </html>
In the command, I’m saying it will be offline for two hours.
In my browser, I see this:
503 Service Unavailable Server is offline for maintenance. Please retry after Sat, 14 Mar 2026 14:20:59 +0000
With wget, I see:
[12:23 nagios04 dvl ~/tmp] % wget -S https://dev.freshports.org --2026-03-14 12:24:14-- https://dev.freshports.org/ Resolving dev.freshports.org (dev.freshports.org)... 173.228.145.171, 2610:1c0:2000:11:8870:201b:27b5:f4f2 Connecting to dev.freshports.org (dev.freshports.org)|173.228.145.171|:443... connected. HTTP request sent, awaiting response... HTTP/1.1 503 Service Temporarily Unavailable Server: nginx/1.28.2 Date: Sat, 14 Mar 2026 12:24:14 GMT Content-Type: text/html Content-Length: 223 Connection: keep-alive ETag: "69b55317-df" Retry-After: 120 2026-03-14 12:24:14 ERROR 503: Service Temporarily Unavailable.
If you check carefully, you’ll see there is a Retry-After in the headers. That differs from the message within the webpage. Why?
Why?
The webpage is constructed from that offline script and is a string in the webpage. Ideally, both that and the header would show the same value. However, I don’t know how to easily do that yet.
Where does the header come from?
I recently modified the nginx configuration for this website. The new bit is the add_header as seen below. The always tag needs to be there. The docs mention it, but I didn’t pick it up. It took a blog post by Claudio Kuenzlerfor me to add it in.
# but wait, there's more!
location @maintenance {
rewrite ^(.*)$ /${maint} break;
add_header Retry-After "120" always;
}
It would be nice to update the website configuration to adjust the “120” value to match the webpage.
That sounds like an Ansible solution.
Going back online
Going back online involves removing the file. I figure that’s easy enough to not need a script.











