HedgeDoc on Ubuntu 24.04 on Azure User Guide
Overview
HedgeDoc is the leading open source, self hosted, real time collaborative markdown editor, the community fork of HackMD. Several people edit the same note at once in a split pane editor with a live rendered preview, presence cursors and collaboration that just works in the browser. Notes support diagrams, code blocks with syntax highlighting, MathJax math, slide deck presentation mode and image uploads.
The cloudimg image installs HedgeDoc 1.10.8 (AGPL-3.0 licensed) to /opt/hedgedoc, runs it on Node.js 20 LTS as a hardened systemd service bound to the loopback address, and fronts it with nginx on port 80 with the WebSocket upgrade support that real time collaboration needs. The SQLite database and image uploads live on a dedicated Azure data disk. Anonymous note creation and open self registration are disabled, and a unique admin account plus session secret are generated on the first boot of every VM and written to a root only file, so no shared or default credentials ship in the image. Backed by 24/7 cloudimg support.
What is included:
- HedgeDoc 1.10.8 in
/opt/hedgedoc, running on Node.js 20 LTS - The HedgeDoc application bound to loopback (
127.0.0.1:3000), never exposed directly - nginx on
:80as a reverse proxy to the loopback backend, carrying the socket.io WebSocket upgrade - A unique admin account and a fresh session secret generated on first boot, written to a root only file
- Anonymous access and open registration disabled by default
- A dedicated Azure data disk at
/var/lib/hedgedocholding the SQLite database and image uploads hedgedoc.serviceandnginx.serviceas systemd units- 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point for a small team. NSG inbound: allow 22/tcp from your management network and 80/tcp. HedgeDoc serves plain HTTP on port 80; for production, terminate TLS in front of it with your own domain (see the HTTPS section below).
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for HedgeDoc by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Review the dedicated data disk on the Disks tab, then Review + create then Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name hedgedoc \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name hedgedoc --port 80 --priority 1010
Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 - Confirm the services and data disk
HedgeDoc runs as hedgedoc.service (the Node.js app, bound to loopback), with nginx.service as the public reverse proxy on port 80. The SQLite database and uploads live on a dedicated Azure data disk mounted at /var/lib/hedgedoc.
systemctl is-active hedgedoc.service nginx.service
sudo ss -tlnp | grep -E ':3000|:80 '
findmnt -no SOURCE,TARGET,FSTYPE /var/lib/hedgedoc
node --version
Both services report active, the data disk is mounted ext4, and Node.js reports v20.x. Note in the listeners that HedgeDoc (3000) is bound to 127.0.0.1 only; the sole public listener is nginx on :80, which proxies to it and carries the WebSocket connections used for real time collaboration.

Step 5 - Retrieve your admin credentials
The administrator account is generated uniquely on the first boot of your VM and written to a root only file. Confirm the sign in page is also being served through nginx on port 80:
sudo cat /root/hedgedoc-credentials.txt
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost/
The file contains HEDGEDOC_ADMIN_EMAIL, HEDGEDOC_ADMIN_PASSWORD (your unique password) and HEDGEDOC_URL. The sign in page returns HTTP 200 through nginx. Store the password somewhere safe.

Step 6 - The security model
HedgeDoc is secure by default. Anonymous access (CMD_ALLOW_ANONYMOUS) and open registration (CMD_ALLOW_EMAIL_REGISTER) are disabled, so only the seeded per-instance admin can sign in and create notes. The check below shows an unauthenticated request being forbidden, a wrong password being rejected, and only the real per-VM admin obtaining a session:
EMAIL=$(sudo grep '^HEDGEDOC_ADMIN_EMAIL=' /root/hedgedoc-credentials.txt | cut -d= -f2-)
PASS=$(sudo grep '^HEDGEDOC_ADMIN_PASSWORD=' /root/hedgedoc-credentials.txt | cut -d= -f2-)
echo -n 'anonymous /me : '; curl -s http://localhost/me; echo
BAD=$(mktemp); curl -s -o /dev/null -c "$BAD" --data-urlencode "email=$EMAIL" --data-urlencode 'password=wrong-password' http://localhost/login
echo -n 'wrong-password /me : '; curl -s -b "$BAD" http://localhost/me; echo; rm -f "$BAD"
GOOD=$(mktemp); curl -s -o /dev/null -c "$GOOD" --data-urlencode "email=$EMAIL" --data-urlencode "password=$PASS" http://localhost/login
echo -n 'signed-in /me : '; curl -s -b "$GOOD" http://localhost/me; echo; rm -f "$GOOD"
The anonymous and wrong password requests both return {"status":"forbidden"}; only the correct per-VM password returns {"status":"ok"} with the admin identity.

Step 7 - Sign in to the web UI
Browse to http://<vm-public-ip>/ and select Sign In. Sign in via E-Mail with the HEDGEDOC_ADMIN_EMAIL and HEDGEDOC_ADMIN_PASSWORD from Step 5.

Step 8 - Collaborate in real time
Select New to create a note. HedgeDoc opens the split pane editor: your Markdown on the left, a live rendered preview on the right. Notes support headings, lists, tables, code blocks with syntax highlighting, math and more. Share the note link and colleagues can edit the same note with you at the same time; the count in the top right shows how many people are online.

Step 9 - Your note overview
The History view lists the notes you have opened, with titles, tags and last visited times, so you can search and return to any note. Use New note to start another, or pin the notes you use most.

Step 10 - Present a note as slides
Any note can be presented as a slide deck. Add a type: slide header to the note and separate slides with ---, then open the note's slide view from the Menu. HedgeDoc renders the note as a reveal.js presentation you can step through and share.

Step 11 - Where your data lives
All persistent state - the SQLite database and every uploaded image - lives on the dedicated Azure data disk mounted at /var/lib/hedgedoc, kept separate from the OS disk so you can snapshot and resize it on its own. The image uploads directory is a symlink from the application into the data disk:
findmnt -no SOURCE,TARGET,FSTYPE,SIZE /var/lib/hedgedoc
sudo ls -lh /var/lib/hedgedoc/db.hedgedoc.sqlite
ls -l /opt/hedgedoc/public/uploads
The database file db.hedgedoc.sqlite and the uploads directory both sit on the data disk; /opt/hedgedoc/public/uploads is a symlink onto it. To back up HedgeDoc, snapshot the /var/lib/hedgedoc data disk, or copy the SQLite database and the uploads directory while the service is quiescent.

Step 12 - Add more users
Open registration is disabled, so you add users from the command line with the bundled manage_users tool. Run it as the hedgedoc service user, loading the environment file so it uses the same database:
cd /opt/hedgedoc
sudo -u hedgedoc env $(sudo grep -v '^#' /etc/hedgedoc/hedgedoc.env | xargs) NODE_ENV=production \
node bin/manage_users --add teammate@example.com --pass 'a-strong-password'
For central identity you can also connect LDAP, SAML or OAuth2 providers by adding the relevant CMD_* variables to /etc/hedgedoc/hedgedoc.env and restarting hedgedoc.service.
Step 13 - Enable HTTPS for production
HedgeDoc is served as plain HTTP on port 80. For production, put your own domain in front and terminate TLS - for example by installing certbot and the nginx plugin, or by placing the VM behind an Azure Application Gateway or Front Door with a managed certificate:
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d hedgedoc.example.com
After enabling HTTPS, set CMD_DOMAIN to your domain and CMD_PROTOCOL_USESSL=true in /etc/hedgedoc/hedgedoc.env, then restart hedgedoc.service so generated links and the session cookie use https://.
Maintenance
- Restart the app:
sudo systemctl restart hedgedoc.service - View logs:
sudo journalctl -u hedgedoc.service -e - Configuration: runtime settings live in
/etc/hedgedoc/hedgedoc.env; the app is in/opt/hedgedoc. - OS updates: unattended-upgrades is enabled; apply the latest security updates with
sudo apt-get update && sudo apt-get -y upgradeand reboot if a new kernel is installed. - Back up: snapshot the
/var/lib/hedgedocdata disk, or copydb.hedgedoc.sqliteand theuploadsdirectory.
Support
This image is maintained by cloudimg with 24/7 support. HedgeDoc is licensed under AGPL-3.0. "HedgeDoc" and "HackMD" are trademarks of their respective owners; this image is provided by cloudimg and is not endorsed by or affiliated with the HedgeDoc project.