Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
enriquebrosericus avatar

Nginx Selfsigned Cert

  • 1 installs
  • Updated July 19, 2026
  • enriquebrosericus/claudefun

Generate, regenerate, or replace a self-signed TLS certificate served by NGINX in a container, generated at startup via an openssl command override.

About

Explains the repo convention of generating a self-signed NGINX TLS cert inside the container at startup rather than baking it into the image, plus the openssl flags and CN choice. A developer uses it when handling TLS in a sub-project, changing the CN, or swapping in a real cert.

  • openssl req -x509 cert generated at container start via command override
  • CN guidance (localhost vs hostname) and how clients skip verification

Nginx Selfsigned Cert by the numbers

  • 1 all-time installs (skills.sh)
  • Ranked #1,173 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
  • Data as of Jul 20, 2026 (Skillselion catalog sync)
npx skills add https://github.com/enriquebrosericus/claudefun --skill nginx-selfsigned-cert

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs1
Last updatedJuly 19, 2026
Repositoryenriquebrosericus/claudefun

What it does

Generate, regenerate, or replace a self-signed TLS certificate served by NGINX in a container, generated at startup via an openssl command override.

Files

SKILL.mdMarkdownGitHub ↗

Self-signed TLS certs for NGINX containers

The claudeFun repo's convention is generate the cert inside the container at startup, not bake it into the image. Every existing project does this via the command: override in docker-compose.yml:

command: ["/bin/sh", "-c", "mkdir -p /etc/nginx/ssl && openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/key.pem -out /etc/nginx/ssl/cert.pem -subj '/CN=localhost' && nginx -g 'daemon off;'"]

The nginx config then references /etc/nginx/ssl/cert.pem and /etc/nginx/ssl/key.pem.

Why generate at startup, not at build

  • Image stays portable and rebuildable. No private key checked into the layer cache or pushed to a registry.
  • Cert lifetime resets every container restart. No "expired in CI" failures.
  • Each developer/instance gets their own key. Nothing to coordinate.
  • Trade-off: every restart issues a new cert, so any browser TLS exception is invalidated. For a self-signed dev workflow that's fine; for a production deployment it isn't (see "Swapping in a real cert" below).

The openssl flags, decoded

FlagWhat it does
req -x509Output a self-signed cert directly (skip the CSR step)
-nodesDon't encrypt the private key — nginx needs to read it without a passphrase
-days 365Validity window. 365 is fine since the cert is regenerated on restart anyway
-newkey rsa:2048Generate a fresh 2048-bit RSA keypair
-keyout / -outWhere to write the key and cert
-subj '/CN=...'Skip the interactive prompts; set the Common Name inline

Choosing the CN

  • `CN=localhost` — fine when you only access the app at https://localhost:<port>. Used by bingo/ and music-notation-trainer/.
  • `CN=<your-hostname>` — use when accessing via a real DNS name, even on the LAN. mlb_stats_tracker/docker-compose.yml uses CN=whackbat.techbrose.com.
  • The CN does not affect TLS security in self-signed mode (the browser will warn either way), but a mismatch produces an extra warning on top of the unknown-issuer warning.

How clients should connect

Self-signed certs aren't trusted by any CA, so clients need to skip verification or trust the cert manually:

  • curl: curl -k https://localhost:<port>/ (or --insecure)
  • wget: wget --no-check-certificate https://localhost:<port>/ — this is what the healthchecks in this repo use
  • browsers: click through the warning page once per cert lifetime
  • httpie: http --verify=no https://localhost:<port>/

Common operations

Force-regenerate the cert

Just restart the container — the command: runs openssl req again on every start.

docker compose restart <service-name>

Inspect the cert that's currently serving

docker exec <container-name> openssl x509 -in /etc/nginx/ssl/cert.pem -noout -subject -dates

Swap in a real cert (e.g. Let's Encrypt)

For a project that's actually deployed somewhere with a real hostname:

1. Drop the command: override from compose; let nginx start normally. 2. Mount real cert files in instead:

   volumes:
     - /etc/letsencrypt/live/<hostname>/fullchain.pem:/etc/nginx/ssl/cert.pem:ro
     - /etc/letsencrypt/live/<hostname>/privkey.pem:/etc/nginx/ssl/key.pem:ro

3. Either run certbot on the host and reload nginx on renewal, or add a certbot sidecar service. Don't try to run certbot inside the same nginx container — keep them decoupled.

Gotchas

  • Healthchecks must use `--no-check-certificate` (or hit HTTP) — otherwise the container will be permanently unhealthy.
  • Don't set `ssl_protocols` or `ssl_ciphers` aggressively in dev. The defaults in nginx 1.27 are fine; the cert is the weak link, not the cipher suite.
  • The `command:` override replaces the image's CMD entirely. If you change the base image to something other than nginx:*, you'll need to update the final nginx -g 'daemon off;' part to whatever the new image expects.
  • `apk add openssl` is required in Pattern A (single-container static apps using nginx:1.27-alpine). The nginx:latest (Debian-based) image used in Pattern B already has openssl.

Related skills

DevOps & CI/CDinfradeploy

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.