PageSourceSearch

https://odan.github.io/2026/09/02/trusting-self-signed-certificate-on-linux.html

html odan.github.io collected 2026-10-03 09:42:20 UTC 12,807 bytes, 258 lines download raw bytes

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">&#9790;</button>
61            <button class="hamburger" id="hamburger" aria-label="Menu">&#9776;</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 &amp; 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">&uarr; Back to Blog</a>
215
216
217        <footer>
218            &copy; 2026 Daniel Opitz
219            &nbsp;|&nbsp; <a href="https://x.com/dopitz" target="_blank">X</a>
220            &nbsp;|&nbsp; <a href="https://github.com/odan" target="_blank">GitHub</a>
221            &nbsp;|&nbsp; <a href="https://www.linkedin.com/in/daniel-opitz-493816111" target="_blank">LinkedIn</a>
222            &nbsp;|&nbsp; <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.