Nginx Scripts and Tools

We use the following scripts for various tasks related to our web server. Most of them are run fully automated and regularly as cron jobs on the server, while others are called on demand.

Static Compression

Nginx can be set to serve pre-compressed versions of static files like HMTL- files, CSS stylesheets, script-files. etc. instead of compressing them on-the- fly while sending them to clients.

The following script will try to find static files in the website and pre- compress them for Nginx to to send out.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/bin/bash
#
# Pre-compress static web resources
#
# To be started by cron every few hours
#
# For monitoring use the following command:
#
#   journalctl -t ngx_pre_compress -p <level> --no-tail -f
#
# while <level> may be any of debug, info, notice or warning

# Exit on errors
set -e
# Exit on undefined variable
set -u

NGINX_USER='www-data'
NGINX_GROUP='www-data'
NGINX_CMD='/usr/sbin/nginx'
GZIP_CMD='/bin/gzip'
BROTLI_CMD='/usr/bin/brotli'
# See /etc/nginx/mime.types
FILETYPES='en html htm shtml css xml js atom rss mml txt wml json doc ps rtf xls ppt run pl docx xlsx pptx'

# Log to syslog
log()
{
    logger -t ngx_pre_compress --priority user.${1} ${2}
}

# We need to be root
if [[ ${UID} -gt 0 ]]; then
    log 'error' "Sorry, need to be root"
    echo "Sorry, need to be root"
    exit 1
fi

# Fix sorting
LC_ALL=C

# Start
log 'notice' "Starting pre-compression of files for Nginx."

# Get document root and alias directories from current Nginx configuration
webdirs=$( ${NGINX_CMD} -qT | \
                        grep --only-matching --extended-regexp \
                            "^\s*(root|alias)\s+((/*.)+)" | \
                        grep --only-matching --extended-regexp \
                            "(/[a-zA-Z0-9/_\.]+)" | \
                        sort --unique
                  )
total_dirs=0
total_files=0
total_br_new=0
total_gz_new=0
total_br_updates=0
total_gz_updates=0

dir_files=0
dir_br_new=0
dir_br_updates=0
dir_gz_new=0
dir_gz_updates=0

#
# Create compressed versions

# Walk directories
for dir in ${webdirs};
do

    # Is this a directory?
    if [[ -d ${dir} ]]; then

        log 'info' "Looking for files to pre-compress in ${dir} ..."
        total_dirs=$((total_dirs+1))
        dir_files=0
        dir_br_new=0
        dir_br_updates=0
        dir_gz_new=0
        dir_gz_updates=0

        #echo -n "Searching for "

        # Walk the list of filetypes
        for filetype in ${FILETYPES};
        do
            #echo -n "${filetype} "

            # Find files
            while IFS= read -r -d '' file;
            do

                dir_files=$((dir_files+1))

                # Does it have a Brotli companion?
                if [[ -f "${file}.br" ]]; then

                    # Is it outdated?
                    if [[ "${file}" -nt "${file}.br" ]]; then

                        # Refresh the Brotli companion
                        dir_br_updates=$((dir_br_updates+1))
                        ${BROTLI_CMD} --force --input "${file}" --output "${file}.br"

                        # Set file time, owner, access rights from original
                        chown --reference="${file}" "${file}.br"
                        chmod --reference="${file}" "${file}.br"
                        touch --reference="${file}" "${file}.br"
                    fi
                else

                    # Create new Brotli companion
                    dir_br_new=$((dir_br_new+1))
                    ${BROTLI_CMD} --input "${file}" --output "${file}.br"

                    # Set file time, owner, access rights from original
                    chown --reference="${file}" "${file}.br"
                    chmod --reference="${file}" "${file}.br"
                    touch --reference="${file}" "${file}.br"
                fi

                # Does it have a Gzip companion?
                if [[ -f "${file}.gz" ]]; then

                    # Is it outdated?
                    if [[ "${file}" -nt "${file}.gz" ]]; then

                        # Refresh the GZip companion
                        dir_gz_updates=$((dir_gz_updates+1))
                        ${GZIP_CMD} --keep "${file}"

                        # Set file time, owner, access rights as the original
                        chown --reference="${file}" "${file}.gz"
                        chmod --reference="${file}" "${file}.gz"
                        touch --reference="${file}" "${file}.gz"
                    fi
                else

                    # Create a new GZip companion
                    dir_gz_new=$((dir_gz_new+1))
                    ${GZIP_CMD} --keep "${file}"

                    # Set file time, owner, access rights as the original
                    chown --reference="${file}" "${file}.gz"
                    chmod --reference="${file}" "${file}.gz"
                    touch --reference="${file}" "${file}.gz"
                fi
            done < <(find "${dir}" -type f -name "*.${filetype}" -print0)
        done
        #echo
        log 'info' "Files processed: ${dir_files}"
        log 'info' "New Brotlis created: ${dir_br_new}"
        log 'info' "Outdated Brotlis updated: ${dir_br_updates}"
        log 'info' "New GZips created: ${dir_gz_new}"
        log 'info' "Outdated GZips updated: ${dir_gz_updates}"
        total_files=$((total_files+dir_files))
        total_br_new=$((total_br_new+dir_br_new))
        total_br_updates=$((total_br_updates+dir_br_updates))
        total_gz_new=$((total_gz_new+dir_gz_new))
        total_gz_updates=$((total_gz_updates+dir_gz_updates))
    else
        echo "${dir} is not a directory."
    fi
done
log 'info' "Total Directories processed: ${total_dirs}"
log 'info' "Total Files processed: ${total_files}"
log 'info' "Total New Brotlis created: ${total_br_new}"
log 'info' "Total Outdated Brotlis updated: ${total_br_updates}"
log 'info' "Total New GZips created: ${total_gz_new}"
log 'info' "Total Outdated GZips updated: ${total_gz_updates}"

# End
log 'notice' " pre-compression of files for Nginx complete. Have a nice day."

OCSP Staples

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#!/bin/bash
#
# OCSP response files creation for stapling in Nginx
#
# To be started by cron every few hours
#
# For monitoring use the following command:
#
#   journalctl -t ngx_ocsp_staples -p <level> --no-tail -f
#
# while <level> may be any of debug, info, notice or warning
#

# Exit on errors
set -e

CERTS_DIRS='/etc/dehydrated/ec_certs /etc/dehydrated/rsa_certs'
OPENSSL_CMD='/opt/openssl-1.1.0e/bin/openssl'
NGINX_CMD='/usr/sbin/nginx'
OCSP_REQ_OPTIONS='-no_nonce -sha256'

# Log to syslog
log()
{
    logger -t ngx_ocsp_staples --priority user.${1} ${2}
}

log 'notice' "Starting to create Nginx OCSP repsonse files ..."

# We need to be root
if [[ ${UID} -gt 0 ]]; then
    log 'error' "Sorry, need to be root"
    echo "Sorry, need to be root"
    exit 1
fi

# Reload Nginx only on changed repsonse files
NGINX_RELOAD=false

for certs_dir in ${CERTS_DIRS}; do

    # Walk the certificates directory
    for cert_dir in ${certs_dir}/*; do

        # Is it a directory?
        if [[ -d "${cert_dir}" ]]; then

            log 'info' "Getting OCSP repsonse for ${cert_dir} ..."

            cd ${cert_dir}

            timestamp="$( date +%s )"
            cert_file="cert.pem"
            issuer_cert_file="chain.pem"
            ca_cert_file="${issuer_cert_file}"
            response_file="ocsp_response.der"

            # Do we have a certificate?
            if [[ -f "${cert_file}" ]]; then

                cert_subject=$( ${OPENSSL_CMD} x509 -in ${cert_file} -noout -subject )
                log 'info' "Certificate file for ${cert_subject} found."

            else

                log 'warning' "No certificate file in ${cert_dir} found, skipping."
                continue

            fi

            # Do we have an issuer certficate chain file?
            if [[ -f "${issuer_cert_file}" ]]; then

                issuer_cert_subject=$(
                    ${OPENSSL_CMD} x509 -in ${issuer_cert_file} -noout -subject
                )
                log 'info' "Issuer certificate file of ${issuer_cert_subject} found."

            else

                log 'warning' "No issuer certificate file for ${cert_subject} found, skipping."
                continue

            fi

            # Get the OCSP URI
            ocsp_uri=$(
                ${OPENSSL_CMD} x509 -in ${cert_file} -noout -ocsp_uri
            )

            # Get the Hostname out of the URI
            ocsp_host=$(
                echo ${ocsp_uri} | sed -e '\,^[hH][tT][tT][pP]://\([^/]*\).*,!d
                    s//\1/;s/.*@//
                    s/.*://'
            )

            # Do we already have an OCSP Response file?
            if [[ -L "${response_file}" ]]; then

                # Validate it
                log 'info' "Existing OSCP response file found, validating ..."
                ocsp_verification=$(
                    ${OPENSSL_CMD} ocsp \
                        -issuer ${issuer_cert_file} \
                        -VAfile ${ca_cert_file} \
                        -cert ${cert_file} \
                        -respin ${response_file} \
                        -no_nonce 2>&1
                )
                export RC=$?
                log 'debug' "OpenSSL returns ${RC}: ${ocsp_verification}"

                if [[ ${RC} -eq 0 ]] ; then

                    # Has it expired?
                    if [[ ${ocsp_verification} = *'WARNING: Status times invalid'* ]]
                    then
                        log 'notice' "OCSP repsonse file has expired, removing ..."
                        rm ${response_file}

                    else

                        log 'info' "Existing OSCP response file is valid, skipping."
                        continue
                    fi

                else

                    log 'notice' "OCSP repsonse file does not validate, removing ..."
                    rm ${response_file}

                fi

            else

                log 'info' "No previous OCSP repsonse file found."

            fi

            # Don't hammer the OCSP server
            sleep 5

            # Do the OCSP request
            log 'notice' "Contacting ${ocsp_host} for validation of ${cert_subject} ..."
            ocsp_response=$(
                ${OPENSSL_CMD} ocsp \
                    -issuer ${issuer_cert_file} \
                    -CAfile ${ca_cert_file} \
                    -VAfile ${ca_cert_file} \
                    -cert ${cert_file} \
                    -url ${ocsp_uri} \
                    -header "HOST" "${ocsp_host}" \
                    ${OCSP_REQ_OPTIONS} \
                    -respout ocsp_response-${timestamp}.der 2>&1
                )
            export RC=$?
            log 'debug' "OpenSSL returns ${RC}: ${ocsp_response}"

            # Has a new response file been created?
            if [[ -f "ocsp_response-${timestamp}.der" ]]; then

                # Read, check and verify it
                log 'info' "New OSCP response file ocsp_response-${timestamp}.der created, validating ..."
                ocsp_verification=$(
                    ${OPENSSL_CMD} ocsp \
                        -issuer ${issuer_cert_file} \
                        -VAfile ${ca_cert_file} \
                        -cert ${cert_file} \
                        -respin ocsp_response-${timestamp}.der \
                        -no_nonce 2>&1
                )
                export RC=$?
                log 'debug' "OpenSSL returns ${RC}: ${ocsp_verification}"
                if [[ ${RC} -eq 0 ]] ; then

                    log 'notice' "New OSCP response file for ${cert_subject} is valid, installing..."

                    # Update symlink
                    ln --force --symbolic ocsp_response-${timestamp}.der \
                        ${response_file}

                    # Nginx will be reloaded
                    NGINX_RELOAD=true

                else

                    log 'error' "Created OCSP repsonse file ocsp_response-${timestamp}.der does not validate, skipping."
                    continue

                fi

            else

                log 'error' "OCSP response file  ocsp_response-${timestamp}.der creation failed, skipping."
                continue

            fi

        else

            log 'info' "${cert_dir} is not a directory, skipping ..."

        fi

    done

done

# Do we have to reload Nginx?
if [[ ${NGINX_RELOAD} == true ]]; then

    # Test Server configuration
    log 'info' "Checking Nginx server configuration ..."
    ${NGINX_CMD} -tq

    # Restart Nginx
    log 'notice' "Relaoding Nginx server ..."
    ${NGINX_CMD} -s reload

else

    log 'info' "Nginx server does not need to reload"

fi

log 'notice' "Nginx OCSP repsonse files creation complete. Have a nice day."

TLS Session Key Rotation

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/bin/bash
#
# SSL Session ticket key rotation
# for Nginx virtual servers
#
# To be started by cron every few hours
#
# For monitoring use the following command:
#
#   journalctl -t ngx_key_rotation -p <level> --no-tail -f
#
# while <level> may be any of debug, info, notice or warning
#
# See also:
# https://github.com/Fleshgrinder/nginx-session-ticket-key-rotation
#

# Exit on errors
set -e

NGINX_USER='www-data'
NGINX_GROUP='www-data'
KEYS_DIR='/etc/nginx/tls_session_keys'
KEY_DISCARD=24 # Time until a key will be discarded (in hours)
KEY_EXPIRE=8 # Time until a fresh key will be created (in hours)
KEY_SIZE=48 # 80 bytes for AES256 or 48 byte for AES128 encryption
OPENSSL_CMD='/usr/bin/openssl'
NGINX_CMD='/usr/sbin/nginx'

# Add default site to servers list
VIRTUAL_SERVERS="${VIRTUAL_SERVERS} default_server"

# Log to syslog
log()
{
    logger -t ngx_key_rotation --priority user.${1} ${2}
}

# Create new random key
generate_key()
{

    ${OPENSSL_CMD} rand ${KEY_SIZE} > ${1}
    chown ${NGINX_USER}:${NGINX_GROUP} ${1}
    chmod 660 ${1}
}

# Start
log 'notice' "Starting Nginx TLS/SSL session key rotation."

# We need to be root
if [[ ${UID} -gt 0 ]]; then
    log 'error' "Sorry, need to be root"
    echo "Sorry, need to be root"
    exit 1
fi

# Fix sorting
LC_ALL=C

# Reload Nginx only on keys change
NGINX_RELOAD=false

# Get primary virtual server names from Nginx configuration
VIRTUAL_SERVERS=$( ${NGINX_CMD} -qT | \
                        grep --only-matching --extended-regexp \
                            "^\s*server_name\s+((\w|-|\.)+)" | \
                        grep --only-matching --extended-regexp \
                            "(\w|-|\.)+$" | \
                        sort --unique
                  )

# Create the directory for storing the keys
mkdir -p ${KEYS_DIR}
chown ${NGINX_USER}:${NGINX_GROUP} ${KEYS_DIR}
chmod 770 ${KEYS_DIR}

# Walk the list of virtual servers
for SERVER_NAME in ${VIRTUAL_SERVERS}; do

    log 'debug' "Checking Nginx TLS session keys for ${SERVER_NAME}"

    # Walk trough keys
    for KEY_NUM in 3 2 1 ; do

        KEYFILE="${KEYS_DIR}/${SERVER_NAME}.${KEY_NUM}.key"

        # Do we already have this key
        if [[ -f ${KEYFILE} ]]; then

            log 'debug' "Nginx session key ${KEY_NUM} for ${SERVER_NAME} found."
            KEY_TIME=$( date +'%s' -r ${KEYFILE} )
            KEY_EXPIRE_TIME=$(  date +%s --date="@$(( ${KEY_TIME} + ( ${KEY_EXPIRE}  * 60 * 60 * ${KEY_NUM} ) ))" )
            KEY_DISCARD_TIME=$( date +%s --date="@$(( ${KEY_TIME} + ( ${KEY_DISCARD} * 60 * 60 ) ))" )

            # Has it reached its end of life?
            if [[ ${KEY_TIME} -ge $(( ${KEY_DISCARD_TIME} - 30 )) ]]; then
                log 'info' "Nginx session key ${KEY_NUM} for ${SERVER_NAME} has reached EOL, removing..."
                rm ${KEYFILE}

            fi

            # Key number lesser then 3?
            if [[ ${KEY_NUM} -lt 3 ]]; then

                # Has it reached its expiration time?
                if [[ $( date +'%s') -ge $(( ${KEY_EXPIRE_TIME} - 30 )) ]]; then

                    log 'info' "Nginx session key ${KEY_NUM} for ${SERVER_NAME} has expired, moving..."
                    EXP_KEYFILE="${KEYS_DIR}/${SERVER_NAME}.$(( ${KEY_NUM} + 1 )).key"
                    cp --force --preserve=mode,ownership,timestamps ${KEYFILE} ${EXP_KEYFILE}
                    RELOAD_NGINX=true

                    # Key number 1?
                    if [[ ${KEY_NUM} -eq 1 ]]; then

                        log 'info' "Generating fresh Nginx session key ${KEY_NUM} for ${SERVER_NAME} ..."
                        generate_key ${KEYFILE}
                        RELOAD_NGINX=true

                    fi

                fi

            fi

        else

            log 'notice' "No Nginx session key ${KEY_NUM} for ${SERVER_NAME} found. Generating ..."
            generate_key ${KEYFILE}
            RELOAD_NGINX=true

        fi

    done

    # Do we already have this key
    if [[ ! -f ${KEYFILE} ]]; then

        log 'warn' "No Nginx session key ${KEY_NUM} for ${SERVER_NAME} found. Generating ..."
        generate_key ${KEYFILE}
        RELOAD_NGINX=true

    fi

done

# Cleanup, remove anything older then 48 hours
#find ${KEYS_DIR} -type f -mmin +$(( ${KEY_DISCARD} * 2 * 60 ))

# Do we have to reload Nginx?
if [[ ${RELOAD_NGINX} == true ]]; then

    log 'notice' "Nginx server needs to be reloaded ..."

    # Test Server configuration
    log 'info' "Checking Nginx server configuration ..."
    ${NGINX_CMD} -tq

    # Restart Nginx
    log 'info' "Relaoding Nginx server ..."
    ${NGINX_CMD} -s reload

fi

log 'notice' "Nginx TLS/SSL session key rotation complete. Have a nice day."

Tor Exit Nodes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/bin/bash
#
# Create Nginx map file of Tor Exit Nodes
#

# Bail-out on errors
#set -e

# Settings
MY_IP=$( curl -s --fail --ipv4 http://v4.ipv6-test.com/api/myip.php )
MY_PORT=443
FETCH_URL="https://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=${MY_IP}&port=${MY_PORT}"
MAP_FILE='/etc/nginx/tor-exit-nodes.map'

# Log to syslog
log()
{
    logger -t ngx_tor_exits --priority user.${1} ${2}
}

valid_ip()
# Test an IP address for validity:
# Usage:
#      valid_ip IP_ADDRESS
#      if [[ $? -eq 0 ]]; then echo good; else echo bad; fi
#   OR
#      if valid_ip IP_ADDRESS; then echo good; else echo bad; fi
#
{
    local  ip=$1
    local  stat=1

    if [[ ${ip} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        OIFS=${IFS}
        IFS='.'
        ip=(${ip})
        IFS=${OIFS}
        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
            && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
        stat=$?
    fi
    return ${stat}
}

TMP_DL_FILE=$( mktemp )
TMP_MAP_FILE=$( mktemp )

# Fetch the list
log 'notice' "Fetching Tor Exit Nodes ..."
the_list=$( curl -s --fail --remote-time --remote-time ${MAP_FILE} --url ${FETCH_URL} )
log 'notice' "Done fetching Nodes"

# Set the field separator to new line
IFS=$'\n'

while read -r line; do
    valid_ip ${line}
    if [[ $? -eq 0 ]]; then
        line+=' true;'
    else
        line="##${line}"
    fi
    echo ${line} >> ${TMP_MAP_FILE}
done <<< "${the_list}"

# Remove old backups
find /etc/nginx/ -name tor-exit-nodes.map.~* -delete

# Install
log 'notice' "Installing fresh node list ${MAP_FILE} ..."
/usr/bin/install --backup=numbered --mode=0664 --preserve-timestamps \
    ${TMP_MAP_FILE} ${MAP_FILE}

Connect Servers

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/bin/bash
#
# Connect to all our virutal servers
#

# Exit on errors
set -e
# Return pipe errors
set -o pipefail
# Error on undefined variables
#set -u

NGINX_CMD='/usr/sbin/nginx'
OPENSSL_CMD='/opt/openssl-1.1.0e/bin/openssl'
CURL_CMD='/usr/bin/curl'
CONNECT_HOST='ip4.urown.net'

# Fix sorting
LC_ALL=C

# Log to syslog
log()
{
    logger -t ngx_connect --priority user.${1} ${2}
    echo "${1}: ${2}"
}

# We need to be root
if [[ ${UID} -gt 0 ]]; then
    log 'error' "Sorry, need to be root"
    echo "Sorry, need to be root"
    exit 1
fi

# Get primary virtual server names from Nginx configuration
VIRTUAL_SERVERS=$( ${NGINX_CMD} -qT | \
                        grep --only-matching --extended-regexp \
                            "^\s*server_name\s+((\w|-|\.)+)" | \
                        grep --only-matching --extended-regexp \
                            "(\w|-|\.)+$" | \
                        grep --extended-regexp --invert-match "\.onion$" | \
                        sort --unique
                  )

# Walk the list of virtual servers
for SERVER_NAME in ${VIRTUAL_SERVERS}; do

    #log 'info' "Connecting to ${SERVER_NAME}"

    echo -en "${SERVER_NAME}\t\tECDSA Key:\t\t"
    sleep 1
    ${OPENSSL_CMD} s_client -connect ${CONNECT_HOST}:443 -status \
        -servername ${SERVER_NAME} -crlf -verify 2 \
        -cipher 'ECDHE-ECDSA-AES128-GCM-SHA256' \
            2>&1 < /dev/null | fgrep 'OCSP Response Status'||echo -e '    Failed'

    echo -en "${SERVER_NAME}\t\tRSA Key:\t\t"
    sleep 1
    ${OPENSSL_CMD} s_client -servername ${SERVER_NAME} -status \
        -connect ${CONNECT_HOST}:443 -crlf -verify 2 \
        -cipher 'ECDHE-RSA-AES128-GCM-SHA256' \
            2>&1 < /dev/null | fgrep 'OCSP Response Status'||echo -e '    Failed'
    echo
done