Running my blog on Tor (.onion) and the Clearnet with Hugo + PaperMod

TL;DR — The site is built once (Hugo project), published twice: Onion: 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. Install & configure Tor (Debian/Ubuntu): sudo apt update && sudo apt install -y tor sudoedit /etc/tor/torrc Add: ...

September 19, 2025 · 6 min · Iman Alipour
HedgeDoc collaborative editing

Self-Hosting HedgeDoc with Docker + Nginx + Let's Encrypt

HedgeDoc is an open-source collaborative Markdown editor. Think Google Docs for Markdown: multiple people can edit the same note in real-time, with support for diagrams, math, polls, and slide decks. In this post we’ll walk through setting up your own instance on a server, secured with HTTPS. Prerequisites A Linux server with Docker and Docker Compose A domain name pointing to your server (e.g. notes.alipourimjourneys.ir) Nginx installed for reverse proxying Certbot for Let’s Encrypt certificates 1. Create the project directory mkdir ~/hedgedoc && cd ~/hedgedoc 2. Create .env POSTGRES_PASSWORD=ChangeThisStrongPassword HD_DOMAIN=notes.alipourimjourneys.ir Generate a strong password with: ...

August 29, 2025 · 2 min · Iman Alipour
Matrix, Signal but distributed

Self-hosting Matrix + Element Call with LiveKit: from zero to working (and the [not so!!] fun debugging along the way)

TL;DR: The call kept saying “waiting for media” because the browser never opened a WebSocket to LiveKit. The root cause was duplicate Access-Control-Allow-Origin headers on /sfu/get (CORS), which stopped the JWT response. Fixing CORS and ensuring the WS proxy worked (HTTP 101 in logs) solved it. What I’m building A Matrix homeserver (Synapse) at matrix.example.com (replace with your domain). TURN/STUN (coTURN) for NAT traversal. Element Call backed by LiveKit, fronted by rtc.example.com. Nginx (host) as the single reverse proxy for everything. Cloudflare DNS (with rtc.* set to DNS-only, no orange cloud). UFW firewall opened for Matrix federation, TURN, and LiveKit media ports. I used Docker for Synapse, PostgreSQL, LiveKit and the JWT helper. I used host Nginx (not Nginx in Docker) to avoid port binding conflicts on 80/443/8448. ...

August 26, 2025 · 9 min · Iman Alipour
RSS