Script to generate that maintenance.html file for taking my websites into maintenance mode

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.

Website Pin Facebook Twitter Myspace Friendfeed Technorati del.icio.us Digg Google StumbleUpon Premium Responsive

Leave a Comment

Scroll to Top