You ensure your website is secure by passing 8 outside-in checks: a 1-hop HTTPS redirect, a complete certificate chain, 30+ days to expiry, TLS 1.2 or newer, HSTS, 6 more security headers, DNSSEC and a version-free Server header. They cover 4 layers: connection, certificate, HTTP response and DNS zone. UpMonitor's probes audit 7 of the 8 from outside your network and warn 30 days before a certificate expires. Code flaws such as SQL injection need a separate review, if your site accepts user input.
What Does a Website Security Checklist Cover?
A website security checklist is a list of configuration tests anyone can run against a live site from outside, without access to its code or servers. Each check has a binary pass condition, such as "TLS 1.1 refused" or "X-Frame-Options present", so 2 people who run it get the same answer. The 8 checks below protect data in transit, keep the browser from being turned against your visitors, and make DNS answers verifiable. They do not test your application: broken access control, injection and the other risks in the OWASP Top 10 live in your code and need a code review or a penetration test.
The 8-Point Website Security Checklist
The checklist runs outside-in, from the first request a browser sends to the DNS zone behind it. Each row names the pass condition and the probe that audits it:
| # | Check | Pass condition | Audited by |
|---|---|---|---|
| 1 | HTTPS redirect | http:// answers a 301 to the final https:// URL in 1 hop | http probe |
| 2 | Certificate chain | The leaf and its intermediates chain to a trusted root | ssl probe |
| 3 | Certificate expiry | 30 or more days left, renewal automated | ssl probe |
| 4 | TLS version | TLS 1.2 and 1.3 accepted, TLS 1.0 and 1.1 refused | ssl probe (negotiated version) |
| 5 | HSTS | max-age of at least 15552000 seconds | securityHeaders probe |
| 6 | 6 more security headers | CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy and COOP present | securityHeaders probe |
| 7 | DNSSEC | A DNSKEY record at the zone and a DS record at the registrar | dnssec probe |
| 8 | Server disclosure | No version in Server, no X-Powered-By header | a curl command, section 8 below |
Start with the certificate rows: the free SSL certificate checker reads checks 2, 3 and 4 in 1 probe. Passing all 8 rows means every request reaches your site encrypted, over a current protocol, with the browser defences switched on.

How to Force HTTPS With a Single 301 Redirect
Force HTTPS by answering every plain-HTTP request with 1 permanent redirect straight to the final HTTPS URL. A 301 tells browsers and search engines that the resource moved permanently, and search engines pass the old URL's ranking to the new one. The 3 steps for nginx, with example.com as the canonical host:
1. Redirect port 80 in 1 hop. Send both hostnames to the canonical HTTPS URL in a single return:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
2. Redirect the second HTTPS hostname. A visitor who types https://www.example.com meets the certificate before the redirect, so that server block needs a certificate for the www name too:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
3. Count the hops. curl follows the chain and prints the number of redirects and the final URL:
curl -sIL -o /dev/null -w "%{num_redirects} %{url_effective}\n" http://www.example.com
A healthy result is 1 https://example.com/. The http probe follows up to 10 redirects, fails on a loop, and warns when the chain passes 4 hops or when http:// never reaches https://. Trace any URL with the HTTP redirect chain checker.
How to Keep Your SSL Certificate Valid and Renewed
Keep a certificate valid by automating renewal and probing its expiry from outside, because the maximum certificate lifetime is shrinking in 3 steps. CA/Browser Forum ballot SC-081v3, adopted on 11 April 2025, caps the validity of a publicly trusted TLS certificate by its issue date:
| Issued | Maximum validity |
|---|---|
| Before 15 March 2026 | 398 days |
| From 15 March 2026 | 200 days |
| From 15 March 2027 | 100 days |
| From 15 March 2029 | 47 days |
At 47 days, a site needs at least 8 certificates a year, so renewal has to run without a human. The chain matters as much as the date. Serve the leaf certificate together with its intermediates (certbot's fullchain.pem, not cert.pem), or a client that has not cached the intermediate cannot build the chain and rejects the connection. The ssl probe connects with chain validation on, fails on an untrusted or expired certificate, and warns when fewer than 30 days remain. Match an error message to its cause with the guide to decode SSL certificate errors.
How to Disable TLS 1.0 and TLS 1.1
Disable TLS 1.0 and 1.1 by listing only TLS 1.2 and 1.3 in your server's protocol directive. RFC 8996, published in March 2021, deprecates both versions and states that TLS 1.0 and TLS 1.1 MUST NOT be used. In nginx, 1 directive sets the accepted versions:
ssl_protocols TLSv1.2 TLSv1.3;
Current nginx releases ship exactly this value as the default, so a config that still lists TLSv1 or TLSv1.1 turns them back on by hand. Test which versions the server accepts from outside your network:
nmap --script ssl-enum-ciphers -p 443 example.com
The output prints 1 block per accepted protocol version, and a server that shows only TLSv1.2 and TLSv1.3 passes. The ssl probe reports the version each connection negotiates and warns on TLSv1 or TLSv1.1.
Which 7 Security Headers Should Every Website Send?
Every website should send 7 security headers: Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy and Cross-Origin-Opener-Policy. They are the 7 headers the securityHeaders probe reads, and the values below follow the OWASP HTTP Headers Cheat Sheet:
| Header | Recommended value | What it stops |
|---|---|---|
| Strict-Transport-Security | max-age=63072000; includeSubDomains; preload | A downgrade to plain HTTP on later visits |
| Content-Security-Policy | A per-site allowlist, starting at default-src 'self' | Scripts from origins you did not approve (XSS) |
| X-Frame-Options | DENY | Clickjacking through a frame on another site |
| X-Content-Type-Options | nosniff | The browser guessing a MIME type the server never sent |
| Referrer-Policy | strict-origin-when-cross-origin | Full URLs leaking to other sites |
| Permissions-Policy | geolocation=(), camera=(), microphone=() | Embedded content using browser features |
| Cross-Origin-Opener-Policy | same-origin | Cross-origin windows sharing your browsing context |
The probe fails when all 7 are missing, warns when CSP or HSTS is absent, and lists the other 5 as missing in its report. It also flags an HSTS max-age below 15552000 seconds, 180 days. Browsers ignore HSTS on a plain-HTTP response, so the header only protects a site that already passes check 1. The nginx block for all 7:
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
The always parameter adds each header to error responses as well. Read your live headers with the free security headers checker, and use the security headers guide to design a CSP for your own scripts.
Does DNSSEC Make a Website More Secure?
Yes: DNSSEC makes the DNS answers for your domain verifiable, so a validating resolver rejects a forged record instead of sending visitors to an attacker's server. RFC 4033 defines the service as origin authentication and integrity assurance for DNS data, and the same RFC states that it does not provide confidentiality. The protection has 2 halves:
- A DNSKEY record at your zone. Your DNS host signs the zone and publishes the public key at the zone apex.
- A DS record at your registrar. The parent zone stores a digest of that key, which ties your zone into the chain of trust.
A DS record that no longer matches the zone's key breaks resolution for every visitor behind a validating resolver, so change both halves together when you move DNS hosts. The dnssec probe asks Cloudflare and Google DNS-over-HTTPS for DNSKEY and DS records and fails when it finds neither; probe the apex domain, where the DNSKEY lives. Audit both records with the free DNSSEC checker.
How to Stop Your Server From Leaking Its Version
Stop version leaks by removing the version number from the Server header and dropping X-Powered-By, the 2 changes the OWASP HTTP Headers Cheat Sheet recommends for these headers. nginx prints its version on error pages and in the Server header by default (server_tokens on). The 2-line fix inside the http block:
server_tokens off;
proxy_hide_header X-Powered-By;
proxy_hide_header strips the header an application behind the proxy adds, such as Express or PHP; PHP-FPM setups use fastcgi_hide_header X-Powered-By; instead. Confirm what the response still reveals:
curl -sI https://example.com | grep -iE "^(server|x-powered-by):"
A passing response shows Server: nginx with no version and no X-Powered-By line. The 4 probes above do not flag this header, so run the command after every server upgrade.
How to Fix 5 Common Website Security Audit Failures
Fix each failure at the layer that produced it, then probe the site again. Each of the 5 failures opens with the message the probe prints:
1. HTTP version does not redirect to HTTPS. Port 80 serves the site instead of redirecting it. Add the port-80 server block from the redirect section and reload nginx. Prevention: keep the redirect in its own server block, so an application deploy never rewrites it.
2. SSL certificate will expire in 12 days. The renewal job stopped, or it renewed a file the server does not read. Run sudo certbot renew --dry-run, fix what it reports, then confirm the served expiry date moved. Prevention: a probe that warns at 30 days leaves time to fix renewal before a 200-day certificate lapses.
3. SSL connection failed: unable to verify the first certificate The server sends the leaf certificate without its intermediate. Point ssl_certificate at fullchain.pem and reload. Prevention: probe from outside after every certificate change, because a browser that cached the intermediate earlier hides the fault.
4. Missing non-critical security headers: Permissions-Policy, Cross-Origin-Opener-Policy The headers exist in the config, but a location block with its own add_header line replaces them: nginx inherits add_header from the previous level only when the current level defines none. Put the 7 lines in 1 snippet file and include it in every block that sets headers. Prevention: probe a deep URL, not only the home page.
5. Long redirect chain detected (5 hops). Old rules stack up: HTTP to HTTPS, then apex to www, then a trailing slash. Rewrite the first rule to send traffic straight to the final canonical URL. Prevention: rerun the curl hop count after every rewrite rule you add.
How to Automate the Website Security Checklist
Automate the checklist by running the probes on a schedule and in your deploy pipeline. A new monitor runs 6 probes by default, the http, ssl, securityHeaders and dnssec probes included: every 300 seconds from 1 region on the Free plan, and as often as every 60 seconds from up to 6 regions on PRO or 12 on Agency. The same probes gate a CI job:
npx @upmonitor/cli check https://example.com --ci --fail-on warning --checks http,ssl,securityHeaders
--fail-on warning exits with code 1 on any warning or failure, so an expiring certificate or a missing CSP stops the deploy. The CLI documentation lists the 3 exit codes: 0 when all checks pass, 1 when a check fails under --fail-on, and 2 on a configuration or network error. A scheduled probe reports a lapsed certificate or a dropped header within 1 interval, before a visitor meets it.
Frequently Asked Questions
Is HTTPS enough to make a website secure?
No. HTTPS encrypts the connection, which covers checks 1 to 4 of the 8. It does not stop another site from framing your pages, block injected scripts, or protect your DNS answers; the security headers and DNSSEC cover those. HTTPS also does nothing for flaws in your own code, which need a code review.
How often should I run a website security audit?
Run the full audit on every deploy and probe the site on a schedule between deploys. A deploy is when headers get dropped and redirects get rewritten, while a certificate expires on its own date whatever you ship. A 300-second probe interval reports either problem within 5 minutes.
What is the most important security header?
Strict-Transport-Security is the most important security header, if your site already redirects to HTTPS. It makes the browser refuse plain HTTP for the whole max-age period, which closes the downgrade path on every later visit. Content-Security-Policy blocks script injection but needs a policy written for your site, so send HSTS first and trial CSP with the Content-Security-Policy-Report-Only header.
Does a website security checklist replace a penetration test?
No. The checklist tests configuration that is visible from outside: the connection, the certificate, the headers and DNS. A penetration test attacks the application itself, including login, access control and input handling. Run the checklist on every deploy and a penetration test before major releases, if your site stores personal or payment data.
