131 lines
No EOL
66 KiB
HTML
131 lines
No EOL
66 KiB
HTML
<!doctype html><html lang=en dir=auto><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name=robots content="index, follow"><title>Running my blog on Tor (.onion) and the Clearnet with Hugo + PaperMod | AlipourIm journeys</title>
|
||
<meta name=keywords content="tor,nginx,hugo,papermod,cloudflare,letsencrypt"><meta name=description content="How I hosted a Hugo + PaperMod site both as a Tor onion service and a normal HTTPS site behind Cloudflare, with clean configs, dual builds, and a one-command deploy."><meta name=author content="Iman Alipour"><link rel=canonical href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/tor_clearnet_blog/><link crossorigin=anonymous href=/assets/css/stylesheet.51e3b550fcc0c3f3a10e2d7b70445c6cb21171bed36521d66dc7427208cafbf9.css integrity="sha256-UeO1UPzAw/OhDi17cERcbLIRcb7TZSHWbcdCcgjK+/k=" rel="preload stylesheet" as=style><link rel=icon href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/favicon.ico><link rel=icon type=image/png sizes=16x16 href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/favicon-16x16.png><link rel=icon type=image/png sizes=32x32 href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/favicon-32x32.png><link rel=apple-touch-icon href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/apple-touch-icon.png><link rel=mask-icon href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/safari-pinned-tab.svg><meta name=theme-color content="#2e2e33"><meta name=msapplication-TileColor content="#2e2e33"><link rel=alternate hreflang=en href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/tor_clearnet_blog/><noscript><style>#theme-toggle,.top-link{display:none}</style><style>@media(prefers-color-scheme:dark){:root{--theme:rgb(29, 30, 32);--entry:rgb(46, 46, 51);--primary:rgb(218, 218, 219);--secondary:rgb(155, 156, 157);--tertiary:rgb(65, 66, 68);--content:rgb(196, 196, 197);--code-block-bg:rgb(46, 46, 51);--code-bg:rgb(55, 56, 62);--border:rgb(51, 51, 51)}.list{background:var(--theme)}.list:not(.dark)::-webkit-scrollbar-track{background:0 0}.list:not(.dark)::-webkit-scrollbar-thumb{border-color:var(--theme)}}</style></noscript><meta property="og:url" content="http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/tor_clearnet_blog/"><meta property="og:site_name" content="AlipourIm journeys"><meta property="og:title" content="Running my blog on Tor (.onion) and the Clearnet with Hugo + PaperMod"><meta property="og:description" content="How I hosted a Hugo + PaperMod site both as a Tor onion service and a normal HTTPS site behind Cloudflare, with clean configs, dual builds, and a one-command deploy."><meta property="og:locale" content="en"><meta property="og:type" content="article"><meta property="article:section" content="posts"><meta property="article:published_time" content="2025-09-19T00:00:00+00:00"><meta property="article:modified_time" content="2025-09-19T00:00:00+00:00"><meta property="article:tag" content="Tor"><meta property="article:tag" content="Nginx"><meta property="article:tag" content="Hugo"><meta property="article:tag" content="Papermod"><meta property="article:tag" content="Cloudflare"><meta property="article:tag" content="Letsencrypt"><meta name=twitter:card content="summary"><meta name=twitter:title content="Running my blog on Tor (.onion) and the Clearnet with Hugo + PaperMod"><meta name=twitter:description content="How I hosted a Hugo + PaperMod site both as a Tor onion service and a normal HTTPS site behind Cloudflare, with clean configs, dual builds, and a one-command deploy."><script type=application/ld+json>{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Posts","item":"http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/"},{"@type":"ListItem","position":2,"name":"Running my blog on Tor (.onion) and the Clearnet with Hugo + PaperMod","item":"http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/tor_clearnet_blog/"}]}</script><script type=application/ld+json>{"@context":"https://schema.org","@type":"BlogPosting","headline":"Running my blog on Tor (.onion) and the Clearnet with Hugo + PaperMod","name":"Running my blog on Tor (.onion) and the Clearnet with Hugo \u002b PaperMod","description":"How I hosted a Hugo + PaperMod site both as a Tor onion service and a normal HTTPS site behind Cloudflare, with clean configs, dual builds, and a one-command deploy.","keywords":["tor","nginx","hugo","papermod","cloudflare","letsencrypt"],"articleBody":" TL;DR — The site is built once (Hugo project), published twice:\nOnion: http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/ via Tor, no TLS/HSTS, bound to 127.0.0.1:3301. Clearnet: https://blog.alipourimjourneys.ir behind Cloudflare, Let’s Encrypt cert, Onion-Location header pointing to the onion mirror. 1) Tor hidden service (onion) basics I used Tor’s v3 onion services and mapped onion port 80 → my local web server on 127.0.0.1:3301.\nInstall \u0026 configure Tor (Debian/Ubuntu):\nsudo apt update \u0026\u0026 sudo apt install -y tor sudoedit /etc/tor/torrc Add:\nH H i i d d d d e e n n S S e e r r v v i i c c e e D P i o r r t v 8 a 0 r / 1 l 2 i 7 b . 0 t . o 0 r . 1 h : i 3 d 3 d 0 e 1 n _ s i t e / Make sure the directory is owned by Tor’s user and private:\nsudo mkdir -p /var/lib/tor/hidden_site sudo chown -R debian-tor:debian-tor /var/lib/tor/hidden_site sudo chmod 700 /var/lib/tor/hidden_site Important: use the right systemd unit:\n# validate as the Tor user sudo -u debian-tor tor -f /etc/tor/torrc --verify-config # (re)start the real service sudo systemctl enable --now tor@default sudo systemctl restart tor@default Get the onion address:\nsudo cat /var/lib/tor/hidden_site/hostname Quick check (do remote DNS via SOCKS):\ncurl -I --socks5-hostname 127.0.0.1:9050 \"http://$(sudo cat /var/lib/tor/hidden_site/hostname)\" 2) Nginx for the onion (localhost-only) I keep the onion site strictly on localhost: no HTTPS, no redirects, no HSTS. Tor already provides e2e encryption and authenticity.\n/etc/nginx/sites-available/onion-blog:\nserver { listen 127.0.0.1:3301 default_server; server_name .onion 127.0.0.1 localhost; # keep onion simple; no HSTS/redirects here add_header Referrer-Policy no-referrer always; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options SAMEORIGIN always; # (optional) strict CSP so nothing leaks to clearnet # add_header Content-Security-Policy \"default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'\" always; root /srv/hugo/mysite/public-onion; index index.html; location / { try_files $uri $uri/ /index.html; } location ~* \\.(css|js|ico|png|jpg|jpeg|gif|svg|webp|txt|xml)$ { access_log off; add_header Cache-Control \"public, max-age=31536000, immutable\"; try_files $uri =404; } } Enable/reload:\nsudo ln -sf /etc/nginx/sites-available/onion-blog /etc/nginx/sites-enabled/onion-blog sudo nginx -t \u0026\u0026 sudo systemctl reload nginx Gotcha I hit: I had two server blocks on 127.0.0.1:3301, which caused 404s via onion. Make sure only the intended vhost listens there (or mark it default_server). Also, if you ever use a regex in server_name, the syntax is server_name ~* \\.onion$ (note the space after ~*).\n3) Hugo + PaperMod setup (and version bumps) PaperMod now requires Hugo Extended ≥ 0.146.0. I installed the extended binary from the official tarball to avoid Snap’s sandbox limitations (Snap can’t read /srv paths by default).\n# install Hugo extended (example) VER=0.146.0 cd /tmp wget https://github.com/gohugoio/hugo/releases/download/v${VER}/hugo_extended_${VER}_Linux-amd64.tar.gz tar -xzf hugo_extended_${VER}_Linux-amd64.tar.gz sudo mv hugo /usr/local/bin/hugo hugo version # should say \"extended\" and \u003e= 0.146.0 Create the site and theme:\nsudo mkdir -p /srv/hugo \u0026\u0026 sudo chown -R \"$USER\":\"$USER\" /srv/hugo cd /srv/hugo hugo new site mysite cd mysite git init git submodule add https://github.com/adityatelange/hugo-PaperMod themes/PaperMod Config updates: in newer Hugo, paginate is deprecated → use:\n# config/_default/hugo.toml title = \"My Blog\" theme = \"PaperMod\" enableRobotsTXT = true [pagination] pagerSize = 10 [params] defaultTheme = \"auto\" showReadingTime = true showPostNavLinks = true showBreadCrumbs = true showCodeCopyButtons = true I added per-environment overrides so I can build two outputs with different baseURLs:\n# config/clearnet/hugo.toml baseURL = \"https://blog.alipourimjourneys.ir/\" # config/onion/hugo.toml baseURL = \"http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/\" 4) Dual builds (clearnet + onion) and one-command deploy I publish the same content twice—once for each base URL and docroot:\ncd /srv/hugo/mysite # clearnet build (served over HTTPS) hugo --minify --environment clearnet -d public-clearnet # onion build (served via Tor) hugo --minify --environment onion -d public-onion sudo systemctl reload nginx Helper script I use:\nsudo tee /usr/local/bin/build-both \u003e/dev/null \u003c\u003c'EOF' #!/usr/bin/env bash set -euo pipefail cd /srv/hugo/mysite hugo --minify --environment clearnet -d public-clearnet hugo --minify --environment onion -d public-onion sudo systemctl reload nginx echo \"Deployed both at $(date)\" EOF sudo chmod +x /usr/local/bin/build-both While editing, I sometimes auto-rebuild on file save:\nsudo apt install -y entr cd /srv/hugo/mysite find content layouts assets static config -type f | entr -r build-both 5) Clearnet behind Cloudflare + Let’s Encrypt (manual DNS-01) Cloudflare is set to Full (strict). I issued a public cert for blog.alipourimjourneys.ir using manual DNS-01 (no API token):\nsudo snap install --classic certbot sudo certbot certonly --manual --preferred-challenges dns -d blog.alipourimjourneys.ir --agree-tos -m you@example.com --no-eff-email Certbot tells you to add a TXT record _acme-challenge.blog.alipourimjourneys.ir. Add it in Cloudflare DNS, verify with dig, then continue. Cert ends up at:\n/ / e e t t c c / / l l e e t t s s e e n n c c r r y y p p t t / / l l i i v v e e / / b b l l o o g g . . a a l l i i p p o o u u r r i i m m j j o o u u r r n n e e y y s s . . i i r r / / f p u r l i l v c k h e a y i . n p . e p m e m Clearnet Nginx vhosts:\n# HTTP → HTTPS redirect (optional; CF usually talks HTTPS to origin anyway) server { listen 80; listen [::]:80; server_name blog.alipourimjourneys.ir; return 301 https://blog.alipourimjourneys.ir$request_uri; } # HTTPS origin (behind Cloudflare) server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name blog.alipourimjourneys.ir; ssl_certificate /etc/letsencrypt/live/blog.alipourimjourneys.ir/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/blog.alipourimjourneys.ir/privkey.pem; # HSTS on clearnet only add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\" always; # Help Tor Browser discover the onion mirror (safe on clearnet) add_header Onion-Location \"http://.onion$request_uri\" always; root /srv/hugo/mysite/public-clearnet; index index.html; location / { try_files $uri $uri/ /index.html; } } Note: don’t add HSTS or HTTPS redirects to the onion vhost. Keep onion pure HTTP on localhost.\n6) Troubleshooting I ran into (and fixes) Tor unit confusion: tor.service is a tiny master; the real daemon is tor@default. Use that unit and verify config as debian-tor. Permissions: HiddenServiceDir must be owned by debian-tor and mode 700. Mapping mismatch: If HiddenServicePort 80 127.0.0.1:3301 is set, visit http:/// (no :3301). If you set HiddenServicePort 3301 127.0.0.1:3301, you must use http://:3301/. Curl \u0026 .onion: modern curl refuses .onion unless you use remote DNS via SOCKS: curl -I --socks5-hostname 127.0.0.1:9050 \"http:///\" Two Nginx vhosts on the same port: I had a duplicate server on 127.0.0.1:3301 pointing somewhere else, which caused onion 404s. Keep only one (or mark one default_server). Regex in server_name: if you use it, write server_name ~* \\.onion$ (space after ~*). I fixed an invalid variable name error caused by a missing space. PaperMod with old Hugo: upgraded to extended ≥ 0.146.0. Also updated paginate → [pagination].pagerSize. Snap confinement: Snap’s hugo couldn’t read /srv (.../void: permission denied). Switched to the tarball build in /usr/local/bin. 7) “Not secure” in Tor Browser? That message can appear because onion uses HTTP. It’s OK: Tor provides e2e encryption + onion auth. If you enable HTTPS-Only Mode, add an exception for the site. Also ensure the onion build doesn’t reference clearnet resources (scan the built HTML for http(s):// links that aren’t your onion).\n8) Day-to-day workflow Create content: hugo new posts/my-first-post.md # then set draft: false Publish both: build-both (Optional) Auto on save: find content layouts assets static config -type f | entr -r build-both (Optional) Git push-to-deploy with a bare repo + post-receive hook that runs build-both. Final notes Clearnet gets HTTPS + HSTS and an Onion-Location header. Onion gets no HSTS/redirects, and all assets are self-hosted to avoid mixed content. Serving both worlds from one Hugo repo is easy: two builds, two vhosts, one workflow. ","wordCount":"1264","inLanguage":"en","datePublished":"2025-09-19T00:00:00Z","dateModified":"2025-09-19T00:00:00Z","author":{"@type":"Person","name":"Iman Alipour"},"mainEntityOfPage":{"@type":"WebPage","@id":"http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/tor_clearnet_blog/"},"publisher":{"@type":"Organization","name":"AlipourIm journeys","logo":{"@type":"ImageObject","url":"http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/favicon.ico"}}}</script></head><body id=top><script>localStorage.getItem("pref-theme")==="dark"?document.body.classList.add("dark"):localStorage.getItem("pref-theme")==="light"?document.body.classList.remove("dark"):window.matchMedia("(prefers-color-scheme: dark)").matches&&document.body.classList.add("dark")</script><header class=header><nav class=nav><div class=logo><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/ accesskey=h title="AlipourIm journeys (Alt + H)">AlipourIm journeys</a><div class=logo-switches><button id=theme-toggle accesskey=t title="(Alt + T)" aria-label="Toggle theme"><svg id="moon" width="24" height="18" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg><svg id="sun" width="24" height="18" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg></button></div></div><ul id=menu><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/ title=Posts><span>Posts</span></a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/phd_journey/ title=PhD_journey><span>PhD_journey</span></a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/about/ title=About><span>About</span></a></li></ul></nav></header><main class=main><article class=post-single><header class=post-header><div class=breadcrumbs><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/>Home</a> » <a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/>Posts</a></div><h1 class="post-title entry-hint-parent">Running my blog on Tor (.onion) and the Clearnet with Hugo + PaperMod</h1><div class=post-description>How I hosted a Hugo + PaperMod site both as a Tor onion service and a normal HTTPS site behind Cloudflare, with clean configs, dual builds, and a one-command deploy.</div><div class=post-meta><span title='2025-09-19 00:00:00 +0000 UTC'>September 19, 2025</span> · 6 min · Iman Alipour
|
||
<span class=post-meta-item><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/tor_clearnet_blog/#isso-thread class=isso-comments-link>Comments</a></span></div></header><div class=toc><details open><summary accesskey=c title="(Alt + C)"><span class=details>Table of Contents</span></summary><div class=inner><ul><li><a href=#1-tor-hidden-service-onion-basics aria-label="1) Tor hidden service (onion) basics">1) Tor hidden service (onion) basics</a></li><li><a href=#2-nginx-for-the-onion-localhost-only aria-label="2) Nginx for the onion (localhost-only)">2) Nginx for the onion (localhost-only)</a></li><li><a href=#3-hugo--papermod-setup-and-version-bumps aria-label="3) Hugo + PaperMod setup (and version bumps)">3) Hugo + PaperMod setup (and version bumps)</a></li><li><a href=#4-dual-builds-clearnet--onion-and-one-command-deploy aria-label="4) Dual builds (clearnet + onion) and one-command deploy">4) Dual builds (clearnet + onion) and one-command deploy</a></li><li><a href=#5-clearnet-behind-cloudflare--lets-encrypt-manual-dns-01 aria-label="5) Clearnet behind Cloudflare + Let’s Encrypt (manual DNS-01)">5) Clearnet behind Cloudflare + Let’s Encrypt (manual DNS-01)</a></li><li><a href=#6-troubleshooting-i-ran-into-and-fixes aria-label="6) Troubleshooting I ran into (and fixes)">6) Troubleshooting I ran into (and fixes)</a></li><li><a href=#7-not-secure-in-tor-browser aria-label="7) “Not secure” in Tor Browser?">7) “Not secure” in Tor Browser?</a></li><li><a href=#8-day-to-day-workflow aria-label="8) Day-to-day workflow">8) Day-to-day workflow</a></li><li><a href=#final-notes aria-label="Final notes">Final notes</a></li></ul></div></details></div><div class=post-content><blockquote><p>TL;DR — The site is built once (Hugo project), <strong>published twice</strong>:</p><ul><li><strong>Onion</strong>: <code>http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/</code> via Tor, no TLS/HSTS, bound to <code>127.0.0.1:3301</code>.</li><li><strong>Clearnet</strong>: <code>https://blog.alipourimjourneys.ir</code> behind Cloudflare, Let’s Encrypt cert, <code>Onion-Location</code> header pointing to the onion mirror.</li></ul></blockquote><hr><h2 id=1-tor-hidden-service-onion-basics>1) Tor hidden service (onion) basics<a hidden class=anchor aria-hidden=true href=#1-tor-hidden-service-onion-basics>#</a></h2><p>I used Tor’s v3 onion services and mapped onion port 80 → my local web server on <code>127.0.0.1:3301</code>.</p><p><strong>Install & configure Tor (Debian/Ubuntu):</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>sudo apt update <span style=color:#f92672>&&</span> sudo apt install -y tor
|
||
</span></span><span style=display:flex><span>sudoedit /etc/tor/torrc
|
||
</span></span></code></pre></div><p>Add:</p><div class="goat svg-container"><svg font-family="Menlo,Lucida Console,monospace" viewBox="0 0 344 41"><g transform="translate(8,16)"><path d="M132 8l-8 32" fill="none" stroke="currentcolor"/><path d="M196 8l-8 32" fill="none" stroke="currentcolor"/><path d="M228 8l-8 32" fill="none" stroke="currentcolor"/><text text-anchor="middle" x="0" y="4" fill="currentcolor" style="font-size:1em">H</text><text text-anchor="middle" x="0" y="20" fill="currentcolor" style="font-size:1em">H</text><text text-anchor="middle" x="8" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="8" y="20" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="16" y="4" fill="currentcolor" style="font-size:1em">d</text><text text-anchor="middle" x="16" y="20" fill="currentcolor" style="font-size:1em">d</text><text text-anchor="middle" x="24" y="4" fill="currentcolor" style="font-size:1em">d</text><text text-anchor="middle" x="24" y="20" fill="currentcolor" style="font-size:1em">d</text><text text-anchor="middle" x="32" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="32" y="20" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="40" y="4" fill="currentcolor" style="font-size:1em">n</text><text text-anchor="middle" x="40" y="20" fill="currentcolor" style="font-size:1em">n</text><text text-anchor="middle" x="48" y="4" fill="currentcolor" style="font-size:1em">S</text><text text-anchor="middle" x="48" y="20" fill="currentcolor" style="font-size:1em">S</text><text text-anchor="middle" x="56" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="56" y="20" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="64" y="4" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="64" y="20" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="72" y="4" fill="currentcolor" style="font-size:1em">v</text><text text-anchor="middle" x="72" y="20" fill="currentcolor" style="font-size:1em">v</text><text text-anchor="middle" x="80" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="80" y="20" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="88" y="4" fill="currentcolor" style="font-size:1em">c</text><text text-anchor="middle" x="88" y="20" fill="currentcolor" style="font-size:1em">c</text><text text-anchor="middle" x="96" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="96" y="20" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="104" y="4" fill="currentcolor" style="font-size:1em">D</text><text text-anchor="middle" x="104" y="20" fill="currentcolor" style="font-size:1em">P</text><text text-anchor="middle" x="112" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="112" y="20" fill="currentcolor" style="font-size:1em">o</text><text text-anchor="middle" x="120" y="4" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="120" y="20" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="128" y="20" fill="currentcolor" style="font-size:1em">t</text><text text-anchor="middle" x="144" y="4" fill="currentcolor" style="font-size:1em">v</text><text text-anchor="middle" x="144" y="20" fill="currentcolor" style="font-size:1em">8</text><text text-anchor="middle" x="152" y="4" fill="currentcolor" style="font-size:1em">a</text><text text-anchor="middle" x="152" y="20" fill="currentcolor" style="font-size:1em">0</text><text text-anchor="middle" x="160" y="4" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="168" y="4" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="168" y="20" fill="currentcolor" style="font-size:1em">1</text><text text-anchor="middle" x="176" y="4" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="176" y="20" fill="currentcolor" style="font-size:1em">2</text><text text-anchor="middle" x="184" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="184" y="20" fill="currentcolor" style="font-size:1em">7</text><text text-anchor="middle" x="192" y="4" fill="currentcolor" style="font-size:1em">b</text><text text-anchor="middle" x="192" y="20" fill="currentcolor" style="font-size:1em">.</text><text text-anchor="middle" x="200" y="20" fill="currentcolor" style="font-size:1em">0</text><text text-anchor="middle" x="208" y="4" fill="currentcolor" style="font-size:1em">t</text><text text-anchor="middle" x="208" y="20" fill="currentcolor" style="font-size:1em">.</text><text text-anchor="middle" x="216" y="4" fill="currentcolor" style="font-size:1em">o</text><text text-anchor="middle" x="216" y="20" fill="currentcolor" style="font-size:1em">0</text><text text-anchor="middle" x="224" y="4" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="224" y="20" fill="currentcolor" style="font-size:1em">.</text><text text-anchor="middle" x="232" y="20" fill="currentcolor" style="font-size:1em">1</text><text text-anchor="middle" x="240" y="4" fill="currentcolor" style="font-size:1em">h</text><text text-anchor="middle" x="240" y="20" fill="currentcolor" style="font-size:1em">:</text><text text-anchor="middle" x="248" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="248" y="20" fill="currentcolor" style="font-size:1em">3</text><text text-anchor="middle" x="256" y="4" fill="currentcolor" style="font-size:1em">d</text><text text-anchor="middle" x="256" y="20" fill="currentcolor" style="font-size:1em">3</text><text text-anchor="middle" x="264" y="4" fill="currentcolor" style="font-size:1em">d</text><text text-anchor="middle" x="264" y="20" fill="currentcolor" style="font-size:1em">0</text><text text-anchor="middle" x="272" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="272" y="20" fill="currentcolor" style="font-size:1em">1</text><text text-anchor="middle" x="280" y="4" fill="currentcolor" style="font-size:1em">n</text><text text-anchor="middle" x="288" y="4" fill="currentcolor" style="font-size:1em">_</text><text text-anchor="middle" x="296" y="4" fill="currentcolor" style="font-size:1em">s</text><text text-anchor="middle" x="304" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="312" y="4" fill="currentcolor" style="font-size:1em">t</text><text text-anchor="middle" x="320" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="328" y="4" fill="currentcolor" style="font-size:1em">/</text></g></svg></div><p>Make sure the directory is owned by Tor’s user and private:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>sudo mkdir -p /var/lib/tor/hidden_site
|
||
</span></span><span style=display:flex><span>sudo chown -R debian-tor:debian-tor /var/lib/tor/hidden_site
|
||
</span></span><span style=display:flex><span>sudo chmod <span style=color:#ae81ff>700</span> /var/lib/tor/hidden_site
|
||
</span></span></code></pre></div><p><strong>Important:</strong> use the right systemd unit:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span><span style=color:#75715e># validate as the Tor user</span>
|
||
</span></span><span style=display:flex><span>sudo -u debian-tor tor -f /etc/tor/torrc --verify-config
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># (re)start the real service</span>
|
||
</span></span><span style=display:flex><span>sudo systemctl enable --now tor@default
|
||
</span></span><span style=display:flex><span>sudo systemctl restart tor@default
|
||
</span></span></code></pre></div><p>Get the onion address:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>sudo cat /var/lib/tor/hidden_site/hostname
|
||
</span></span></code></pre></div><p>Quick check (do remote DNS via SOCKS):</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>curl -I --socks5-hostname 127.0.0.1:9050 <span style=color:#e6db74>"http://</span><span style=color:#66d9ef>$(</span>sudo cat /var/lib/tor/hidden_site/hostname<span style=color:#66d9ef>)</span><span style=color:#e6db74>"</span>
|
||
</span></span></code></pre></div><hr><h2 id=2-nginx-for-the-onion-localhost-only>2) Nginx for the onion (localhost-only)<a hidden class=anchor aria-hidden=true href=#2-nginx-for-the-onion-localhost-only>#</a></h2><p>I keep the onion site strictly on localhost: <strong>no HTTPS, no redirects, no HSTS</strong>. Tor already provides e2e encryption and authenticity.</p><p><code>/etc/nginx/sites-available/onion-blog</code>:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-nginx data-lang=nginx><span style=display:flex><span><span style=color:#66d9ef>server</span> {
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>listen</span> 127.0.0.1:<span style=color:#ae81ff>3301</span> <span style=color:#e6db74>default_server</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>server_name</span> <span style=color:#e6db74><your-56-char>.onion</span> 127.0.0.1 <span style=color:#e6db74>localhost</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e># keep onion simple; no HSTS/redirects here
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#f92672>add_header</span> <span style=color:#e6db74>Referrer-Policy</span> <span style=color:#e6db74>no-referrer</span> <span style=color:#e6db74>always</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>add_header</span> <span style=color:#e6db74>X-Content-Type-Options</span> <span style=color:#e6db74>nosniff</span> <span style=color:#e6db74>always</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>add_header</span> <span style=color:#e6db74>X-Frame-Options</span> <span style=color:#e6db74>SAMEORIGIN</span> <span style=color:#e6db74>always</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e># (optional) strict CSP so nothing leaks to clearnet
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#75715e># add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'" always;
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span>
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>root</span> <span style=color:#e6db74>/srv/hugo/mysite/public-onion</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>index</span> <span style=color:#e6db74>index.html</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>location</span> <span style=color:#e6db74>/</span> { <span style=color:#f92672>try_files</span> $uri $uri/ <span style=color:#e6db74>/index.html</span>; }
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>location</span> ~<span style=color:#e6db74>*</span> <span style=color:#e6db74>\.(css|js|ico|png|jpg|jpeg|gif|svg|webp|txt|xml)</span>$ {
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>access_log</span> <span style=color:#66d9ef>off</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>add_header</span> <span style=color:#e6db74>Cache-Control</span> <span style=color:#e6db74>"public,</span> <span style=color:#e6db74>max-age=31536000,</span> <span style=color:#e6db74>immutable"</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>try_files</span> $uri =<span style=color:#ae81ff>404</span>;
|
||
</span></span><span style=display:flex><span> }
|
||
</span></span><span style=display:flex><span>}
|
||
</span></span></code></pre></div><p>Enable/reload:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>sudo ln -sf /etc/nginx/sites-available/onion-blog /etc/nginx/sites-enabled/onion-blog
|
||
</span></span><span style=display:flex><span>sudo nginx -t <span style=color:#f92672>&&</span> sudo systemctl reload nginx
|
||
</span></span></code></pre></div><blockquote><p>Gotcha I hit: I had <strong>two</strong> server blocks on <code>127.0.0.1:3301</code>, which caused 404s via onion. Make sure only the intended vhost listens there (or mark it <code>default_server</code>). Also, if you ever use a regex in <code>server_name</code>, the syntax is <code>server_name ~* \.onion$</code> (note the space after <code>~*</code>).</p></blockquote><hr><h2 id=3-hugo--papermod-setup-and-version-bumps>3) Hugo + PaperMod setup (and version bumps)<a hidden class=anchor aria-hidden=true href=#3-hugo--papermod-setup-and-version-bumps>#</a></h2><p>PaperMod now requires <strong>Hugo Extended ≥ 0.146.0</strong>. I installed the extended binary from the official tarball to avoid Snap’s sandbox limitations (Snap can’t read <code>/srv</code> paths by default).</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span><span style=color:#75715e># install Hugo extended (example)</span>
|
||
</span></span><span style=display:flex><span>VER<span style=color:#f92672>=</span>0.146.0
|
||
</span></span><span style=display:flex><span>cd /tmp
|
||
</span></span><span style=display:flex><span>wget https://github.com/gohugoio/hugo/releases/download/v<span style=color:#e6db74>${</span>VER<span style=color:#e6db74>}</span>/hugo_extended_<span style=color:#e6db74>${</span>VER<span style=color:#e6db74>}</span>_Linux-amd64.tar.gz
|
||
</span></span><span style=display:flex><span>tar -xzf hugo_extended_<span style=color:#e6db74>${</span>VER<span style=color:#e6db74>}</span>_Linux-amd64.tar.gz
|
||
</span></span><span style=display:flex><span>sudo mv hugo /usr/local/bin/hugo
|
||
</span></span><span style=display:flex><span>hugo version <span style=color:#75715e># should say "extended" and >= 0.146.0</span>
|
||
</span></span></code></pre></div><p>Create the site and theme:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>sudo mkdir -p /srv/hugo <span style=color:#f92672>&&</span> sudo chown -R <span style=color:#e6db74>"</span>$USER<span style=color:#e6db74>"</span>:<span style=color:#e6db74>"</span>$USER<span style=color:#e6db74>"</span> /srv/hugo
|
||
</span></span><span style=display:flex><span>cd /srv/hugo
|
||
</span></span><span style=display:flex><span>hugo new site mysite
|
||
</span></span><span style=display:flex><span>cd mysite
|
||
</span></span><span style=display:flex><span>git init
|
||
</span></span><span style=display:flex><span>git submodule add https://github.com/adityatelange/hugo-PaperMod themes/PaperMod
|
||
</span></span></code></pre></div><p><strong>Config updates:</strong> in newer Hugo, <code>paginate</code> is deprecated → use:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-toml data-lang=toml><span style=display:flex><span><span style=color:#75715e># config/_default/hugo.toml</span>
|
||
</span></span><span style=display:flex><span><span style=color:#a6e22e>title</span> = <span style=color:#e6db74>"My Blog"</span>
|
||
</span></span><span style=display:flex><span><span style=color:#a6e22e>theme</span> = <span style=color:#e6db74>"PaperMod"</span>
|
||
</span></span><span style=display:flex><span><span style=color:#a6e22e>enableRobotsTXT</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span>[<span style=color:#a6e22e>pagination</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>pagerSize</span> = <span style=color:#ae81ff>10</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span>[<span style=color:#a6e22e>params</span>]
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>defaultTheme</span> = <span style=color:#e6db74>"auto"</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>showReadingTime</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>showPostNavLinks</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>showBreadCrumbs</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span><span style=display:flex><span> <span style=color:#a6e22e>showCodeCopyButtons</span> = <span style=color:#66d9ef>true</span>
|
||
</span></span></code></pre></div><p>I added per-environment overrides so I can build two outputs with different <code>baseURL</code>s:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-toml data-lang=toml><span style=display:flex><span><span style=color:#75715e># config/clearnet/hugo.toml</span>
|
||
</span></span><span style=display:flex><span><span style=color:#a6e22e>baseURL</span> = <span style=color:#e6db74>"https://blog.alipourimjourneys.ir/"</span>
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># config/onion/hugo.toml</span>
|
||
</span></span><span style=display:flex><span><span style=color:#a6e22e>baseURL</span> = <span style=color:#e6db74>"http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/"</span>
|
||
</span></span></code></pre></div><hr><h2 id=4-dual-builds-clearnet--onion-and-one-command-deploy>4) Dual builds (clearnet + onion) and one-command deploy<a hidden class=anchor aria-hidden=true href=#4-dual-builds-clearnet--onion-and-one-command-deploy>#</a></h2><p>I publish the same content twice—once for each base URL and docroot:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>cd /srv/hugo/mysite
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># clearnet build (served over HTTPS)</span>
|
||
</span></span><span style=display:flex><span>hugo --minify --environment clearnet -d public-clearnet
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># onion build (served via Tor)</span>
|
||
</span></span><span style=display:flex><span>hugo --minify --environment onion -d public-onion
|
||
</span></span><span style=display:flex><span>sudo systemctl reload nginx
|
||
</span></span></code></pre></div><p>Helper script I use:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>sudo tee /usr/local/bin/build-both >/dev/null <span style=color:#e6db74><<'EOF'
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>#!/usr/bin/env bash
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>set -euo pipefail
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>cd /srv/hugo/mysite
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>hugo --minify --environment clearnet -d public-clearnet
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>hugo --minify --environment onion -d public-onion
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>sudo systemctl reload nginx
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>echo "Deployed both at $(date)"
|
||
</span></span></span><span style=display:flex><span><span style=color:#e6db74>EOF</span>
|
||
</span></span><span style=display:flex><span>sudo chmod +x /usr/local/bin/build-both
|
||
</span></span></code></pre></div><p>While editing, I sometimes auto-rebuild on file save:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>sudo apt install -y entr
|
||
</span></span><span style=display:flex><span>cd /srv/hugo/mysite
|
||
</span></span><span style=display:flex><span>find content layouts assets static config -type f | entr -r build-both
|
||
</span></span></code></pre></div><hr><h2 id=5-clearnet-behind-cloudflare--lets-encrypt-manual-dns-01>5) Clearnet behind Cloudflare + Let’s Encrypt (manual DNS-01)<a hidden class=anchor aria-hidden=true href=#5-clearnet-behind-cloudflare--lets-encrypt-manual-dns-01>#</a></h2><p>Cloudflare is set to <strong>Full (strict)</strong>. I issued a public cert for <code>blog.alipourimjourneys.ir</code> using <strong>manual DNS-01</strong> (no API token):</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>sudo snap install --classic certbot
|
||
</span></span><span style=display:flex><span>sudo certbot certonly --manual --preferred-challenges dns -d blog.alipourimjourneys.ir --agree-tos -m you@example.com --no-eff-email
|
||
</span></span></code></pre></div><p>Certbot tells you to add a TXT record <code>_acme-challenge.blog.alipourimjourneys.ir</code>. Add it in Cloudflare DNS, verify with <code>dig</code>, then continue. Cert ends up at:</p><div class="goat svg-container"><svg font-family="Menlo,Lucida Console,monospace" viewBox="0 0 496 41"><g transform="translate(8,16)"><text text-anchor="middle" x="0" y="4" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="0" y="20" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="8" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="8" y="20" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="16" y="4" fill="currentcolor" style="font-size:1em">t</text><text text-anchor="middle" x="16" y="20" fill="currentcolor" style="font-size:1em">t</text><text text-anchor="middle" x="24" y="4" fill="currentcolor" style="font-size:1em">c</text><text text-anchor="middle" x="24" y="20" fill="currentcolor" style="font-size:1em">c</text><text text-anchor="middle" x="32" y="4" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="32" y="20" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="40" y="4" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="40" y="20" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="48" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="48" y="20" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="56" y="4" fill="currentcolor" style="font-size:1em">t</text><text text-anchor="middle" x="56" y="20" fill="currentcolor" style="font-size:1em">t</text><text text-anchor="middle" x="64" y="4" fill="currentcolor" style="font-size:1em">s</text><text text-anchor="middle" x="64" y="20" fill="currentcolor" style="font-size:1em">s</text><text text-anchor="middle" x="72" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="72" y="20" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="80" y="4" fill="currentcolor" style="font-size:1em">n</text><text text-anchor="middle" x="80" y="20" fill="currentcolor" style="font-size:1em">n</text><text text-anchor="middle" x="88" y="4" fill="currentcolor" style="font-size:1em">c</text><text text-anchor="middle" x="88" y="20" fill="currentcolor" style="font-size:1em">c</text><text text-anchor="middle" x="96" y="4" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="96" y="20" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="104" y="4" fill="currentcolor" style="font-size:1em">y</text><text text-anchor="middle" x="104" y="20" fill="currentcolor" style="font-size:1em">y</text><text text-anchor="middle" x="112" y="4" fill="currentcolor" style="font-size:1em">p</text><text text-anchor="middle" x="112" y="20" fill="currentcolor" style="font-size:1em">p</text><text text-anchor="middle" x="120" y="4" fill="currentcolor" style="font-size:1em">t</text><text text-anchor="middle" x="120" y="20" fill="currentcolor" style="font-size:1em">t</text><text text-anchor="middle" x="128" y="4" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="128" y="20" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="136" y="4" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="136" y="20" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="144" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="144" y="20" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="152" y="4" fill="currentcolor" style="font-size:1em">v</text><text text-anchor="middle" x="152" y="20" fill="currentcolor" style="font-size:1em">v</text><text text-anchor="middle" x="160" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="160" y="20" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="168" y="4" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="168" y="20" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="176" y="4" fill="currentcolor" style="font-size:1em">b</text><text text-anchor="middle" x="176" y="20" fill="currentcolor" style="font-size:1em">b</text><text text-anchor="middle" x="184" y="4" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="184" y="20" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="192" y="4" fill="currentcolor" style="font-size:1em">o</text><text text-anchor="middle" x="192" y="20" fill="currentcolor" style="font-size:1em">o</text><text text-anchor="middle" x="200" y="4" fill="currentcolor" style="font-size:1em">g</text><text text-anchor="middle" x="200" y="20" fill="currentcolor" style="font-size:1em">g</text><text text-anchor="middle" x="208" y="4" fill="currentcolor" style="font-size:1em">.</text><text text-anchor="middle" x="208" y="20" fill="currentcolor" style="font-size:1em">.</text><text text-anchor="middle" x="216" y="4" fill="currentcolor" style="font-size:1em">a</text><text text-anchor="middle" x="216" y="20" fill="currentcolor" style="font-size:1em">a</text><text text-anchor="middle" x="224" y="4" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="224" y="20" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="232" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="232" y="20" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="240" y="4" fill="currentcolor" style="font-size:1em">p</text><text text-anchor="middle" x="240" y="20" fill="currentcolor" style="font-size:1em">p</text><text text-anchor="middle" x="248" y="4" fill="currentcolor" style="font-size:1em">o</text><text text-anchor="middle" x="248" y="20" fill="currentcolor" style="font-size:1em">o</text><text text-anchor="middle" x="256" y="4" fill="currentcolor" style="font-size:1em">u</text><text text-anchor="middle" x="256" y="20" fill="currentcolor" style="font-size:1em">u</text><text text-anchor="middle" x="264" y="4" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="264" y="20" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="272" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="272" y="20" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="280" y="4" fill="currentcolor" style="font-size:1em">m</text><text text-anchor="middle" x="280" y="20" fill="currentcolor" style="font-size:1em">m</text><text text-anchor="middle" x="288" y="4" fill="currentcolor" style="font-size:1em">j</text><text text-anchor="middle" x="288" y="20" fill="currentcolor" style="font-size:1em">j</text><text text-anchor="middle" x="296" y="4" fill="currentcolor" style="font-size:1em">o</text><text text-anchor="middle" x="296" y="20" fill="currentcolor" style="font-size:1em">o</text><text text-anchor="middle" x="304" y="4" fill="currentcolor" style="font-size:1em">u</text><text text-anchor="middle" x="304" y="20" fill="currentcolor" style="font-size:1em">u</text><text text-anchor="middle" x="312" y="4" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="312" y="20" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="320" y="4" fill="currentcolor" style="font-size:1em">n</text><text text-anchor="middle" x="320" y="20" fill="currentcolor" style="font-size:1em">n</text><text text-anchor="middle" x="328" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="328" y="20" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="336" y="4" fill="currentcolor" style="font-size:1em">y</text><text text-anchor="middle" x="336" y="20" fill="currentcolor" style="font-size:1em">y</text><text text-anchor="middle" x="344" y="4" fill="currentcolor" style="font-size:1em">s</text><text text-anchor="middle" x="344" y="20" fill="currentcolor" style="font-size:1em">s</text><text text-anchor="middle" x="352" y="4" fill="currentcolor" style="font-size:1em">.</text><text text-anchor="middle" x="352" y="20" fill="currentcolor" style="font-size:1em">.</text><text text-anchor="middle" x="360" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="360" y="20" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="368" y="4" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="368" y="20" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="376" y="4" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="376" y="20" fill="currentcolor" style="font-size:1em">/</text><text text-anchor="middle" x="384" y="4" fill="currentcolor" style="font-size:1em">f</text><text text-anchor="middle" x="384" y="20" fill="currentcolor" style="font-size:1em">p</text><text text-anchor="middle" x="392" y="4" fill="currentcolor" style="font-size:1em">u</text><text text-anchor="middle" x="392" y="20" fill="currentcolor" style="font-size:1em">r</text><text text-anchor="middle" x="400" y="4" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="400" y="20" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="408" y="4" fill="currentcolor" style="font-size:1em">l</text><text text-anchor="middle" x="408" y="20" fill="currentcolor" style="font-size:1em">v</text><text text-anchor="middle" x="416" y="4" fill="currentcolor" style="font-size:1em">c</text><text text-anchor="middle" x="416" y="20" fill="currentcolor" style="font-size:1em">k</text><text text-anchor="middle" x="424" y="4" fill="currentcolor" style="font-size:1em">h</text><text text-anchor="middle" x="424" y="20" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="432" y="4" fill="currentcolor" style="font-size:1em">a</text><text text-anchor="middle" x="432" y="20" fill="currentcolor" style="font-size:1em">y</text><text text-anchor="middle" x="440" y="4" fill="currentcolor" style="font-size:1em">i</text><text text-anchor="middle" x="440" y="20" fill="currentcolor" style="font-size:1em">.</text><text text-anchor="middle" x="448" y="4" fill="currentcolor" style="font-size:1em">n</text><text text-anchor="middle" x="448" y="20" fill="currentcolor" style="font-size:1em">p</text><text text-anchor="middle" x="456" y="4" fill="currentcolor" style="font-size:1em">.</text><text text-anchor="middle" x="456" y="20" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="464" y="4" fill="currentcolor" style="font-size:1em">p</text><text text-anchor="middle" x="464" y="20" fill="currentcolor" style="font-size:1em">m</text><text text-anchor="middle" x="472" y="4" fill="currentcolor" style="font-size:1em">e</text><text text-anchor="middle" x="480" y="4" fill="currentcolor" style="font-size:1em">m</text></g></svg></div><p>Clearnet Nginx vhosts:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-nginx data-lang=nginx><span style=display:flex><span><span style=color:#75715e># HTTP → HTTPS redirect (optional; CF usually talks HTTPS to origin anyway)
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span><span style=color:#66d9ef>server</span> {
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>listen</span> <span style=color:#ae81ff>80</span>; <span style=color:#f92672>listen</span> <span style=color:#e6db74>[::]:80</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>server_name</span> <span style=color:#e6db74>blog.alipourimjourneys.ir</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>return</span> <span style=color:#ae81ff>301</span> <span style=color:#e6db74>https://blog.alipourimjourneys.ir</span>$request_uri;
|
||
</span></span><span style=display:flex><span>}
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span><span style=color:#75715e># HTTPS origin (behind Cloudflare)
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span><span style=color:#66d9ef>server</span> {
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>listen</span> <span style=color:#ae81ff>443</span> <span style=color:#e6db74>ssl</span> <span style=color:#e6db74>http2</span>; <span style=color:#f92672>listen</span> <span style=color:#e6db74>[::]:443</span> <span style=color:#e6db74>ssl</span> <span style=color:#e6db74>http2</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>server_name</span> <span style=color:#e6db74>blog.alipourimjourneys.ir</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>ssl_certificate</span> <span style=color:#e6db74>/etc/letsencrypt/live/blog.alipourimjourneys.ir/fullchain.pem</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>ssl_certificate_key</span> <span style=color:#e6db74>/etc/letsencrypt/live/blog.alipourimjourneys.ir/privkey.pem</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e># HSTS on clearnet only
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#f92672>add_header</span> <span style=color:#e6db74>Strict-Transport-Security</span> <span style=color:#e6db74>"max-age=31536000</span>; <span style=color:#f92672>includeSubDomains</span>; <span style=color:#f92672>preload"</span> <span style=color:#e6db74>always</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#75715e># Help Tor Browser discover the onion mirror (safe on clearnet)
|
||
</span></span></span><span style=display:flex><span><span style=color:#75715e></span> <span style=color:#f92672>add_header</span> <span style=color:#e6db74>Onion-Location</span> <span style=color:#e6db74>"http://<your-56-char>.onion</span>$request_uri" <span style=color:#e6db74>always</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>root</span> <span style=color:#e6db74>/srv/hugo/mysite/public-clearnet</span>;
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>index</span> <span style=color:#e6db74>index.html</span>;
|
||
</span></span><span style=display:flex><span>
|
||
</span></span><span style=display:flex><span> <span style=color:#f92672>location</span> <span style=color:#e6db74>/</span> { <span style=color:#f92672>try_files</span> $uri $uri/ <span style=color:#e6db74>/index.html</span>; }
|
||
</span></span><span style=display:flex><span>}
|
||
</span></span></code></pre></div><blockquote><p>Note: don’t add HSTS or HTTPS redirects to the <strong>onion</strong> vhost. Keep onion pure HTTP on localhost.</p></blockquote><hr><h2 id=6-troubleshooting-i-ran-into-and-fixes>6) Troubleshooting I ran into (and fixes)<a hidden class=anchor aria-hidden=true href=#6-troubleshooting-i-ran-into-and-fixes>#</a></h2><ul><li><strong>Tor unit confusion:</strong> <code>tor.service</code> is a tiny master; the real daemon is <code>tor@default</code>. Use that unit and verify config as <code>debian-tor</code>.</li><li><strong>Permissions:</strong> <code>HiddenServiceDir</code> must be owned by <code>debian-tor</code> and mode <code>700</code>.</li><li><strong>Mapping mismatch:</strong> If <code>HiddenServicePort 80 127.0.0.1:3301</code> is set, visit <code>http://<onion>/</code> (no <code>:3301</code>). If you set <code>HiddenServicePort 3301 127.0.0.1:3301</code>, you must use <code>http://<onion>:3301/</code>.</li><li><strong>Curl & .onion:</strong> modern curl refuses <code>.onion</code> unless you use remote DNS via SOCKS:<div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>curl -I --socks5-hostname 127.0.0.1:9050 <span style=color:#e6db74>"http://<onion>/"</span>
|
||
</span></span></code></pre></div></li><li><strong>Two Nginx vhosts on the same port:</strong> I had a duplicate server on <code>127.0.0.1:3301</code> pointing somewhere else, which caused onion 404s. Keep only one (or mark one <code>default_server</code>).</li><li><strong>Regex in <code>server_name</code>:</strong> if you use it, write <code>server_name ~* \.onion$</code> (space after <code>~*</code>). I fixed an <code>invalid variable name</code> error caused by a missing space.</li><li><strong>PaperMod with old Hugo:</strong> upgraded to <strong>extended ≥ 0.146.0</strong>. Also updated <code>paginate</code> → <code>[pagination].pagerSize</code>.</li><li><strong>Snap confinement:</strong> Snap’s <code>hugo</code> couldn’t read <code>/srv</code> (<code>.../void: permission denied</code>). Switched to the tarball build in <code>/usr/local/bin</code>.</li></ul><hr><h2 id=7-not-secure-in-tor-browser>7) “Not secure” in Tor Browser?<a hidden class=anchor aria-hidden=true href=#7-not-secure-in-tor-browser>#</a></h2><p>That message can appear because onion uses <strong>HTTP</strong>. It’s OK: Tor provides e2e encryption + onion auth. If you enable HTTPS-Only Mode, add an exception for the site. Also ensure the onion build doesn’t reference <strong>clearnet</strong> resources (scan the built HTML for <code>http(s)://</code> links that aren’t your onion).</p><hr><h2 id=8-day-to-day-workflow>8) Day-to-day workflow<a hidden class=anchor aria-hidden=true href=#8-day-to-day-workflow>#</a></h2><ul><li>Create content:<div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>hugo new posts/my-first-post.md <span style=color:#75715e># then set draft: false</span>
|
||
</span></span></code></pre></div></li><li>Publish both:<div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>build-both
|
||
</span></span></code></pre></div></li><li>(Optional) Auto on save:<div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>find content layouts assets static config -type f | entr -r build-both
|
||
</span></span></code></pre></div></li><li>(Optional) Git push-to-deploy with a bare repo + post-receive hook that runs <code>build-both</code>.</li></ul><hr><h2 id=final-notes>Final notes<a hidden class=anchor aria-hidden=true href=#final-notes>#</a></h2><ul><li>Clearnet gets <strong>HTTPS + HSTS</strong> and an <code>Onion-Location</code> header.</li><li>Onion gets <strong>no HSTS/redirects</strong>, and all assets are self-hosted to avoid mixed content.</li><li>Serving both worlds from one Hugo repo is easy: <strong>two builds, two vhosts, one workflow</strong>.</li></ul></div><footer class=post-footer><ul class=post-tags><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/tor/>Tor</a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/nginx/>Nginx</a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/hugo/>Hugo</a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/papermod/>Papermod</a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/cloudflare/>Cloudflare</a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/letsencrypt/>Letsencrypt</a></li></ul><nav class=paginav><a class=prev href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/minecraft_server/><span class=title>« Prev</span><br><span>Dockerizing my Minecraft Server + Geyser: from 'no space left' to stable releases</span>
|
||
</a><a class=next href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/vpn/><span class=title>Next »</span><br><span>Stealth Trojan VPN Behind Cloudflare Guide</span></a></nav></footer><div class=comments-switch style="display:flex;gap:.5rem;margin:.5rem 0 1rem"><button id=btn-isso type=button aria-pressed=true>Anonymous (Isso)</button>
|
||
<button id=btn-giscus type=button aria-pressed=false>GitHub (Giscus)</button>
|
||
<a href=https://github.com/AlipourIm/blog-comments/discussions/categories/comments target=_blank rel=noopener>Open on GitHub ↗</a></div><div id=panel-isso><section id=isso-thread></section><script src=/isso/js/embed.min.js data-isso=/isso data-isso-css=true data-isso-lang=en data-isso-max-comments-nested=5 data-isso-sorting=newest async></script><small class=isso-powered style="display:block;margin:.5rem 0;color:var(--secondary,#888)">Comments powered by <a href=https://isso-comments.de target=_blank rel=noopener>Isso</a></small></div><div id=panel-giscus style=display:none><section id=giscus-thread></section></div><script>(function(){var t=document.getElementById("btn-isso"),n=document.getElementById("btn-giscus"),o=document.getElementById("panel-isso"),i=document.getElementById("panel-giscus"),s=!1;function e(e){var a,r=e==="isso";o.style.display=r?"":"none",i.style.display=r?"none":"",t.setAttribute("aria-pressed",r),n.setAttribute("aria-pressed",!r),!r&&!s&&(a=document.createElement("script"),a.src="https://giscus.app/client.js",a.async=!0,a.crossOrigin="anonymous",a.setAttribute("data-repo","AlipourIm/blog-comments"),a.setAttribute("data-repo-id","R_kgDOQGARyA"),a.setAttribute("data-category","Comments"),a.setAttribute("data-category-id","DIC_kwDOQGARyM4Cw3x-"),a.setAttribute("data-mapping","pathname"),a.setAttribute("data-strict","0"),a.setAttribute("data-reactions-enabled","1"),a.setAttribute("data-emit-metadata","0"),a.setAttribute("data-input-position","bottom"),a.setAttribute("data-theme","preferred_color_scheme"),a.setAttribute("data-lang","en"),document.getElementById("giscus-thread").appendChild(a),s=!0)}t.addEventListener("click",function(){e("isso")}),n.addEventListener("click",function(){e("giscus")}),e("isso")})()</script></article></main><footer class=footer><span>© 2025 <a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/>AlipourIm journeys</a></span> ·
|
||
<span>Powered by
|
||
<a href=https://gohugo.io/ rel="noopener noreferrer" target=_blank>Hugo</a> &
|
||
<a href=https://github.com/adityatelange/hugo-PaperMod/ rel=noopener target=_blank>PaperMod</a></span></footer><a href=#top aria-label="go to top" title="Go to Top (Alt + G)" class=top-link id=top-link accesskey=g><svg viewBox="0 0 12 6" fill="currentcolor"><path d="M12 6H0l6-6z"/></svg>
|
||
</a><a href=/index.xml rel=alternate type=application/rss+xml title=RSS class=rss-link><svg viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 019 9"/><path d="M4 4a16 16 0 0116 16"/><circle cx="5" cy="19" r="1"/></svg>
|
||
<span>RSS</span>
|
||
</a><script>let menu=document.getElementById("menu");menu&&(menu.scrollLeft=localStorage.getItem("menu-scroll-position"),menu.onscroll=function(){localStorage.setItem("menu-scroll-position",menu.scrollLeft)}),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){e.preventDefault();var t=this.getAttribute("href").substr(1);window.matchMedia("(prefers-reduced-motion: reduce)").matches?document.querySelector(`[id='${decodeURIComponent(t)}']`).scrollIntoView():document.querySelector(`[id='${decodeURIComponent(t)}']`).scrollIntoView({behavior:"smooth"}),t==="top"?history.replaceState(null,null," "):history.pushState(null,null,`#${t}`)})})</script><script>var mybutton=document.getElementById("top-link");window.onscroll=function(){document.body.scrollTop>800||document.documentElement.scrollTop>800?(mybutton.style.visibility="visible",mybutton.style.opacity="1"):(mybutton.style.visibility="hidden",mybutton.style.opacity="0")}</script><script>document.getElementById("theme-toggle").addEventListener("click",()=>{document.body.className.includes("dark")?(document.body.classList.remove("dark"),localStorage.setItem("pref-theme","light")):(document.body.classList.add("dark"),localStorage.setItem("pref-theme","dark"))})</script><script>document.querySelectorAll("pre > code").forEach(e=>{const n=e.parentNode.parentNode,t=document.createElement("button");t.classList.add("copy-code"),t.innerHTML="copy";function s(){t.innerHTML="copied!",setTimeout(()=>{t.innerHTML="copy"},2e3)}t.addEventListener("click",t=>{if("clipboard"in navigator){navigator.clipboard.writeText(e.textContent),s();return}const n=document.createRange();n.selectNodeContents(e);const o=window.getSelection();o.removeAllRanges(),o.addRange(n);try{document.execCommand("copy"),s()}catch{}o.removeRange(n)}),n.classList.contains("highlight")?n.appendChild(t):n.parentNode.firstChild==n||(e.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName=="TABLE"?e.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(t):e.parentNode.appendChild(t))})</script></body></html> |