How to Generate mkcert Certificates for IP Addresses and URIs: A Complete Guide

Use mkcert <ip> for IP addresses or mkcert <uri> for URIs, and mkcert automatically detects the type and creates the appropriate Subject Alternative Name (SAN) entries.

The mkcert tool by FiloSottile simplifies local development certificate generation by automatically handling various identifier types. When you need to generate mkcert certificates for IP addresses and URIs, the tool inspects each argument to determine whether it represents a DNS hostname, IP address, email address, or URI, then populates the certificate's SAN extension accordingly.

How mkcert Detects IP Addresses and URIs Automatically

The automatic detection logic resides in two key files: main.go for argument classification and cert.go for certificate template construction.

Argument Classification in main.go

In main.go (lines 16-27), each positional argument undergoes type detection using Go's standard library parsers:

if ip := net.ParseIP(name); ip != nil {
    continue               // IP address detected
}
if email, err := mail.ParseAddress(name); err == nil && email.Address == name {
    continue               // Email address detected
}
if uriName, err := url.Parse(name); err == nil && uriName.Scheme != "" && uriName.Host != "" {
    continue               // URI detected
}

If none of these parsers succeed, mkcert treats the argument as a DNS name after applying puny-code conversion for internationalized domain names.

SAN Construction in cert.go

The makeCert method in cert.go (lines 76-86) receives the classified hosts and populates the x509.Certificate template:

for _, h := range hosts {
    if ip := net.ParseIP(h); ip != nil {
        tpl.IPAddresses = append(tpl.IPAddresses, ip)
    } else if email, err := mail.ParseAddress(h); err == nil && email.Address == h {
        tpl.EmailAddresses = append(tpl.EmailAddresses, h)
    } else if uriName, err := url.Parse(h); err == nil && uriName.Scheme != "" && uriName.Host != "" {
        tpl.URIs = append(tpl.URIs, uriName)
    } else {
        tpl.DNSNames = append(tpl.DNSNames, h)
    }
}

For URIs, mkcert stores only the scheme and host components. The path, query, and fragment are discarded because the X.509 SAN specification does not support them.

Key Usage Adjustments

According to cert.go (lines 91-96), mkcert automatically sets appropriate Extended Key Usage (EKU) flags:

  • IP addresses, DNS names, and URIs: Adds ExtKeyUsageServerAuth for TLS server authentication.
  • Email addresses: Adds ExtKeyUsageEmailProtection for S/MIME or email signing.

If you pass the -client flag, mkcert also adds ExtKeyUsageClientAuth for mutual TLS scenarios.

Generating Certificates for IP Addresses

IPv4 Addresses

To generate a certificate for a local development server bound to 127.0.0.1:

mkcert 127.0.0.1

This creates 127.0.0.1.pem and 127.0.0.1-key.pem with an IP Address SAN entry containing the IPv4 address.

IPv6 Addresses

mkcert supports IPv6 addresses using standard notation:

mkcert ::1

Or for a specific IPv6 address:

mkcert 2001:db8::1

The net.ParseIP function in main.go handles both IPv4 and IPv6 formats automatically.

Generating Certificates for URIs

URIs are useful for services that validate the full URI rather than just the hostname, such as certain OAuth 2.0 providers or SPIFFE-based service meshes.

Basic URI Certificate

To generate a certificate for a specific URI:

mkcert https://api.example.com

Note that mkcert extracts only https://api.example.com (scheme and host). If you include a path like https://api.example.com/v1, the path component is stripped during SAN construction in cert.go.

Multiple URIs

You can combine URIs with other name types:

mkcert https://app.local https://api.local 192.168.1.10

This generates a single certificate with URI SAN entries for both HTTPS endpoints and an IP SAN entry for the local network address.

Advanced Usage Examples

Mixed Host Types

For microservices that expose both DNS names and IP endpoints, generate a single certificate covering all endpoints:

mkcert localhost 127.0.0.1 ::1 example.com https://service.example.com

The resulting certificate includes:

  • DNS names: localhost, example.com
  • IP addresses: 127.0.0.1, ::1
  • URI: https://service.example.com

Custom Output Filenames

When generating certificates for IP addresses, the default filename contains dots or colons that may cause issues on some filesystems. Use the -cert-file and -key-file flags:

mkcert -cert-file local-server.pem -key-file local-server-key.pem 127.0.0.1

Client Authentication Certificates

For mutual TLS (mTLS) scenarios where a service needs to authenticate clients by IP address:

mkcert -client 10.0.0.5

This adds the ExtKeyUsageClientAuth flag while still placing 10.0.0.5 in the IP Address SAN field, as implemented in cert.go lines 91-96.

Summary

  • Automatic detection: mkcert uses net.ParseIP, mail.ParseAddress, and url.Parse in main.go to classify arguments as IP addresses, emails, URIs, or DNS names.
  • SAN population: The makeCert method in cert.go populates tpl.IPAddresses for IPs and tpl.URIs for URIs, ensuring proper X.509 encoding.
  • Simple syntax: Run mkcert <ip> or mkcert <uri> without special flags—mkcert handles the certificate structure automatically.
  • Key usage: Server authentication EKU is automatically added for IP and URI entries, with optional client authentication via the -client flag.

Frequently Asked Questions

Can mkcert generate certificates for private IP ranges?

Yes. mkcert treats any valid IP address parsed by net.ParseIP equally, whether it is a public routable address or a private range such as 192.168.x.x, 10.x.x.x, or 172.16.x.x. The certificate will contain an IP Address SAN entry that TLS clients will match against the connection address.

Does mkcert support IPv6 addresses?

Yes. mkcert fully supports IPv6 addresses in standard notation, such as ::1 for localhost or 2001:db8::1 for specific addresses. The net.ParseIP function in main.go handles both IPv4 and IPv6 formats, and cert.go appends them to the tpl.IPAddresses slice for inclusion in the final certificate.

What URI schemes are supported by mkcert?

mkcert accepts any URI that url.Parse can parse with a non-empty scheme and host, including https://, http://, spiffe://, and custom schemes. However, only the scheme and host components are preserved in the certificate's SAN extension; paths, query parameters, and fragments are stripped during processing in cert.go because the X.509 standard does not support them in URI SAN entries.

How do I install the generated certificate on a mobile device?

First, generate a PKCS#12 (PFX) bundle instead of separate PEM files using the -pkcs12 flag: mkcert -pkcs12 example.com 192.168.1.5. Then transfer the .p12 file to your mobile device. On iOS, you can email the file or use AirDrop, then install it via Settings > General > VPN & Device Management. On Android, open the file in a file manager to trigger the installation prompt. You will also need to install the mkcert root CA on the device to trust the certificate.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →