Introduction
You've probably heard you should "always use HTTPS," but when you're working on a local server — something that never touches the public internet — it's easy to wonder if it really matters. The honest answer is: sometimes yes, sometimes no. But when it does matter, getting it set up is actually pretty easy.
I recently went through this for a local Ubuntu server I've been running on my home network, and I wanted
to access it by a proper hostname (swerver.local) over HTTPS from both my Mac and a Windows
machine.
This is because there are a lot of Chrome APIs, and protocols like WebDAV that simply will not run without a valid HTTPS certificate.
Here is what I learned during that process.
Does HTTPS Even Matter on a Local Network?
Before setting anything up, it's worth thinking about whether you actually need it. Local traffic doesn't travel over the public internet, so the biggest HTTPS threat — someone intercepting your data in transit — is mostly not a concern on a trusted home or office LAN.
That said, there are real reasons HTTPS matters locally:
- Browser security APIs require it. (the reason I started this project) Service Workers, the Web Crypto API, camera/microphone access, WebAuthn, push notifications — none of these work without a secure context. Browsers treat
localhostas secure, but a custom hostname likeswerver.localis not treated that way automatically. - Mixed content rules. If your local app calls an external HTTPS API, some browsers will block those requests from an HTTP page.
- Parity with production. Developing over HTTP and deploying to HTTPS can hide subtle bugs — cookie
Secureflags, HSTS behavior, redirect logic, etc.
For pure solo dev on localhost, HTTP is fine. Once you move to a custom hostname or need
any of those browser APIs, HTTPS is worth the small setup cost. And with the right tools, it's maybe
15 minutes of work.
What You'll Need
To get this setup, you'll need two computers on the same network. One will be acting as the server, and the other will be acting as the client. My server (I call it swerver because it's a server where things can get a little sideways — dad joke, sorry not sorry) is running Ubuntu 26.04 LTS. I used both Windows and Mac for the client and both worked fine for the HTTPS setup. All the commands we'll talk about will be in terms of the Ubuntu server.
With that out of the way, let's get started!
The Tool: mkcert
mkcert is the right tool for this. It creates a local Certificate Authority (CA) on your machine and issues certs that your browsers fully trust — no warnings, no clicking through scary dialogs. The key insight is that you install the CA cert on each client machine, and then any cert mkcert issues on the server will be trusted automatically. And bonus points for it being free and open source!
Step 1: Set Up mkcert on the Ubuntu Server
First, open a bash environment (terminal on the server, or ssh) and install the dependency and grab the mkcert binary:
bashsudo apt install libnss3-tools -y
curl -Lo mkcert https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64
chmod +x mkcert
sudo mv mkcert /usr/local/bin/
Then create the local CA and generate a cert. Include both your hostname and your server's LAN IP address — that way connections using either will work:
bashmkcert -install
mkcert HOSTNAME IP_ADDRESS
Replacing the HOSTNAME, and IP_ADDRESS with the appropriate info for your local server. For example:
bashmkcert swerver.local 192.168.1.50
This produces two files: swerver.local+1.pem (the cert) and swerver.local+1-key.pem (the private key). Note where your CA root lives — you'll need it soon:
bashmkcert -CAROOT
# → /root/.local/share/mkcert
Step 2: Point Your Server at the Cert
However you're serving content, point it at those two files. Here's nginx as an example — it's a common choice for proxying a Node app or serving static files (I had AI generate this config — I ran a Python script and a C# app, both of which consume the cert files directly):
nginxserver {
listen 443 ssl;
server_name swerver.local;
ssl_certificate /home/youruser/swerver.local+1.pem;
ssl_certificate_key /home/youruser/swerver.local+1-key.pem;
location / {
proxy_pass http://localhost:3000;
}
}
bashsudo ln -s /etc/nginx/sites-available/swerver /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Note on port 443: Binding to port 443 requires sudo on Linux. If you'd rather not do that, run on port 4443 and access the server at https://swerver.local:4443.
Step 3: Copy the CA Cert to Your Client Machines
This is the step people miss. The cert mkcert issued is trusted because it's signed by mkcert's local CA —
but your Mac and Windows machine don't know about that CA yet. You need to copy rootCA.pem
from the server to each client.
bash — run on your Mac or Windows machinescp user@192.168.1.50:~/.local/share/mkcert/rootCA.pem ~/Desktop/
The path above assumes mkcert was run as your regular user. If you ran it as root (e.g. sudo mkcert), the CA lives at /root/.local/share/mkcert/rootCA.pem instead. You can always check with mkcert -CAROOT on the server.
It's not a secret — it's a public cert — so feel free to copy it however is convenient.
Step 4: Trust the CA on Mac
From the terminal:
bashsudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain ~/Desktop/rootCA.pem
Or via the GUI: double-click rootCA.pem → Keychain Access opens → find the cert → double-click → expand Trust → set to Always Trust.
Then add the hostname to /etc/hosts:
bashsudo nano /etc/hosts
# add:
192.168.1.50 swerver.local
Now https://swerver.local should load cleanly in any browser.
Step 5: Trust the CA on Windows
- Double-click
rootCA.pem→ click Install Certificate - Choose Local Machine → Next
- Select Place all certificates in the following store → Browse → Trusted Root Certification Authorities
- Finish
Then add the hostname. Open Notepad as Administrator and edit:
pathC:\Windows\System32\drivers\etc\hosts
Add the same line:
hosts192.168.1.50 swerver.local
That covers Chrome and Edge. Firefox manages its own cert store — if you use it, go to
about:preferences#privacy → View Certificates → Authorities → Import → pick rootCA.pem.
That's it. The whole thing — CA setup, cert generation, nginx config, and trusting the cert on two different operating systems — takes maybe 15 minutes once you've done it once. And once it's done, you get a proper green padlock and access to the full browser security API surface, which is worth it if you're doing anything beyond the most basic local development.