1<!DOCTYPE html> 2<html lang=" en-US" data-theme="dark"> 3 4<head> 5
5<script> 6 (function () { 7 var saved = localStorage.getItem('theme') || 'dark'; 8 document.documentElement.setAttribute('data-theme', saved); 9 })(); 10 </script>
10 11 <meta charset="UTF-8"> 12 <!-- Begin Jekyll SEO tag v2.8.0 --> 13<title>Trusting a self-signed localhost certificate in Chrome on Linux | Daniel Opitz - Blog</title> 14<meta name="generator" content="Jekyll v3.10.0" /> 15<meta property="og:title" content="Trusting a self-signed localhost certificate in Chrome on Linux" /> 16<meta property="og:locale" content="en_US" /> 17<meta name="description" content="Trust a self-signed localhost HTTPS certificate in Chrome on Ubuntu, Linux Mint, and other Debian-based Linux distributions." /> 18<meta property="og:description" content="Trust a self-signed localhost HTTPS certificate in Chrome on Ubuntu, Linux Mint, and other Debian-based Linux distributions." /> 19<link rel="canonical" href="https://odan.github.io/2026/09/02/trusting-self-signed-certificate-on-linux.html" /> 20<meta property="og:url" content="https://odan.github.io/2026/09/02/trusting-self-signed-certificate-on-linux.html" /> 21<meta property="og:site_name" content="Daniel Opitz - Blog" /> 22<meta property="og:type" content="article" /> 23<meta property="article:published_time" content="2026-09-02T00:00:00+00:00" /> 24<meta name="twitter:card" content="summary" /> 25<meta property="twitter:title" content="Trusting a self-signed localhost certificate in Chrome on Linux" />
26<script type="application/ld+json"> 27{"@context":"https://schema.org","@type":"BlogPosting","dateModified":"2026-09-02T00:00:00+00:00","datePublished":"2026-09-02T00:00:00+00:00","description":"Trust a self-signed localhost HTTPS certificate in Chrome on Ubuntu, Linux Mint, and other Debian-based Linux distributions.","headline":"Trusting a self-signed localhost certificate in Chrome on Linux","mainEntityOfPage":{"@type":"WebPage","@id":"https://odan.github.io/2026/09/02/trusting-self-signed-certificate-on-linux.html"},"url":"https://odan.github.io/2026/09/02/trusting-self-signed-certificate-on-linux.html"}</script>
27 28<!-- End Jekyll SEO tag --> 29 30 <meta name="viewport" content="width=device-width, initial-scale=1"> 31 <meta name="theme-color" content="#1e293b"> 32 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> 33 34 <meta name="keywords" content="chrome, localhost, https, ssl, tls, self-signed certificate, linux, ubuntu, linux mint, certutil, nss" /> 35 36 <link rel="alternate" type="application/rss+xml" title="Subscribe to What's New" 37 href="https://odan.github.io/feed.xml" /> 38 <link rel="preconnect" href="https://fonts.bunny.net"> 39 <link rel="stylesheet" href="/assets/css/style.css?v=e9a526afe686618291ddcbf01fc2dc3799c141f8"> 40 <link href="https://fonts.bunny.net/css?family=inter:400,500,600,700,800|jetbrains-mono:400,500" rel="stylesheet" /> 41 <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?"> 42
42<script type="module" 43 src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@latest/dist/turbo.es2017-esm.min.js"></script>
43 44 <meta name="view-transition" content="same-origin"> 45 <meta name="turbo-prefetch" content="false"> 46 <meta name="turbo-refresh-method" content="morph"> 47 <meta name="turbo-refresh-scroll" content="preserve"> 48</head> 49 50<body> 51 <nav> 52 <div class="nav-inner"> 53 <a href="/" class="nav-logo">odan/blog</a> 54 <div class="nav-links" id="nav-links"> 55 <a href="/">Blog</a> 56 <a href="/about.html">About</a> 57 <a href="/donate.html">Donate</a> 58 <a href="/search.html">Search</a> 59 </div> 60 <button class="theme-btn" id="toggle-mode" aria-label="Toggle dark/light mode">☾</button> 61 <button class="hamburger" id="hamburger" aria-label="Menu">☰</button> 62 </div> 63 <div class="nav-overlay" id="nav-overlay"></div> 64 </nav> 65 66 <header class="hero" role="banner"> 67 <div class="hero-bg"></div> 68 <div class="hero-content"> 69 <h1>Daniel Opitz - Blog</h1> 70 <p>Developer, Trainer, Open Source Contributor</p> 71 </div> 72 </header> 73 74 <main id="content" class="container-wide" role="main"> 75 <article> 76 <div class="breadcrumb"> 77 <a href="/">Blog</a> 78 79 / <span>2026</span> 80 / <span>Trusting a self-signed localhost certificate in Chrome on Linux</span> 81 </div> 82 83 <h1>Trusting a self-signed localhost certificate in Chrome on Linux</h1> 84 85 <div class="post-meta"> 86 <img src="https://odan.github.io/assets/images/dopitz3.png" alt="Daniel Opitz" class="avatar"> 87 <div class="post-meta-text"> 88 <span class="author-name">Daniel Opitz</span> 89 <span class="post-date"> 90 91 02. September 2026 92 93 94 </span> 95 </div> 96 </div> 97 98 99 <div class="tags"> 100 101 </div> 102 103 104 <hr> 105 106 <p>When developing locally over HTTPS, Chrome may reject a self-signed certificate with:</p> 107 108<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>NET::ERR_CERT_AUTHORITY_INVALID 109</code></pre></div></div> 110 111<p>For example, a development profile might serve HTTPS using a certificate stored at:</p> 112 113<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>src/main/resources/certs/localhost.pem 114</code></pre></div></div> 115 116<p>On Ubuntu, Linux Mint, and other Debian-based distributions, you can trust the certificate in Chrome by adding it to the userâs NSS certificate database.</p> 117 118<h2 id="install-the-nss-tools">Install the NSS tools</h2> 119 120<p>Install <code class="language-plaintext highlighter-rouge">certutil</code>:</p> 121 122<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>libnss3-tools 123</code></pre></div></div> 124 125<h2 id="create-the-nss-certificate-database">Create the NSS certificate database</h2> 126 127<p>Chrome uses an NSS database for user certificates. Create it if it does not already exist:</p> 128 129<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> <span class="nt">-p</span> <span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.pki/nssdb"</span> 130certutil <span class="nt">-d</span> sql:<span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.pki/nssdb"</span> <span class="nt">-N</span> <span class="nt">--empty-password</span> 131</code></pre></div></div> 132 133<p>If the database already exists, the second command may not be necessary.</p> 134 135<h2 id="add-the-localhost-certificate">Add the localhost certificate</h2> 136 137<p>From the project root, import the development certificate:</p> 138 139<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>certutil <span class="se">\</span> 140 <span class="nt">-d</span> sql:<span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.pki/nssdb"</span> <span class="se">\</span> 141 <span class="nt">-A</span> <span class="se">\</span> 142 <span class="nt">-t</span> <span class="s2">"P,,"</span> <span class="se">\</span> 143 <span class="nt">-n</span> <span class="s2">"localhost"</span> <span class="se">\</span> 144 <span class="nt">-i</span> src/main/resources/certs/localhost.pem 145</code></pre></div></div> 146 147<p>You can verify that it was added with:</p> 148 149<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>certutil <span class="nt">-d</span> sql:<span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.pki/nssdb"</span> <span class="nt">-L</span> 150</code></pre></div></div> 151 152<p>You should see an entry named <code class="language-plaintext highlighter-rouge">localhost</code>.</p> 153 154<h2 id="restart-chrome">Restart Chrome</h2> 155 156<p>Close Chrome completely, including any background processes, and start it again.</p> 157 158<p>Then open:</p> 159 160<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://localhost 161</code></pre></div></div> 162 163<p>Chrome should now accept the local certificate without showing <code class="language-plaintext highlighter-rouge">NET::ERR_CERT_AUTHORITY_INVALID</code>.</p> 164 165<h2 id="removing-the-certificate">Removing the certificate</h2> 166 167<p>If you no longer need the certificate, remove it from the NSS database with:</p> 168 169<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>certutil <span class="nt">-d</span> sql:<span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.pki/nssdb"</span> <span class="nt">-D</span> <span class="nt">-n</span> <span class="s2">"localhost"</span> 170</code></pre></div></div> 171 172<p>This setup is intended for local development only. Self-signed localhost certificates should not be used as a replacement for certificates issued by a trusted certificate authority in production.</p> 173 174 175 <div class="author-box"> 176 <img src="https://odan.github.io/assets/images/dopitz3.png" alt="Daniel Opitz"> 177 <div> 178 <h4>Daniel Opitz</h4> 179 <p>Developer, Trainer & Open Source Contributor. Passionate about PHP, Slim Framework, and clean code.</p> 180 </div> 181 </div> 182 183 <div class="share">
184 <span>Share:</span> 185 <a href="https://x.com/intent/tweet?text=Trusting+a+self-signed+localhost+certificate+in+Chrome+on+Linux&url=https%3A%2F%2Fodan.github.io%2F2026%2F09%2F02%2Ftrusting-self-signed-certificate-on-linux.html" target="_blank">X</a> 186 <a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fodan.github.io%2F2026%2F09%2F02%2Ftrusting-self-signed-certificate-on-linux.html" target="_blank">Facebook</a> 187 <a href="https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fodan.github.io%2F2026%2F09%2F02%2Ftrusting-self-signed-certificate-on-linux.html&title=Trusting+a+self-signed+localhost+certificate+in+Chrome+on+Linux" target="_blank">LinkedIn</a> 188 </div> 189 190 191 <div class="comments"> 192 <h3>Comments</h3> 193
193<script src="https://utteranc.es/client.js" 194 repo="odan/odan.github.io" 195 issue-term="pathname" 196 theme="github-light" 197 crossorigin="anonymous" 198 async 199 id="utterances-script"> 200</script>
vendor: 2 bytes, line 200
200
201<script> 202 (function() { 203 var theme = document.documentElement.getAttribute('data-theme'); 204 if (theme === 'dark') { 205 var s = document.getElementById('utterances-script'); 206 s.setAttribute('theme', 'github-dark'); 207 } 208 })(); 209</script>
209 210 </div> 211 212</article> 213 214<a href="/" class="back-top">↑ Back to Blog</a> 215 216 217 <footer> 218 © 2026 Daniel Opitz 219 | <a href="https://x.com/dopitz" target="_blank">X</a> 220 | <a href="https://github.com/odan" target="_blank">GitHub</a> 221 | <a href="https://www.linkedin.com/in/daniel-opitz-493816111" target="_blank">LinkedIn</a> 222 | <a href="https://odan.github.io/feed.xml" target="_blank">RSS</a> 223 </footer> 224 </main> 225 226
226<script> 227 (function () { 228 document.getElementById('toggle-mode').addEventListener('click', function (e) { 229 var cur = document.documentElement.getAttribute('data-theme'); 230 var next = cur === 'dark' ? 'light' : 'dark'; 231 document.documentElement.setAttribute('data-theme', next); 232 localStorage.setItem('theme', next); 233 }); 234 235 var hamburger = document.getElementById('hamburger'); 236 var navLinks = document.getElementById('nav-links'); 237 var overlay = document.getElementById('nav-overlay'); 238 if (hamburger && navLinks) { 239 function closeMenu() { 240 navLinks.classList.remove('open'); 241 overlay.classList.remove('open'); 242 document.body.classList.remove('nav-open'); 243 } 244 hamburger.addEventListener('click', function () { 245 navLinks.classList.toggle('open'); 246 overlay.classList.toggle('open'); 247 document.body.classList.toggle('nav-open'); 248 }); 249 overlay.addEventListener('click', closeMenu); 250 navLinks.querySelectorAll('a').forEach(function (link) { 251 link.addEventListener('click', closeMenu); 252 }); 253 } 254 })(); 255 </script>
255 256</body> 257 258</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.