← Back to Blog

TIL: OpenSSL can serve HTTPS

Developer NotePublished July 29, 2026Updated August 5, 20262 min read
OpenSSLTLSDebuggingCommand Line

TLDR

OpenSSL includes a small TLS server:

openssl s_server \
  -accept 8443 \
  -cert ./server.pem \
  -key ./server.key \
  -www

This listens on port 8443 and returns a small status page. Connect using the hostname or IP address from your certificate.

To serve files instead, replace lowercase -www with uppercase -WWW. OpenSSL then serves requested files from the current directory, so run it only where those files are safe to expose.

With -WWW, this is also a quick HTTPS alternative to python3 -m http.server. It can help with browser tests that require a secure context, such as camera access. On servers and other non-development machines, OpenSSL may already be available even when Python is not, giving you a temporary HTTPS endpoint without setting up Nginx, Caddy, or a small test application. The terminal also shows incoming handshakes and TLS alerts.

Why this is useful

OpenSSL already handles certificate inspection and verification. s_server adds another useful check: it presents the certificate and uses its matching private key in a real TLS handshake.

I used this while debugging local HTTPS from an Android app. The OpenSSL output showed that the phone reached the TLS handshake but rejected the development certificate. Once the app trusted the development CA, the same endpoint returned the built-in status page. That separated server reachability from client trust with one command.

Useful options

s_server has many switches. These cover the common debugging cases without reproducing the whole manual:

Option When it helps
-accept [host:]port Chooses the listening address and port. Omitting the host, as in -accept 8443, does not restrict the listener to loopback. Use -accept 127.0.0.1:8443 when it should stay local to the machine.
-4 / -6 Usually unnecessary. Use -4 when you explicitly need IPv4, or -6 when you explicitly need IPv6.
-cert_chain ./chain.pem Supplies the intermediate certificates that the server should send with the leaf. This is easy to miss when the leaf is not signed directly by the trusted root.
-tls1_2 / -tls1_3 Forces exactly one TLS version. Without either flag, the server negotiates the highest version shared with the client. Use -min_protocol TLSv1.2 when the requirement is “TLS 1.2 or newer.”
-brief, -state, -msg, -tlsextdebug Chooses how much connection detail to print: a short summary, state transitions, protocol messages, or received TLS extensions.
-naccept 1 Exits after the specified number of connections. Useful for a one-request reproduction or a script.

The local installation describes its complete option set with:

openssl s_server -help

I checked these options with OpenSSL 3.6.3. OpenSSL builds can expose different switches, so check the local help before copying an option.

What it proves

If s_server starts, OpenSSL loaded the certificate and its matching private key. If a client receives the status page, that client reached the listener and completed the TLS handshake.

s_server is a debugging tool, not a production server.

OpenSSL documents the available s_server options.