Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild
Back to Blog Troubleshooting

curl -k: Ignoring Certificate Errors, and Why You Should Fix Them Instead

Sean

Platform Writer

Aug 13, 2026
8 min read

curl -k https://host — or the longer --insecure — tells curl to proceed even when the server’s TLS certificate does not verify. It switches off hostname checking and chain-of-trust validation, which means the connection is still encrypted but you no longer know who you are talking to. That is a reasonable trade on your own machine against your own staging box, and a bad one anywhere a script runs unattended.

curl -k: Ignoring Certificate Errors, and Why You Should Fix Them Instead

The flag is easy to find. The useful part is reading the error first, because the four common causes have different fixes and only one of them justifies reaching for -k at all.

Table of contents

The flag

curl -k https://staging.internal/health
curl --insecure https://staging.internal/health

# Through a proxy that also has an untrusted cert
curl -k --proxy-insecure -x https://localhost:8080 https://example.com

-k covers the target server. --proxy-insecure is separate and covers the proxy’s own certificate — a distinction that catches people debugging through a local intercepting proxy.

What you have disabled: verification that the certificate chains to a trusted CA, and verification that the hostname matches. Encryption still happens. Authentication does not, which means the connection is trivially interceptable by anyone positioned to do so.

Read the error before reaching for the flag

curl’s messages are specific, and each points at a different fix.

  • certificate has expired — the certificate is past its notAfter date. Renew it. Nothing else to discuss.
  • unable to get local issuer certificate — the chain is incomplete or your CA bundle does not include the issuer. Usually the server is not sending its intermediate certificate.
  • self-signed certificate — exactly what it says. Trust it explicitly with --cacert rather than disabling verification globally.
  • subjectAltName does not match — the certificate is valid but issued for a different hostname. You may be hitting an IP address, or a name the certificate does not cover.
# What is the server actually presenting?
openssl s_client -connect example.com:443 -servername example.com </dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

Thirty seconds with that command usually replaces an afternoon of guessing.

The missing intermediate, which is the most common real cause

A certificate chains from the server’s leaf certificate through one or more intermediates up to a root your system trusts. Browsers often paper over a missing intermediate by fetching it themselves. curl does not, which is why a site “works in Chrome” and fails in curl.

# Count the certificates the server sends
openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null \
  | grep -c 'BEGIN CERTIFICATE'

One certificate usually means the intermediate is missing. The fix is on the server: install the full chain, not just the leaf. Most issuers ship a fullchain.pem for exactly this reason, and configuring the leaf-only file instead is an easy mistake to make.

This one is worth fixing rather than working around, because every non-browser client — your monitoring, your webhook receivers, other people’s integrations — hits the same wall and most of them fail silently.

Trusting a specific certificate instead of disabling verification

For internal CAs and self-signed certificates, this is the right answer. You keep verification on; you just extend what counts as trusted.

# Trust one CA for this request
curl --cacert /path/to/internal-ca.pem https://internal.service/health

# Trust a specific self-signed leaf certificate
curl --cacert /path/to/server-cert.pem https://staging.internal/health

# Pin by public key hash -- strictest option
curl --pinnedpubkey 'sha256//YOUR_BASE64_HASH' https://internal.service/health

# Persist for the session
export CURL_CA_BUNDLE=/path/to/internal-ca.pem

The difference is meaningful. -k accepts any certificate including one an attacker generates; --cacert accepts exactly the one you nominated. Same convenience, none of the exposure.

For a machine-wide fix on Debian or Ubuntu, drop the CA into /usr/local/share/ca-certificates/ and run sudo update-ca-certificates. On RHEL-family systems it is /etc/pki/ca-trust/source/anchors/ and sudo update-ca-trust.

Hostname mismatches and —resolve

Testing a server before DNS points at it is a legitimate case where people reach for -k unnecessarily.

# Wrong: hits the IP, certificate is for the name, fails, so you add -k
curl -k https://203.0.113.10/health

# Right: correct hostname, forced to a specific IP, verification intact
curl --resolve example.com:443:203.0.113.10 https://example.com/health

--resolve sets the hostname for SNI and certificate validation while directing the connection to the address you choose. It is the tool for testing a new server, a specific node behind a load balancer, or a cutover before DNS propagates — with verification still on.

Where -k does real damage

In an interactive terminal, against a box you control, -k is fine. The problems start when it gets committed.

  • A -k in a deployment script means the deploy is interceptable and nobody will notice.
  • -k in a health check means the check passes against anything answering on that port, including the wrong thing.
  • -k in a container image outlives whoever added it and the reason they added it.
  • curl -k ... | bash is the worst version, since the content that gets executed is now unauthenticated.

The realistic advice is not “never use it”. It is: use it to confirm a diagnosis, then fix the cause and remove it. A -k that survives past the debugging session has become a permanent hole opened for a temporary reason.

A grep for --insecure and -k across your scripts and Dockerfiles is a five-minute audit that usually finds at least one.

Certificates you do not have to manage

Most of these errors trace back to certificate lifecycle work done by hand — issuing, installing the full chain, and renewing before expiry. Expiry in particular is a scheduled outage that everyone schedules and nobody attends.

Where the platform issues and renews the certificate for a custom domain, the expired-certificate case and the missing-intermediate case both stop happening, because neither is a step anyone performs manually. That is how custom domains work on RunxBuild — the certificate is part of attaching the domain rather than a separate chore with its own calendar reminder.

How this fits the rest of the stack

-k is --insecure and it disables both chain validation and hostname checking. Read the error first: expired means renew, missing issuer usually means the server is not sending its intermediate, self-signed means use --cacert, and a name mismatch often means you wanted --resolve. Use -k to confirm what is wrong, then take it back out.

The deeper fix is not doing certificate lifecycle by hand. If you are pricing out what a setup with managed certificates costs to run, the RunxBuild hosting calculator shows the service, database, storage, and bandwidth as separate line items.

Useful related references:

FAQ

What is the curl flag to ignore SSL certificate errors?

-k, or its long form --insecure. It allows curl to continue when the certificate fails verification. The connection stays encrypted but is no longer authenticated, so you lose any guarantee about who is on the other end.

Is curl -k safe to use?

It is acceptable for interactive debugging against a host you control. It is not safe in scripts, health checks, container images, or anything piped into a shell, because it accepts any certificate an attacker could present. Use it to confirm a diagnosis, then fix the cause and remove the flag.

How do I trust a self-signed certificate in curl without -k?

Pass the certificate or its CA with --cacert /path/to/cert.pem, or set CURL_CA_BUNDLE for the session. This keeps verification enabled and trusts exactly the certificate you nominated, unlike -k, which trusts anything at all.

Why does curl say ‘unable to get local issuer certificate’ when the browser is fine?

The server is probably not sending its intermediate certificate. Browsers often fetch the missing intermediate themselves; curl does not. Check with openssl s_client -showcerts and count the certificates returned — if there is only one, install the full chain on the server.

How do I test a server before DNS points at it, without -k?

Use --resolve hostname:443:1.2.3.4. curl sends the correct hostname for SNI and certificate validation while connecting to the address you specify, so verification stays on. This is also how you test one specific node behind a load balancer.

#curl#ssl certificate#tls#insecure#self-signed certificate