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#!/bin/bash
  2#
  3# Pre-compress static web resources
  4#
  5# To be started by cron every few hours
  6#
  7# For monitoring use the following command:
  8#
  9#   journalctl -t ngx_pre_compress -p <level> --no-tail -f
 10#
 11# while <level> may be any of debug, info, notice or warning
 12
 13# Exit on errors
 14set -e
 15# Exit on undefined variable
 16set -u
 17
 18NGINX_USER='www-data'
 19NGINX_GROUP='www-data'
 20NGINX_CMD='/usr/sbin/nginx'
 21GZIP_CMD='/bin/gzip'
 22BROTLI_CMD='/usr/bin/brotli'
 23# See /etc/nginx/mime.types
 24FILETYPES='en html htm shtml css xml js atom rss mml txt wml json doc ps rtf xls ppt run pl docx xlsx pptx'
 25
 26# Log to syslog
 27log()
 28{
 29    logger -t ngx_pre_compress --priority user.${1} ${2}
 30}
 31
 32# We need to be root
 33if [[ ${UID} -gt 0 ]]; then
 34    log 'error' "Sorry, need to be root"
 35    echo "Sorry, need to be root"
 36    exit 1
 37fi
 38
 39# Fix sorting
 40LC_ALL=C
 41
 42# Start
 43log 'notice' "Starting pre-compression of files for Nginx."
 44
 45# Get document root and alias directories from current Nginx configuration
 46webdirs=$( ${NGINX_CMD} -qT | \
 47                        grep --only-matching --extended-regexp \
 48                            "^\s*(root|alias)\s+((/*.)+)" | \
 49                        grep --only-matching --extended-regexp \
 50                            "(/[a-zA-Z0-9/_\.]+)" | \
 51                        sort --unique
 52                  )
 53total_dirs=0
 54total_files=0
 55total_br_new=0
 56total_gz_new=0
 57total_br_updates=0
 58total_gz_updates=0
 59
 60dir_files=0
 61dir_br_new=0
 62dir_br_updates=0
 63dir_gz_new=0
 64dir_gz_updates=0
 65
 66#
 67# Create compressed versions
 68
 69# Walk directories
 70for dir in ${webdirs};
 71do
 72
 73    # Is this a directory?
 74    if [[ -d ${dir} ]]; then
 75
 76        log 'info' "Looking for files to pre-compress in ${dir} ..."
 77        total_dirs=$((total_dirs+1))
 78        dir_files=0
 79        dir_br_new=0
 80        dir_br_updates=0
 81        dir_gz_new=0
 82        dir_gz_updates=0
 83
 84        #echo -n "Searching for "
 85
 86        # Walk the list of filetypes
 87        for filetype in ${FILETYPES};
 88        do
 89            #echo -n "${filetype} "
 90
 91            # Find files
 92            while IFS= read -r -d '' file;
 93            do
 94
 95                dir_files=$((dir_files+1))
 96
 97                # Does it have a Brotli companion?
 98                if [[ -f "${file}.br" ]]; then
 99
100                    # Is it outdated?
101                    if [[ "${file}" -nt "${file}.br" ]]; then
102
103                        # Refresh the Brotli companion
104                        dir_br_updates=$((dir_br_updates+1))
105                        ${BROTLI_CMD} --force --input "${file}" --output "${file}.br"
106
107                        # Set file time, owner, access rights from original
108                        chown --reference="${file}" "${file}.br"
109                        chmod --reference="${file}" "${file}.br"
110                        touch --reference="${file}" "${file}.br"
111                    fi
112                else
113
114                    # Create new Brotli companion
115                    dir_br_new=$((dir_br_new+1))
116                    ${BROTLI_CMD} --input "${file}" --output "${file}.br"
117
118                    # Set file time, owner, access rights from original
119                    chown --reference="${file}" "${file}.br"
120                    chmod --reference="${file}" "${file}.br"
121                    touch --reference="${file}" "${file}.br"
122                fi
123
124                # Does it have a Gzip companion?
125                if [[ -f "${file}.gz" ]]; then
126
127                    # Is it outdated?
128                    if [[ "${file}" -nt "${file}.gz" ]]; then
129
130                        # Refresh the GZip companion
131                        dir_gz_updates=$((dir_gz_updates+1))
132                        ${GZIP_CMD} --keep "${file}"
133
134                        # Set file time, owner, access rights as the original
135                        chown --reference="${file}" "${file}.gz"
136                        chmod --reference="${file}" "${file}.gz"
137                        touch --reference="${file}" "${file}.gz"
138                    fi
139                else
140
141                    # Create a new GZip companion
142                    dir_gz_new=$((dir_gz_new+1))
143                    ${GZIP_CMD} --keep "${file}"
144
145                    # Set file time, owner, access rights as the original
146                    chown --reference="${file}" "${file}.gz"
147                    chmod --reference="${file}" "${file}.gz"
148                    touch --reference="${file}" "${file}.gz"
149                fi
150            done < <(find "${dir}" -type f -name "*.${filetype}" -print0)
151        done
152        #echo
153        log 'info' "Files processed: ${dir_files}"
154        log 'info' "New Brotlis created: ${dir_br_new}"
155        log 'info' "Outdated Brotlis updated: ${dir_br_updates}"
156        log 'info' "New GZips created: ${dir_gz_new}"
157        log 'info' "Outdated GZips updated: ${dir_gz_updates}"
158        total_files=$((total_files+dir_files))
159        total_br_new=$((total_br_new+dir_br_new))
160        total_br_updates=$((total_br_updates+dir_br_updates))
161        total_gz_new=$((total_gz_new+dir_gz_new))
162        total_gz_updates=$((total_gz_updates+dir_gz_updates))
163    else
164        echo "${dir} is not a directory."
165    fi
166done
167log 'info' "Total Directories processed: ${total_dirs}"
168log 'info' "Total Files processed: ${total_files}"
169log 'info' "Total New Brotlis created: ${total_br_new}"
170log 'info' "Total Outdated Brotlis updated: ${total_br_updates}"
171log 'info' "Total New GZips created: ${total_gz_new}"
172log 'info' "Total Outdated GZips updated: ${total_gz_updates}"
173
174# End
175log 'notice' " pre-compression of files for Nginx complete. Have a nice day."

OCSP Staples

  1#!/bin/bash
  2#
  3# OCSP response files creation for stapling in Nginx
  4#
  5# To be started by cron every few hours
  6#
  7# For monitoring use the following command:
  8#
  9#   journalctl -t ngx_ocsp_staples -p <level> --no-tail -f
 10#
 11# while <level> may be any of debug, info, notice or warning
 12#
 13
 14# Exit on errors
 15set -e
 16
 17CERTS_DIRS='/etc/dehydrated/ec_certs /etc/dehydrated/rsa_certs'
 18OPENSSL_CMD='/opt/openssl-1.1.0e/bin/openssl'
 19NGINX_CMD='/usr/sbin/nginx'
 20OCSP_REQ_OPTIONS='-no_nonce -sha256'
 21
 22# Log to syslog
 23log()
 24{
 25    logger -t ngx_ocsp_staples --priority user.${1} ${2}
 26}
 27
 28log 'notice' "Starting to create Nginx OCSP repsonse files ..."
 29
 30# We need to be root
 31if [[ ${UID} -gt 0 ]]; then
 32    log 'error' "Sorry, need to be root"
 33    echo "Sorry, need to be root"
 34    exit 1
 35fi
 36
 37# Reload Nginx only on changed repsonse files
 38NGINX_RELOAD=false
 39
 40for certs_dir in ${CERTS_DIRS}; do
 41
 42    # Walk the certificates directory
 43    for cert_dir in ${certs_dir}/*; do
 44
 45        # Is it a directory?
 46        if [[ -d "${cert_dir}" ]]; then
 47
 48            log 'info' "Getting OCSP repsonse for ${cert_dir} ..."
 49
 50            cd ${cert_dir}
 51
 52            timestamp="$( date +%s )"
 53            cert_file="cert.pem"
 54            issuer_cert_file="chain.pem"
 55            ca_cert_file="${issuer_cert_file}"
 56            response_file="ocsp_response.der"
 57
 58            # Do we have a certificate?
 59            if [[ -f "${cert_file}" ]]; then
 60
 61                cert_subject=$( ${OPENSSL_CMD} x509 -in ${cert_file} -noout -subject )
 62                log 'info' "Certificate file for ${cert_subject} found."
 63
 64            else
 65
 66                log 'warning' "No certificate file in ${cert_dir} found, skipping."
 67                continue
 68
 69            fi
 70
 71            # Do we have an issuer certficate chain file?
 72            if [[ -f "${issuer_cert_file}" ]]; then
 73
 74                issuer_cert_subject=$(
 75                    ${OPENSSL_CMD} x509 -in ${issuer_cert_file} -noout -subject
 76                )
 77                log 'info' "Issuer certificate file of ${issuer_cert_subject} found."
 78
 79            else
 80
 81                log 'warning' "No issuer certificate file for ${cert_subject} found, skipping."
 82                continue
 83
 84            fi
 85
 86            # Get the OCSP URI
 87            ocsp_uri=$(
 88                ${OPENSSL_CMD} x509 -in ${cert_file} -noout -ocsp_uri
 89            )
 90
 91            # Get the Hostname out of the URI
 92            ocsp_host=$(
 93                echo ${ocsp_uri} | sed -e '\,^[hH][tT][tT][pP]://\([^/]*\).*,!d
 94                    s//\1/;s/.*@//
 95                    s/.*://'
 96            )
 97
 98            # Do we already have an OCSP Response file?
 99            if [[ -L "${response_file}" ]]; then
100
101                # Validate it
102                log 'info' "Existing OSCP response file found, validating ..."
103                ocsp_verification=$(
104                    ${OPENSSL_CMD} ocsp \
105                        -issuer ${issuer_cert_file} \
106                        -VAfile ${ca_cert_file} \
107                        -cert ${cert_file} \
108                        -respin ${response_file} \
109                        -no_nonce 2>&1
110                )
111                export RC=$?
112                log 'debug' "OpenSSL returns ${RC}: ${ocsp_verification}"
113
114                if [[ ${RC} -eq 0 ]] ; then
115
116                    # Has it expired?
117                    if [[ ${ocsp_verification} = *'WARNING: Status times invalid'* ]]
118                    then
119                        log 'notice' "OCSP repsonse file has expired, removing ..."
120                        rm ${response_file}
121
122                    else
123
124                        log 'info' "Existing OSCP response file is valid, skipping."
125                        continue
126                    fi
127
128                else
129
130                    log 'notice' "OCSP repsonse file does not validate, removing ..."
131                    rm ${response_file}
132
133                fi
134
135            else
136
137                log 'info' "No previous OCSP repsonse file found."
138
139            fi
140
141            # Don't hammer the OCSP server
142            sleep 5
143
144            # Do the OCSP request
145            log 'notice' "Contacting ${ocsp_host} for validation of ${cert_subject} ..."
146            ocsp_response=$(
147                ${OPENSSL_CMD} ocsp \
148                    -issuer ${issuer_cert_file} \
149                    -CAfile ${ca_cert_file} \
150                    -VAfile ${ca_cert_file} \
151                    -cert ${cert_file} \
152                    -url ${ocsp_uri} \
153                    -header "HOST" "${ocsp_host}" \
154                    ${OCSP_REQ_OPTIONS} \
155                    -respout ocsp_response-${timestamp}.der 2>&1
156                )
157            export RC=$?
158            log 'debug' "OpenSSL returns ${RC}: ${ocsp_response}"
159
160            # Has a new response file been created?
161            if [[ -f "ocsp_response-${timestamp}.der" ]]; then
162
163                # Read, check and verify it
164                log 'info' "New OSCP response file ocsp_response-${timestamp}.der created, validating ..."
165                ocsp_verification=$(
166                    ${OPENSSL_CMD} ocsp \
167                        -issuer ${issuer_cert_file} \
168                        -VAfile ${ca_cert_file} \
169                        -cert ${cert_file} \
170                        -respin ocsp_response-${timestamp}.der \
171                        -no_nonce 2>&1
172                )
173                export RC=$?
174                log 'debug' "OpenSSL returns ${RC}: ${ocsp_verification}"
175                if [[ ${RC} -eq 0 ]] ; then
176
177                    log 'notice' "New OSCP response file for ${cert_subject} is valid, installing..."
178
179                    # Update symlink
180                    ln --force --symbolic ocsp_response-${timestamp}.der \
181                        ${response_file}
182
183                    # Nginx will be reloaded
184                    NGINX_RELOAD=true
185
186                else
187
188                    log 'error' "Created OCSP repsonse file ocsp_response-${timestamp}.der does not validate, skipping."
189                    continue
190
191                fi
192
193            else
194
195                log 'error' "OCSP response file  ocsp_response-${timestamp}.der creation failed, skipping."
196                continue
197
198            fi
199
200        else
201
202            log 'info' "${cert_dir} is not a directory, skipping ..."
203
204        fi
205
206    done
207
208done
209
210# Do we have to reload Nginx?
211if [[ ${NGINX_RELOAD} == true ]]; then
212
213    # Test Server configuration
214    log 'info' "Checking Nginx server configuration ..."
215    ${NGINX_CMD} -tq
216
217    # Restart Nginx
218    log 'notice' "Relaoding Nginx server ..."
219    ${NGINX_CMD} -s reload
220
221else
222
223    log 'info' "Nginx server does not need to reload"
224
225fi
226
227log 'notice' "Nginx OCSP repsonse files creation complete. Have a nice day."

TLS Session Key Rotation

  1#!/bin/bash
  2#
  3# SSL Session ticket key rotation
  4# for Nginx virtual servers
  5#
  6# To be started by cron every few hours
  7#
  8# For monitoring use the following command:
  9#
 10#   journalctl -t ngx_key_rotation -p <level> --no-tail -f
 11#
 12# while <level> may be any of debug, info, notice or warning
 13#
 14# See also:
 15# https://github.com/Fleshgrinder/nginx-session-ticket-key-rotation
 16#
 17
 18# Exit on errors
 19set -e
 20
 21NGINX_USER='www-data'
 22NGINX_GROUP='www-data'
 23KEYS_DIR='/etc/nginx/tls_session_keys'
 24KEY_DISCARD=24 # Time until a key will be discarded (in hours)
 25KEY_EXPIRE=8 # Time until a fresh key will be created (in hours)
 26KEY_SIZE=48 # 80 bytes for AES256 or 48 byte for AES128 encryption
 27OPENSSL_CMD='/usr/bin/openssl'
 28NGINX_CMD='/usr/sbin/nginx'
 29
 30# Add default site to servers list
 31VIRTUAL_SERVERS="${VIRTUAL_SERVERS} default_server"
 32
 33# Log to syslog
 34log()
 35{
 36    logger -t ngx_key_rotation --priority user.${1} ${2}
 37}
 38
 39# Create new random key
 40generate_key()
 41{
 42
 43    ${OPENSSL_CMD} rand ${KEY_SIZE} > ${1}
 44    chown ${NGINX_USER}:${NGINX_GROUP} ${1}
 45    chmod 660 ${1}
 46}
 47
 48# Start
 49log 'notice' "Starting Nginx TLS/SSL session key rotation."
 50
 51# We need to be root
 52if [[ ${UID} -gt 0 ]]; then
 53    log 'error' "Sorry, need to be root"
 54    echo "Sorry, need to be root"
 55    exit 1
 56fi
 57
 58# Fix sorting
 59LC_ALL=C
 60
 61# Reload Nginx only on keys change
 62NGINX_RELOAD=false
 63
 64# Get primary virtual server names from Nginx configuration
 65VIRTUAL_SERVERS=$( ${NGINX_CMD} -qT | \
 66                        grep --only-matching --extended-regexp \
 67                            "^\s*server_name\s+((\w|-|\.)+)" | \
 68                        grep --only-matching --extended-regexp \
 69                            "(\w|-|\.)+$" | \
 70                        sort --unique
 71                  )
 72
 73# Create the directory for storing the keys
 74mkdir -p ${KEYS_DIR}
 75chown ${NGINX_USER}:${NGINX_GROUP} ${KEYS_DIR}
 76chmod 770 ${KEYS_DIR}
 77
 78# Walk the list of virtual servers
 79for SERVER_NAME in ${VIRTUAL_SERVERS}; do
 80
 81    log 'debug' "Checking Nginx TLS session keys for ${SERVER_NAME}"
 82
 83    # Walk trough keys
 84    for KEY_NUM in 3 2 1 ; do
 85
 86        KEYFILE="${KEYS_DIR}/${SERVER_NAME}.${KEY_NUM}.key"
 87
 88        # Do we already have this key
 89        if [[ -f ${KEYFILE} ]]; then
 90
 91            log 'debug' "Nginx session key ${KEY_NUM} for ${SERVER_NAME} found."
 92            KEY_TIME=$( date +'%s' -r ${KEYFILE} )
 93            KEY_EXPIRE_TIME=$(  date +%s --date="@$(( ${KEY_TIME} + ( ${KEY_EXPIRE}  * 60 * 60 * ${KEY_NUM} ) ))" )
 94            KEY_DISCARD_TIME=$( date +%s --date="@$(( ${KEY_TIME} + ( ${KEY_DISCARD} * 60 * 60 ) ))" )
 95
 96            # Has it reached its end of life?
 97            if [[ ${KEY_TIME} -ge $(( ${KEY_DISCARD_TIME} - 30 )) ]]; then
 98                log 'info' "Nginx session key ${KEY_NUM} for ${SERVER_NAME} has reached EOL, removing..."
 99                rm ${KEYFILE}
100
101            fi
102
103            # Key number lesser then 3?
104            if [[ ${KEY_NUM} -lt 3 ]]; then
105
106                # Has it reached its expiration time?
107                if [[ $( date +'%s') -ge $(( ${KEY_EXPIRE_TIME} - 30 )) ]]; then
108
109                    log 'info' "Nginx session key ${KEY_NUM} for ${SERVER_NAME} has expired, moving..."
110                    EXP_KEYFILE="${KEYS_DIR}/${SERVER_NAME}.$(( ${KEY_NUM} + 1 )).key"
111                    cp --force --preserve=mode,ownership,timestamps ${KEYFILE} ${EXP_KEYFILE}
112                    RELOAD_NGINX=true
113
114                    # Key number 1?
115                    if [[ ${KEY_NUM} -eq 1 ]]; then
116
117                        log 'info' "Generating fresh Nginx session key ${KEY_NUM} for ${SERVER_NAME} ..."
118                        generate_key ${KEYFILE}
119                        RELOAD_NGINX=true
120
121                    fi
122
123                fi
124
125            fi
126
127        else
128
129            log 'notice' "No Nginx session key ${KEY_NUM} for ${SERVER_NAME} found. Generating ..."
130            generate_key ${KEYFILE}
131            RELOAD_NGINX=true
132
133        fi
134
135    done
136
137    # Do we already have this key
138    if [[ ! -f ${KEYFILE} ]]; then
139
140        log 'warn' "No Nginx session key ${KEY_NUM} for ${SERVER_NAME} found. Generating ..."
141        generate_key ${KEYFILE}
142        RELOAD_NGINX=true
143
144    fi
145
146done
147
148# Cleanup, remove anything older then 48 hours
149#find ${KEYS_DIR} -type f -mmin +$(( ${KEY_DISCARD} * 2 * 60 ))
150
151# Do we have to reload Nginx?
152if [[ ${RELOAD_NGINX} == true ]]; then
153
154    log 'notice' "Nginx server needs to be reloaded ..."
155
156    # Test Server configuration
157    log 'info' "Checking Nginx server configuration ..."
158    ${NGINX_CMD} -tq
159
160    # Restart Nginx
161    log 'info' "Relaoding Nginx server ..."
162    ${NGINX_CMD} -s reload
163
164fi
165
166log 'notice' "Nginx TLS/SSL session key rotation complete. Have a nice day."

Tor Exit Nodes

 1#!/bin/bash
 2#
 3# Create Nginx map file of Tor Exit Nodes
 4#
 5
 6# Bail-out on errors
 7#set -e
 8
 9# Settings
10MY_IP=$( curl -s --fail --ipv4 http://v4.ipv6-test.com/api/myip.php )
11MY_PORT=443
12FETCH_URL="https://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=${MY_IP}&port=${MY_PORT}"
13MAP_FILE='/etc/nginx/tor-exit-nodes.map'
14
15# Log to syslog
16log()
17{
18    logger -t ngx_tor_exits --priority user.${1} ${2}
19}
20
21valid_ip()
22# Test an IP address for validity:
23# Usage:
24#      valid_ip IP_ADDRESS
25#      if [[ $? -eq 0 ]]; then echo good; else echo bad; fi
26#   OR
27#      if valid_ip IP_ADDRESS; then echo good; else echo bad; fi
28#
29{
30    local  ip=$1
31    local  stat=1
32
33    if [[ ${ip} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
34        OIFS=${IFS}
35        IFS='.'
36        ip=(${ip})
37        IFS=${OIFS}
38        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
39            && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
40        stat=$?
41    fi
42    return ${stat}
43}
44
45TMP_DL_FILE=$( mktemp )
46TMP_MAP_FILE=$( mktemp )
47
48# Fetch the list
49log 'notice' "Fetching Tor Exit Nodes ..."
50the_list=$( curl -s --fail --remote-time --remote-time ${MAP_FILE} --url ${FETCH_URL} )
51log 'notice' "Done fetching Nodes"
52
53# Set the field separator to new line
54IFS=$'\n'
55
56while read -r line; do
57    valid_ip ${line}
58    if [[ $? -eq 0 ]]; then
59        line+=' true;'
60    else
61        line="##${line}"
62    fi
63    echo ${line} >> ${TMP_MAP_FILE}
64done <<< "${the_list}"
65
66# Remove old backups
67find /etc/nginx/ -name tor-exit-nodes.map.~* -delete
68
69# Install
70log 'notice' "Installing fresh node list ${MAP_FILE} ..."
71/usr/bin/install --backup=numbered --mode=0664 --preserve-timestamps \
72    ${TMP_MAP_FILE} ${MAP_FILE}

Connect Servers

 1#!/bin/bash
 2#
 3# Connect to all our virutal servers
 4#
 5
 6# Exit on errors
 7set -e
 8# Return pipe errors
 9set -o pipefail
10# Error on undefined variables
11#set -u
12
13NGINX_CMD='/usr/sbin/nginx'
14OPENSSL_CMD='/opt/openssl-1.1.0e/bin/openssl'
15CURL_CMD='/usr/bin/curl'
16CONNECT_HOST='ip4.urown.net'
17
18# Fix sorting
19LC_ALL=C
20
21# Log to syslog
22log()
23{
24    logger -t ngx_connect --priority user.${1} ${2}
25    echo "${1}: ${2}"
26}
27
28# We need to be root
29if [[ ${UID} -gt 0 ]]; then
30    log 'error' "Sorry, need to be root"
31    echo "Sorry, need to be root"
32    exit 1
33fi
34
35# Get primary virtual server names from Nginx configuration
36VIRTUAL_SERVERS=$( ${NGINX_CMD} -qT | \
37                        grep --only-matching --extended-regexp \
38                            "^\s*server_name\s+((\w|-|\.)+)" | \
39                        grep --only-matching --extended-regexp \
40                            "(\w|-|\.)+$" | \
41                        grep --extended-regexp --invert-match "\.onion$" | \
42                        sort --unique
43                  )
44
45# Walk the list of virtual servers
46for SERVER_NAME in ${VIRTUAL_SERVERS}; do
47
48    #log 'info' "Connecting to ${SERVER_NAME}"
49
50    echo -en "${SERVER_NAME}\t\tECDSA Key:\t\t"
51    sleep 1
52    ${OPENSSL_CMD} s_client -connect ${CONNECT_HOST}:443 -status \
53        -servername ${SERVER_NAME} -crlf -verify 2 \
54        -cipher 'ECDHE-ECDSA-AES128-GCM-SHA256' \
55            2>&1 < /dev/null | fgrep 'OCSP Response Status'||echo -e '    Failed'
56
57    echo -en "${SERVER_NAME}\t\tRSA Key:\t\t"
58    sleep 1
59    ${OPENSSL_CMD} s_client -servername ${SERVER_NAME} -status \
60        -connect ${CONNECT_HOST}:443 -crlf -verify 2 \
61        -cipher 'ECDHE-RSA-AES128-GCM-SHA256' \
62            2>&1 < /dev/null | fgrep 'OCSP Response Status'||echo -e '    Failed'
63    echo
64done