index.html (14255B)
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <title> 6 Hugo and nip-05 · Jack Mordaunt 7 </title> 8 <meta charset="utf-8"> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 10 <meta name="color-scheme" content="light dark"> 11 12 13 14 15 <meta name="author" content="Jack Mordaunt"> 16 <meta name="description" content="Setup nostr nip-05 with a Hugo site."> 17 <meta name="keywords" content="blog,developer,personal,software,robust,performance,sovereign"> 18 19 20 21 <meta name="twitter:card" content="summary"> 22 <meta name="twitter:title" content="Hugo and nip-05"> 23 <meta name="twitter:description" content="Setup nostr nip-05 with a Hugo site."> 24 25 <meta property="og:url" content="http://jackmordaunt.com/posts/hugo-nip-05/"> 26 <meta property="og:site_name" content="Jack Mordaunt"> 27 <meta property="og:title" content="Hugo and nip-05"> 28 <meta property="og:description" content="Setup nostr nip-05 with a Hugo site."> 29 <meta property="og:locale" content="en"> 30 <meta property="og:type" content="article"> 31 <meta property="article:section" content="posts"> 32 <meta property="article:published_time" content="2025-07-16T14:57:56-03:00"> 33 <meta property="article:modified_time" content="2025-07-16T14:57:56-03:00"> 34 <meta property="article:tag" content="Hugo"> 35 <meta property="article:tag" content="Nostr"> 36 37 38 39 40 <link rel="canonical" href="http://jackmordaunt.com/posts/hugo-nip-05/"> 41 42 43 <link rel="preload" href="/fonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin> 44 <link rel="preload" href="/fonts/fa-regular-400.woff2" as="font" type="font/woff2" crossorigin> 45 <link rel="preload" href="/fonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin> 46 47 48 49 50 <link rel="stylesheet" href="/css/coder.min.6445a802b9389c9660e1b07b724dcf5718b1065ed2d71b4eeaf981cc7cc5fc46.css" integrity="sha256-ZEWoArk4nJZg4bB7ck3PVxixBl7S1xtO6vmBzHzF/EY=" crossorigin="anonymous" media="screen" /> 51 52 53 54 55 56 57 58 59 60 <link rel="stylesheet" href="/css/coder-dark.min.a00e6364bacbc8266ad1cc81230774a1397198f8cfb7bcba29b7d6fcb54ce57f.css" integrity="sha256-oA5jZLrLyCZq0cyBIwd0oTlxmPjPt7y6KbfW/LVM5X8=" crossorigin="anonymous" media="screen" /> 61 62 63 64 65 66 67 68 <link rel="stylesheet" href="/css/custom.min.931a9d02d6f7655cd0cd50317fac1204e00c54ffd0232085acc957b2db5e1283.css" integrity="sha256-kxqdAtb3ZVzQzVAxf6wSBOAMVP/QIyCFrMlXstteEoM=" crossorigin="anonymous" media="screen" /> 69 70 71 72 73 74 75 <link rel="icon" type="image/svg+xml" href="/images/self-tiny-white.svg" sizes="any"> 76 <link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="32x32"> 77 <link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="16x16"> 78 79 <link rel="apple-touch-icon" href="/images/apple-touch-icon.png"> 80 <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png"> 81 82 <link rel="manifest" href="/site.webmanifest"> 83 <link rel="mask-icon" href="/images/safari-pinned-tab.svg" color="#5bbad5"> 84 85 86 87 88 89 90 91 <script defer data-domain="jackmordaunt.com" src="https://plausible.io/js/script.js"></script> 92 93 94 95 96 </head> 97 98 99 100 101 102 103 <body class="preload-transitions colorscheme-auto"> 104 105 <div class="float-container"> 106 <a id="dark-mode-toggle" class="colorscheme-toggle"> 107 <i class="fa-solid fa-adjust fa-fw" aria-hidden="true"></i> 108 </a> 109 </div> 110 111 112 <main class="wrapper"> 113 <nav class="navigation"> 114 <section class="container"> 115 116 <a class="navigation-title" href="http://jackmordaunt.com/"> 117 Jack Mordaunt 118 </a> 119 120 121 <input type="checkbox" id="menu-toggle" /> 122 <label class="menu-button float-right" for="menu-toggle"> 123 <i class="fa-solid fa-bars fa-fw" aria-hidden="true"></i> 124 </label> 125 <ul class="navigation-list"> 126 127 128 <li class="navigation-item"> 129 <a class="navigation-link " href="/posts/">Blog</a> 130 </li> 131 132 <li class="navigation-item"> 133 <a class="navigation-link " href="/about/">About</a> 134 </li> 135 136 <li class="navigation-item"> 137 <a class="navigation-link " href="/projects/">Projects</a> 138 </li> 139 140 <li class="navigation-item"> 141 <a class="navigation-link " href="/contact/">Contact</a> 142 </li> 143 144 <li class="navigation-item"> 145 <a class="navigation-link " href="/pay-with-bitcoin/">Pay</a> 146 </li> 147 148 149 150 </ul> 151 152 </section> 153 </nav> 154 155 156 <div class="content"> 157 158 <section class="container post"> 159 <article> 160 <header> 161 <div class="post-title"> 162 <h1 class="title"> 163 <a class="title-link" href="http://jackmordaunt.com/posts/hugo-nip-05/"> 164 Hugo and nip-05 165 </a> 166 </h1> 167 </div> 168 <div class="post-meta"> 169 <div class="date"> 170 <span class="posted-on"> 171 <i class="fa-solid fa-calendar" aria-hidden="true"></i> 172 <time datetime="2025-07-16T14:57:56-03:00"> 173 July 16, 2025 174 </time> 175 </span> 176 <span class="reading-time"> 177 <i class="fa-solid fa-clock" aria-hidden="true"></i> 178 2-minute read 179 </span> 180 </div> 181 <div class="authors"> 182 <i class="fa-solid fa-user" aria-hidden="true"></i> 183 <a href="/authors/jack-mordaunt/">Jack Mordaunt</a></div> 184 185 <div class="categories"> 186 <i class="fa-solid fa-folder" aria-hidden="true"></i> 187 <a href="/categories/development/">Development</a></div> 188 189 <div class="tags"> 190 <i class="fa-solid fa-tag" aria-hidden="true"></i> 191 <span class="tag"> 192 <a href="/tags/hugo/">Hugo</a> 193 </span> 194 <span class="separator">•</span> 195 <span class="tag"> 196 <a href="/tags/nostr/">Nostr</a> 197 </span></div> 198 199 </div> 200 </header> 201 202 <div class="post-content"> 203 204 <p><a href="https://nostr.how/en/guides/get-verified" class="external-link" target="_blank" rel="noopener">nip-05</a> is a convenience for identifying users on nostr such as <code>mordaunt@jackmordaunt.com</code>, which is 205 shorter and more memorable than a <span class="tooltip"> 206 raw npub 207 <span class="tooltiptext">npub14l0387z0ejfmnn3j38nnalg5p57952d84aqakqguhzx7p7pns2vqg3x78w</span> 208 </span> 209 .</p> 210 <p>It works by making a <code>GET</code> request at <code>jackmordaunt.com/.well-known/nostr.json</code> and extracting the 211 public keys from the JSON response.</p> 212 <p>This quick guide will show you how to host your own with a Hugo site.</p> 213 <h3 id="add-your-configuration"> 214 Add your configuration. 215 <a class="heading-link" href="#add-your-configuration"> 216 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 217 <span class="sr-only">Link to heading</span> 218 </a> 219 </h3> 220 <p>Inside your <code>hugo.toml</code>, add:</p> 221 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[[params.nostr]] 222 </span></span><span style="display:flex;"><span> name = <span style="color:#a5d6ff">"name"</span> 223 </span></span><span style="display:flex;"><span> npub = <span style="color:#a5d6ff">"npub..."</span> 224 </span></span></code></pre></div><p>If you have multiple names you want to host you can add them.</p> 225 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[[params.nostr]] 226 </span></span><span style="display:flex;"><span> name = <span style="color:#a5d6ff">"name1"</span> 227 </span></span><span style="display:flex;"><span> npub = <span style="color:#a5d6ff">"npub..."</span> 228 </span></span><span style="display:flex;"><span>[[params.nostr]] 229 </span></span><span style="display:flex;"><span> name = <span style="color:#a5d6ff">"name2"</span> 230 </span></span><span style="display:flex;"><span> npub = <span style="color:#a5d6ff">"npub..."</span> 231 </span></span><span style="display:flex;"><span>[[params.nostr]] 232 </span></span><span style="display:flex;"><span> name = <span style="color:#a5d6ff">"name3"</span> 233 </span></span><span style="display:flex;"><span> npub = <span style="color:#a5d6ff">"npub..."</span> 234 </span></span></code></pre></div><p>I’ve picked <code>nostr</code> as the subkey, but you can structure this config however you like.</p> 235 <h3 id="define-the-output-type"> 236 Define the output type. 237 <a class="heading-link" href="#define-the-output-type"> 238 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 239 <span class="sr-only">Link to heading</span> 240 </a> 241 </h3> 242 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[outputFormats.nostrjson] 243 </span></span><span style="display:flex;"><span> mediaType = <span style="color:#a5d6ff">"application/json"</span> 244 </span></span><span style="display:flex;"><span> baseName = <span style="color:#a5d6ff">"nostr"</span> 245 </span></span><span style="display:flex;"><span> path = <span style="color:#a5d6ff">".well-known"</span> 246 </span></span><span style="display:flex;"><span> isPlainText = <span style="color:#79c0ff">true</span> 247 </span></span><span style="display:flex;"><span> permalinkable = <span style="color:#79c0ff">true</span> 248 </span></span><span style="display:flex;"><span> notAlternative = <span style="color:#79c0ff">true</span> 249 </span></span><span style="display:flex;"><span> 250 </span></span><span style="display:flex;"><span>[outputs] 251 </span></span><span style="display:flex;"><span> home = [<span style="color:#a5d6ff">"HTML"</span>, <span style="color:#a5d6ff">"nostrjson"</span>] 252 </span></span></code></pre></div><p>This output type tells Hugo that we want to render a JSON file. 253 <code>nostrjson</code> is just the name of this type, you can pick whatever name you like.</p> 254 <p>Read more about output formats <a href="https://gohugo.io/configuration/output-formats" class="external-link" target="_blank" rel="noopener">here</a>.</p> 255 <h3 id="add-the-json-template"> 256 Add the JSON template 257 <a class="heading-link" href="#add-the-json-template"> 258 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 259 <span class="sr-only">Link to heading</span> 260 </a> 261 </h3> 262 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $nostr := .Site.Params.nostr }} 263 </span></span><span style="display:flex;"><span>{ 264 </span></span><span style="display:flex;"><span> "names": { 265 </span></span><span style="display:flex;"><span> {{- range $k, $v := $nostr }} 266 </span></span><span style="display:flex;"><span> "{{ $v.name }}": "{{ printf "%x" $v.npub }}"{{ if not (eq $k (sub ($nostr | len) 1)) }},{{ end }} 267 </span></span><span style="display:flex;"><span> {{- end }} 268 </span></span><span style="display:flex;"><span> } 269 </span></span><span style="display:flex;"><span>} 270 </span></span></code></pre></div><p>This template iterates all nostr configurations under <code>.Site.Params.nostr</code> and renders a key-value entry 271 in the JSON object. The npub is hex encoded because that is the expected format.</p> 272 <p>The complex conditional at the end is simply for placing the commas correctly.</p> 273 <h3 id="build-it"> 274 Build it 275 <a class="heading-link" href="#build-it"> 276 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 277 <span class="sr-only">Link to heading</span> 278 </a> 279 </h3> 280 <p><code>hugo build</code> and verify that the root of the output under <code>public</code> contains <code>.well-known/nostr.json</code> with 281 the correct content!</p> 282 <p>When you publish the site you should be able to get the JSON from doing a <code>GET</code> for <code>.well-known/nostr.json</code>.</p> 283 <p>Lastly, you can specify relays that you are likely to be found on. You’ll have to adjust the template.</p> 284 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span> 285 </span></span><span style="display:flex;"><span>{ 286 </span></span><span style="display:flex;"><span> "names": { 287 </span></span><span style="display:flex;"><span> "YOUR_NOSTR_NAME": "YOUR_NOSTR_PUBLIC_KEY_IN_HEX_FORMAT" 288 </span></span><span style="display:flex;"><span> }, 289 </span></span><span style="display:flex;"><span> "relays": { 290 </span></span><span style="display:flex;"><span> "YOUR_NOSTR_PUBLIC_KEY_IN_HEX_FORMAT": [ 291 </span></span><span style="display:flex;"><span> "wss://relay.one", 292 </span></span><span style="display:flex;"><span> "wss://relay.two", 293 </span></span><span style="display:flex;"><span> ... 294 </span></span><span style="display:flex;"><span> ] 295 </span></span><span style="display:flex;"><span> } 296 </span></span><span style="display:flex;"><span>} 297 </span></span></code></pre></div> 298 </div> 299 300 301 <footer> 302 303 304 305 306 307 308 309 310 311 312 </footer> 313 </article> 314 315 316 </section> 317 318 </div> 319 320 <footer class="footer"> 321 <section class="container"> 322 © 323 324 2025 325 Jack Mordaunt 326 · 327 328 Powered by <a href="https://gohugo.io/" target="_blank" rel="noopener">Hugo</a> & <a href="https://github.com/luizdepra/hugo-coder/" target="_blank" rel="noopener">Coder</a>. 329 330 </section> 331 </footer> 332 333 </main> 334 335 336 337 338 339 <script src="/js/coder.min.6ae284be93d2d19dad1f02b0039508d9aab3180a12a06dcc71b0b0ef7825a317.js" integrity="sha256-auKEvpPS0Z2tHwKwA5UI2aqzGAoSoG3McbCw73gloxc="></script> 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 </body> 381 </html>