Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

38 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Local HTTPS πŸ”’

(Previously pihole-https)

Local Root CA and auto-renewed HTTPS certificates for private networks and services
with automatic deployment to Pi-hole, Technitium, and Tailscale

local-https creates a local Root CA and issues a server certificate for your machine, so you can access web UIs over HTTPS without browser warnings (after trusting the Root CA on your devices).

It can automatically deploy certificates and reload supported services:

  • βœ… Pi-hole (FTL webserver or Lighttpd)
  • βœ… Technitium DNS (uses a password-protected .pfx)
  • βœ… Tailscale (adds your Tailscale DNS name to the certificate SANs)

It is officially supported on Debian-based distributions (Debian, Ubuntu, Raspberry Pi OS, Armbian). Other Linux distributions may work but are not officially supported.

πŸš€ One-Step Install / Update

curl -fsSL https://raw.githubusercontent.com/luizbizzio/local-https/main/install.sh | sudo bash

The installer downloads and verifies the latest local-https, then installs it to /usr/local/sbin/local-https.

On a new installation, or if the initial setup was never completed, it asks whether you want to start the setup. If local-https is already configured, running the same command only updates the program and keeps your existing certificates and configuration.


✨ What it does

  • πŸ” Creates (or reuses) a local Root CA (rootCA.crt)
  • πŸͺͺ Issues a server certificate (default: 40 days) with SANs for:
    • hostname
    • relevant LAN IPs (filtered)
    • a configurable domain name (default pi.hole)
    • Tailscale DNS name when available
  • πŸ“¦ Generates:
    • server.pem (cert + key, for services like Pi-hole)
    • server.pfx (password-protected, for services like Technitium)
  • πŸ” Can enable automatic renewal via systemd timer (or cron fallback)
  • ⬆️ Can check GitHub for a newer version and update itself with --update
  • 🧠 On renewal, it only β€œdeploys/restarts” if a new cert was actually created (unless forced)

🧭 Usage

Command What it does
local-https --version / --v / -V Prints the installed local-https version
sudo local-https --update Checks GitHub for a newer version and asks before updating
sudo local-https --update --yes Updates without asking for confirmation
sudo local-https --install Full setup (Root CA, server cert, PEM/PFX, permissions, auto-renew, optional Pi-hole deploy, Technitium TLS if detected)
sudo local-https --renew Renew if needed (near expiry window). If nothing to do, exits fast
sudo local-https --renew --force-renew Forces a new server certificate + rebuilds PFX + restarts detected services
sudo local-https --status Shows the installed version, current status, and last run info
sudo local-https --check Exit code indicates if renewal is needed
sudo local-https --configure Re-run deploy steps for Pi-hole / Technitium without reinstalling everything
sudo local-https --print-ca Prints rootCA.crt (useful to copy to devices)
sudo local-https --print-pfx-pass Prints the PFX password (stored in a root-only file)
sudo local-https --rotate-pfx-pass Rotates PFX password, rebuilds PFX, updates Technitium TLS settings
sudo local-https --uninstall [--yes] [--purge-certs] Removes installed files and optionally deletes generated certs

⬆️ Updating later

Once installed, you can check for a newer version without using the full curl command again:

sudo local-https --update

If a newer version is available, local-https shows the current and latest versions and asks before installing it. The update only replaces the program itself; your existing Root CA, certificates, state, and service configuration are kept.

For non-interactive updates:

sudo local-https --update --yes

βš™οΈ Reconfigure services

Use --configure when you want to re-detect and reapply supported service integrations without reinstalling local-https.

sudo local-https --configure

This re-checks Pi-hole and Technitium, reapplies certificate permissions and TLS deployment, and keeps your existing Root CA and installation.

This is useful after installing or changing Pi-hole or Technitium, or when you want to run the integration setup again.


🌐 Custom domain

The certificate includes a friendly domain name (default pi.hole). If your network uses a different local domain, you can configure it. The chosen domain is added to the certificate SANs and is remembered across renewals (stored in the state file).

The domain is resolved with the following precedence (highest first):

  1. CLI flag – --domain (works with --install, --configure, and --renew):
    sudo local-https --install --domain home.lan
    sudo local-https --configure --domain dns.home
    sudo local-https --renew --force-renew --domain home.lan
  2. Environment variable – LOCAL_HTTPS_DOMAIN:
    sudo LOCAL_HTTPS_DOMAIN=home.lan local-https --install
  3. Persisted state – whatever was chosen on the previous run (so renewals stay consistent).
  4. Pi-hole auto-detection – on a fresh install, if Pi-hole is detected the script reads its configured webserver.domain (via pihole-FTL --config, falling back to /etc/pihole/pihole.toml) and uses that as the default.
  5. Default – pi.hole.

During an interactive --install/--configure you are also prompted, pre-filled with the resolved value (press Enter to keep it).

To change the domain on an existing install, run sudo local-https --configure --domain <name> (or sudo local-https --renew --force-renew --domain <name>). The Root CA stays the same, so there is nothing new to trust on your devices.


πŸ” Auto-renew (how it works)

  • πŸ“… The server certificate is issued for 40 days.
  • ⏳ --renew only renews when the cert is close to expiry (default window: 7 days).
  • 🧩 If you enable systemd timer, it runs daily (with randomized delay).

Check the timer:

systemctl list-timers | grep local-https
systemctl status local-https-renew.timer --no-pager

See logs:

journalctl -u local-https-renew.service -n 100 --no-pager

Force-run via systemd (without editing unit files):

sudo systemd-run --unit=local-https-renew-force --service-type=oneshot   /usr/local/sbin/local-https --renew --force-renew

🧩 Service support

🟦 Pi-hole

  • Detects Pi-hole automatically.
  • Supports:
    • FTL webserver TLS (Pi-hole 6+)
    • Lighttpd TLS (older setups)
  • On renew (when a new cert is created), it restarts the correct service so the new cert is used.

🟩 Technitium DNS

  • If Technitium is detected, the script can configure Technitium Web UI TLS to use:
    • server.pfx + the stored password
  • Supports both legacy Technitium Linux installations running as root and newer non-root installations.
  • If the Technitium dns-server account exists, it is automatically granted access to the certs group. Custom non-root Technitium service users are supported as well.
  • If the Technitium systemd service restricts filesystem access, local-https automatically creates a systemd drop-in granting read-only access to server.pfx.
  • On renew (when a new cert is created), it restarts the Technitium service so the new cert is loaded.

πŸŸͺ Tailscale

  • If tailscale and jq are available, the script adds your Tailscale DNS name (like host.ts.net) to the certificate SANs.

βš™οΈ Other services (Grafana, Nginx, etc.)

Any service that needs to read the certificate files can be granted access by adding its user to the certs group:

sudo usermod -aG certs grafana
sudo usermod -aG certs nginx

Group membership is preserved across renewals, once added, the service will continue to have access after every certificate rotation without any manual intervention.

Some hardened systemd services may also restrict filesystem access and require an explicit ReadOnlyPaths= rule for certificate files.


πŸ“¦ Files created

Default folder:

  • /etc/ssl/servercerts

Main files:

  • rootCA.crt and rootCA.key (local Root CA)
  • server.crt, server.key, server.pem
  • server.pfx and .pfx-pass (password file)

State:

  • /var/lib/local-https/state.env

Technitium systemd integration (non-root installations only):

  • /etc/systemd/system/<technitium-service>.d/local-https.conf

πŸ“±πŸ’» Install the Root CA on your devices

You must trust rootCA.crt on your device to avoid HTTPS warnings.

Get the certificate from the server:

  • Print in terminal: sudo local-https --print-ca
  • Or copy the file: /etc/ssl/servercerts/rootCA.crt

πŸͺŸ Windows

  1. Copy rootCA.crt to your PC.
  2. Double-click it β†’ Install Certificate
  3. Choose Local Machine
  4. Put it in Trusted Root Certification Authorities
  5. Reopen the browser.

🍏 macOS

  1. Open Keychain Access
  2. Drag rootCA.crt into System keychain
  3. Open the cert β†’ set Trust to Always Trust

πŸ“± iOS / iPadOS

  1. AirDrop/email the rootCA.crt to the device, open it
  2. Settings β†’ General β†’ VPN & Device Management β†’ install profile
  3. Settings β†’ General β†’ About β†’ Certificate Trust Settings β†’ enable full trust

πŸ€– Android

  1. Copy rootCA.crt to the phone
  2. Settings β†’ Security β†’ Encryption & credentials β†’ Install a certificate β†’ CA certificate
  3. Note: some apps ignore user-installed CAs.

🐧 Linux (Debian/Ubuntu)

sudo cp rootCA.crt /usr/local/share/ca-certificates/local-https-rootCA.crt
sudo update-ca-certificates

Why 40-day certificates

Public TLS Certificate Authorities and browser policies now favor shorter lifetimes (around 40–45 days) for security reasons. Our default 40-day validity matches this industry trend and avoids issues with browser trust and automated renewals. See SSL.com’s discussion on ~47-day certificates: https://www.ssl.com/article/preparing-for-47-day-ssl-tls-certificates/


πŸ“ Notes

  • 🏷️ When reporting an issue, include the output of local-https --version.
  • 🧱 This is a local CA. It is for your own network and devices, not public HTTPS.
  • πŸ§ͺ If you are testing renew: use sudo local-https --renew --force-renew and confirm the new notAfter date with OpenSSL.
  • πŸ”§ Pi-hole Lighttpd mode may install lighttpd-mod-openssl via apt-get.
  • 🐳 Not intended for container-based TLS termination or Docker ingress setups.
  • 🧷 The PFX password is stored in a root-only file. Treat it as a secret.
  • πŸ”„ The certs group membership is preserved on every renew, any user or service manually added to the group (e.g. grafana, nginx) will automatically retain access after certificate rotation.

πŸ“„ License

This repository is licensed under the Mozilla Public License Version 2.0

Releases

Sponsor this project

Used by

Contributors

Languages