<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Hedgedoc on AlipourIm journeys</title>
    <link>http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/hedgedoc/</link>
    <description>Recent content in Hedgedoc on AlipourIm journeys</description>
    <generator>Hugo -- 0.146.0</generator>
    <language>en</language>
    <lastBuildDate>Fri, 29 Aug 2025 00:00:00 +0000</lastBuildDate>
    <atom:link href="http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/tags/hedgedoc/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Self-Hosting HedgeDoc with Docker &#43; Nginx &#43; Let&#39;s Encrypt</title>
      <link>http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/hedge_doc/</link>
      <pubDate>Fri, 29 Aug 2025 00:00:00 +0000</pubDate>
      <guid>http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/posts/hedge_doc/</guid>
      <description>&lt;p&gt;HedgeDoc is an open-source collaborative Markdown editor. Think &lt;em&gt;Google Docs for Markdown&lt;/em&gt;: 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.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A Linux server with &lt;strong&gt;Docker&lt;/strong&gt; and &lt;strong&gt;Docker Compose&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;A domain name pointing to your server (e.g. &lt;code&gt;notes.alipourimjourneys.ir&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nginx&lt;/strong&gt; installed for reverse proxying&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Certbot&lt;/strong&gt; for Let’s Encrypt certificates&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;1-create-the-project-directory&#34;&gt;1. Create the project directory&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir ~/hedgedoc &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cd ~/hedgedoc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-create-env&#34;&gt;2. Create &lt;code&gt;.env&lt;/code&gt;&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-env&#34; data-lang=&#34;env&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POSTGRES_PASSWORD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ChangeThisStrongPassword
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HD_DOMAIN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;notes.alipourimjourneys.ir&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Generate a strong password with:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<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 we’ll walk through setting up your own instance on a server, secured with HTTPS.</p>
<hr>
<h2 id="prerequisites">Prerequisites</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 Let’s Encrypt certificates</li>
</ul>
<hr>
<h2 id="1-create-the-project-directory">1. Create the project directory</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></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></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 Let’s Encrypt certificate</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</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</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>You’ll 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!</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 &amp;&amp; docker compose up -d</code>.</li>
<li>Integrations: HedgeDoc supports S3/MinIO image storage, GitHub/GitLab/Google login, and more.</li>
</ul>
<hr>
<div class="signature-block" style="margin-top:1rem">
  <p><strong>Downloads:</strong>
    <a href="/sources/posts/hedge_doc.md">Markdown</a> ·
    <a href="/sources/posts/hedge_doc.md.asc">Signature (.asc)</a>
  </p><details class="signature">
    <summary>View OpenPGP signature</summary>
    <pre style="font-size:0.85em; overflow-x:auto; padding:0.75rem;">-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEEVaKl3oR5K6zGyu4/tYgoUOBMjSoFAmpkbucACgkQtYgoUOBM
jSrPHA//WlMEZx1k/aGx3zau&#43;wRrAOq4XlrvC7keBvqMs0PJGhJmT8jnOMh0&#43;26w
AGav2jBuChLYsDx&#43;O8l18uxcsu9fdrz8r4N4sDOnsndSsg15rTT28P3MNvvUL8ns
iOc9uEUkxF59rT3OXRI56hH3VX6vzxakdAnW3Afhki2Bl54jur2&#43;6RVtuthGUEV&#43;
QZ/36QVXLrOAas1bqq3f38m4M2no3ZqVvpj&#43;Alur2Ji/gcGZlSArBnIoJQoK5L&#43;r
UZLJsQ&#43;LrqCJp4i&#43;GkkX05si2srSTjawBu&#43;ssHf&#43;uwPg0Q6AMTbubrGiHrMMtMbM
4PCFtS8vD/ZBVkVpSBybyXdMxQU&#43;y9AI1LZ//X4cQWdqgRpinOVENuZ2FeVI6qa/
sBGHLThq9nZEXmMT2oQa1wi&#43;CaY17z9fYj20F5moOp2Q6pxBGPyHZRV3WAr5xURU
5B9SwVtNqIzm7eoAbwckU3h&#43;TfIJ4vGulSqPqHvZ/XAdbzCVXaSXBN951oA0No1y
MyvsIskzKVPvSqndYjxLGiopvOpITgxN5q6a7ubBmxYCrS&#43;SF74jPkDjtc4EFuKB
QrMTBm/&#43;Xl/VEESYv5Mx7hwYv1dnmJUFrx62FUYmAMaFP2UcMIlJJ5zQCwsDdREk
aG3wFuWH4d9UFohK&#43;MJIHqYk1&#43;TbZJm3bnds8pOqniIZ7M5PcEg=
=uf5y
-----END PGP SIGNATURE-----
</pre>
  </details><p><em>Verify locally:</em></p>
  <pre style="font-size:0.85em; overflow-x:auto; padding:0.75rem;">torsocks curl -fSLO http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/sources/posts/hedge_doc.md
torsocks curl -fSLO http://fjthpp2h3mj2rup25r3psmqamutnkbvxbpltlohdthw6fscgo3t6bpad.onion/sources/posts/hedge_doc.md.asc
gpg --verify hedge_doc.md.asc hedge_doc.md
  </pre>
</div>


]]></content:encoded>
    </item>
  </channel>
</rss>
