mysite/public/posts/hedge_doc/index.html

108 lines
No EOL
33 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>Self-Hosting HedgeDoc with Docker + Nginx + Let's Encrypt | AlipourIm journeys</title>
<meta name=keywords content="hedgedoc,docker,nginx,letsencrypt,self-hosting"><meta name=description content="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 well 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 Lets 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:"><meta name=author content="Iman Alipour"><link rel=canonical href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/hedge_doc/><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/hedge_doc/><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/hedge_doc/"><meta property="og:site_name" content="AlipourIm journeys"><meta property="og:title" content="Self-Hosting HedgeDoc with Docker + Nginx + Let's Encrypt"><meta property="og:description" content="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 well 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 Lets 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:"><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-08-29T00:00:00+00:00"><meta property="article:modified_time" content="2025-08-29T00:00:00+00:00"><meta property="article:tag" content="Hedgedoc"><meta property="article:tag" content="Docker"><meta property="article:tag" content="Nginx"><meta property="article:tag" content="Letsencrypt"><meta property="article:tag" content="Self-Hosting"><meta property="og:image" content="http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/hedge_doc/images/hedgedoc-cover.png"><meta name=twitter:card content="summary_large_image"><meta name=twitter:image content="http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/hedge_doc/images/hedgedoc-cover.png"><meta name=twitter:title content="Self-Hosting HedgeDoc with Docker + Nginx + Let's Encrypt"><meta name=twitter:description content="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 well 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 Lets 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:"><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":"Self-Hosting HedgeDoc with Docker + Nginx + Let's Encrypt","item":"http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/hedge_doc/"}]}</script><script type=application/ld+json>{"@context":"https://schema.org","@type":"BlogPosting","headline":"Self-Hosting HedgeDoc with Docker + Nginx + Let's Encrypt","name":"Self-Hosting HedgeDoc with Docker \u002b Nginx \u002b Let\u0027s Encrypt","description":"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 well walk through setting up your own instance on a server, secured with HTTPS.\nPrerequisites 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 Lets Encrypt certificates 1. Create the project directory mkdir ~/hedgedoc \u0026amp;\u0026amp; cd ~/hedgedoc 2. Create .env POSTGRES_PASSWORD=ChangeThisStrongPassword HD_DOMAIN=notes.alipourimjourneys.ir Generate a strong password with:\n","keywords":["hedgedoc","docker","nginx","letsencrypt","self-hosting"],"articleBody":"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 well walk through setting up your own instance on a server, secured with HTTPS.\nPrerequisites 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 Lets Encrypt certificates 1. Create the project directory mkdir ~/hedgedoc \u0026\u0026 cd ~/hedgedoc 2. Create .env POSTGRES_PASSWORD=ChangeThisStrongPassword HD_DOMAIN=notes.alipourimjourneys.ir Generate a strong password with:\nopenssl rand -base64 32 3. Create docker-compose.yml version: \"3.9\" services: db: image: postgres:16 environment: POSTGRES_USER: hedgedoc POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: hedgedoc volumes: - db:/var/lib/postgresql/data restart: unless-stopped hedgedoc: image: quay.io/hedgedoc/hedgedoc:1.10.2 depends_on: - db environment: CMD_DB_URL: postgres://hedgedoc:${POSTGRES_PASSWORD}@db:5432/hedgedoc CMD_DOMAIN: ${HD_DOMAIN} CMD_PROTOCOL_USESSL: \"true\" CMD_URL_ADDPORT: \"false\" CMD_PORT: \"3000\" CMD_EMAIL: \"true\" CMD_ALLOW_EMAIL_REGISTER: \"false\" volumes: - uploads:/hedgedoc/public/uploads ports: - \"127.0.0.1:3000:3000\" restart: unless-stopped volumes: db: uploads: Bring it up:\ndocker compose up -d 4. Get a Lets Encrypt certificate Request a cert with a DNS challenge:\nsudo certbot certonly --manual --preferred-challenges dns -d notes.alipourimjourneys.ir -m you@example.com --agree-tos --no-eff-email Add the TXT record certbot asks for, wait for DNS to propagate, then continue.\nCertificates will be in:\n/etc/letsencrypt/live/notes.alipourimjourneys.ir/ 5. Configure Nginx Create /etc/nginx/sites-available/notes.alipourimjourneys.ir:\nserver { server_name notes.alipourimjourneys.ir; listen 80; listen [::]:80; return 301 https://$host$request_uri; } server { server_name notes.alipourimjourneys.ir; listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /etc/letsencrypt/live/notes.alipourimjourneys.ir/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/notes.alipourimjourneys.ir/privkey.pem; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection \"upgrade\"; } } Enable the config and reload Nginx:\nsudo ln -s /etc/nginx/sites-available/notes.alipourimjourneys.ir /etc/nginx/sites-enabled/ sudo nginx -t \u0026\u0026 sudo systemctl reload nginx 6. Create users Because we disabled self-registration, create accounts manually:\ndocker compose exec hedgedoc ./bin/manage_users --add alice@example.com Youll be prompted for a password.\nTo reset a password later:\ndocker compose exec hedgedoc ./bin/manage_users --reset alice@example.com 7. Done! Visit https://notes.alipourimjourneys.ir and log in with the user you created. You now have your own collaborative Markdown editor 🎉\nExtras:\nBackups: dump the PostgreSQL database and save the uploads volume. Upgrades: docker pull quay.io/hedgedoc/hedgedoc:latest \u0026\u0026 docker compose up -d. Integrations: HedgeDoc supports S3/MinIO image storage, GitHub/GitLab/Google login, and more. ","wordCount":"368","inLanguage":"en","image":"http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/hedge_doc/images/hedgedoc-cover.png","datePublished":"2025-08-29T00:00:00Z","dateModified":"2025-08-29T00:00:00Z","author":{"@type":"Person","name":"Iman Alipour"},"mainEntityOfPage":{"@type":"WebPage","@id":"http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/hedge_doc/"},"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>&nbsp;»&nbsp;<a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/>Posts</a></div><h1 class="post-title entry-hint-parent">Self-Hosting HedgeDoc with Docker + Nginx + Let's Encrypt</h1><div class=post-meta><span title='2025-08-29 00:00:00 +0000 UTC'>August 29, 2025</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;Iman Alipour
<span class=post-meta-item><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/hedge_doc/#isso-thread class=isso-comments-link>Comments</a></span></div></header><figure class=entry-cover><img loading=eager src=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/images/hedgedoc-cover.png alt="HedgeDoc collaborative editing"><figcaption>Collaborative Markdown editing with HedgeDoc</figcaption></figure><div class=post-content><p>HedgeDoc is an open-source collaborative Markdown editor. Think <em>Google Docs for Markdown</em>: multiple people can edit the same note in real-time, with support for diagrams, math, polls, and slide decks. In this post well walk through setting up your own instance on a server, secured with HTTPS.</p><hr><h2 id=prerequisites>Prerequisites<a hidden class=anchor aria-hidden=true href=#prerequisites>#</a></h2><ul><li>A Linux server with <strong>Docker</strong> and <strong>Docker Compose</strong></li><li>A domain name pointing to your server (e.g. <code>notes.alipourimjourneys.ir</code>)</li><li><strong>Nginx</strong> installed for reverse proxying</li><li><strong>Certbot</strong> for Lets Encrypt certificates</li></ul><hr><h2 id=1-create-the-project-directory>1. Create the project directory<a hidden class=anchor aria-hidden=true href=#1-create-the-project-directory>#</a></h2><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>mkdir ~/hedgedoc <span style=color:#f92672>&amp;&amp;</span> cd ~/hedgedoc</span></span></code></pre></div><hr><h2 id=2-create-env>2. Create <code>.env</code><a hidden class=anchor aria-hidden=true href=#2-create-env>#</a></h2><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-env data-lang=env><span style=display:flex><span>POSTGRES_PASSWORD<span style=color:#f92672>=</span>ChangeThisStrongPassword
</span></span><span style=display:flex><span>HD_DOMAIN<span style=color:#f92672>=</span>notes.alipourimjourneys.ir</span></span></code></pre></div><p>Generate a strong password with:</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>openssl rand -base64 <span style=color:#ae81ff>32</span></span></span></code></pre></div><hr><h2 id=3-create-docker-composeyml>3. Create <code>docker-compose.yml</code><a hidden class=anchor aria-hidden=true href=#3-create-docker-composeyml>#</a></h2><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-yaml data-lang=yaml><span style=display:flex><span><span style=color:#f92672>version</span>: <span style=color:#e6db74>&#34;3.9&#34;</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#f92672>services</span>:
</span></span><span style=display:flex><span> <span style=color:#f92672>db</span>:
</span></span><span style=display:flex><span> <span style=color:#f92672>image</span>: <span style=color:#ae81ff>postgres:16</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>environment</span>:
</span></span><span style=display:flex><span> <span style=color:#f92672>POSTGRES_USER</span>: <span style=color:#ae81ff>hedgedoc</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>POSTGRES_PASSWORD</span>: <span style=color:#ae81ff>${POSTGRES_PASSWORD}</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>POSTGRES_DB</span>: <span style=color:#ae81ff>hedgedoc</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>volumes</span>:
</span></span><span style=display:flex><span> - <span style=color:#ae81ff>db:/var/lib/postgresql/data</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>restart</span>: <span style=color:#ae81ff>unless-stopped</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#f92672>hedgedoc</span>:
</span></span><span style=display:flex><span> <span style=color:#f92672>image</span>: <span style=color:#ae81ff>quay.io/hedgedoc/hedgedoc:1.10.2</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>depends_on</span>:
</span></span><span style=display:flex><span> - <span style=color:#ae81ff>db</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>environment</span>:
</span></span><span style=display:flex><span> <span style=color:#f92672>CMD_DB_URL</span>: <span style=color:#ae81ff>postgres://hedgedoc:${POSTGRES_PASSWORD}@db:5432/hedgedoc</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>CMD_DOMAIN</span>: <span style=color:#ae81ff>${HD_DOMAIN}</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>CMD_PROTOCOL_USESSL</span>: <span style=color:#e6db74>&#34;true&#34;</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>CMD_URL_ADDPORT</span>: <span style=color:#e6db74>&#34;false&#34;</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>CMD_PORT</span>: <span style=color:#e6db74>&#34;3000&#34;</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>CMD_EMAIL</span>: <span style=color:#e6db74>&#34;true&#34;</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>CMD_ALLOW_EMAIL_REGISTER</span>: <span style=color:#e6db74>&#34;false&#34;</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>volumes</span>:
</span></span><span style=display:flex><span> - <span style=color:#ae81ff>uploads:/hedgedoc/public/uploads</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>ports</span>:
</span></span><span style=display:flex><span> - <span style=color:#e6db74>&#34;127.0.0.1:3000:3000&#34;</span>
</span></span><span style=display:flex><span> <span style=color:#f92672>restart</span>: <span style=color:#ae81ff>unless-stopped</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#f92672>volumes</span>:
</span></span><span style=display:flex><span> <span style=color:#f92672>db</span>:
</span></span><span style=display:flex><span> <span style=color:#ae81ff>uploads:</span></span></span></code></pre></div><p>Bring it up:</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>docker compose up -d</span></span></code></pre></div><hr><h2 id=4-get-a-lets-encrypt-certificate>4. Get a Lets Encrypt certificate<a hidden class=anchor aria-hidden=true href=#4-get-a-lets-encrypt-certificate>#</a></h2><p>Request a cert with a <strong>DNS challenge</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 certbot certonly --manual --preferred-challenges dns -d notes.alipourimjourneys.ir -m you@example.com --agree-tos --no-eff-email</span></span></code></pre></div><p>Add the TXT record certbot asks for, wait for DNS to propagate, then continue.<br>Certificates will be in:</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>/etc/letsencrypt/live/notes.alipourimjourneys.ir/</span></span></code></pre></div><hr><h2 id=5-configure-nginx>5. Configure Nginx<a hidden class=anchor aria-hidden=true href=#5-configure-nginx>#</a></h2><p>Create <code>/etc/nginx/sites-available/notes.alipourimjourneys.ir</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>server_name</span> <span style=color:#e6db74>notes.alipourimjourneys.ir</span>;
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#f92672>listen</span> <span style=color:#ae81ff>80</span>;
</span></span><span style=display:flex><span> <span style=color:#f92672>listen</span> <span style=color:#e6db74>[::]:80</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://</span>$host$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:#66d9ef>server</span> {
</span></span><span style=display:flex><span> <span style=color:#f92672>server_name</span> <span style=color:#e6db74>notes.alipourimjourneys.ir</span>;
</span></span><span style=display:flex><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></span><span style=display:flex><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></span><span style=display:flex><span> <span style=color:#f92672>ssl_certificate</span> <span style=color:#e6db74>/etc/letsencrypt/live/notes.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/notes.alipourimjourneys.ir/privkey.pem</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></span><span style=display:flex><span> <span style=color:#f92672>proxy_pass</span> <span style=color:#e6db74>http://127.0.0.1:3000</span>;
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_set_header</span> <span style=color:#e6db74>Host</span> $host;
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_set_header</span> <span style=color:#e6db74>X-Real-IP</span> $remote_addr;
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_set_header</span> <span style=color:#e6db74>X-Forwarded-For</span> $proxy_add_x_forwarded_for;
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_set_header</span> <span style=color:#e6db74>X-Forwarded-Proto</span> <span style=color:#e6db74>https</span>;
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_http_version</span> <span style=color:#ae81ff>1</span><span style=color:#e6db74>.1</span>;
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_set_header</span> <span style=color:#e6db74>Upgrade</span> $http_upgrade;
</span></span><span style=display:flex><span> <span style=color:#f92672>proxy_set_header</span> <span style=color:#e6db74>Connection</span> <span style=color:#e6db74>&#34;upgrade&#34;</span>;
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>}</span></span></code></pre></div><p>Enable the config and reload Nginx:</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 -s /etc/nginx/sites-available/notes.alipourimjourneys.ir /etc/nginx/sites-enabled/
</span></span><span style=display:flex><span>sudo nginx -t <span style=color:#f92672>&amp;&amp;</span> sudo systemctl reload nginx</span></span></code></pre></div><hr><h2 id=6-create-users>6. Create users<a hidden class=anchor aria-hidden=true href=#6-create-users>#</a></h2><p>Because we disabled self-registration, create accounts manually:</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>docker compose exec hedgedoc ./bin/manage_users --add alice@example.com</span></span></code></pre></div><p>Youll be prompted for a password.<br>To reset a password later:</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>docker compose exec hedgedoc ./bin/manage_users --reset alice@example.com</span></span></code></pre></div><hr><h2 id=7-done>7. Done!<a hidden class=anchor aria-hidden=true href=#7-done>#</a></h2><p>Visit <a href=https://notes.alipourimjourneys.ir>https://notes.alipourimjourneys.ir</a> and log in with the user you created. You now have your own collaborative Markdown editor 🎉</p><hr><p><strong>Extras:</strong></p><ul><li>Backups: dump the PostgreSQL database and save the <code>uploads</code> volume.</li><li>Upgrades: <code>docker pull quay.io/hedgedoc/hedgedoc:latest && docker compose up -d</code>.</li><li>Integrations: HedgeDoc supports S3/MinIO image storage, GitHub/GitLab/Google login, and more.</li></ul></div><footer class=post-footer><ul class=post-tags><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/hedgedoc/>Hedgedoc</a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/docker/>Docker</a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/nginx/>Nginx</a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/letsencrypt/>Letsencrypt</a></li><li><a href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/self-hosting/>Self-Hosting</a></li></ul><nav class=paginav><a class=prev href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/phd_journey/augest_2025/><span class=title>« Prev</span><br><span>Augest '25</span>
</a><a class=next href=http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/matrix_setup/><span class=title>Next »</span><br><span>Self-hosting Matrix + Element Call with LiveKit: from zero to working (and the [not so!!] fun debugging along the way)</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>&copy; 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>