How to Self-Host HedgeDoc with Docker Compose
What Is HedgeDoc?
HedgeDoc is a self-hosted, real-time collaborative Markdown editor. Share a link and multiple people can edit the same document simultaneously — like Google Docs, but for Markdown. It’s the open-source successor to CodiMD (and before that, HackMD). HedgeDoc is ideal for meeting notes, documentation drafts, and any situation where you need shared, live-editing Markdown without a cloud service.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 500 MB of free disk space
- 512 MB of RAM (minimum)
- A domain name (recommended for sharing notes)
Docker Compose Configuration
Create a docker-compose.yml file:
services:
hedgedoc:
image: quay.io/hedgedoc/hedgedoc:1.10.7
container_name: hedgedoc
restart: unless-stopped
ports:
- "3000:3000"
environment:
# Database connection
CMD_DB_URL: "postgres://hedgedoc:your_db_password@hedgedoc-db:5432/hedgedoc"
# REQUIRED — Domain where HedgeDoc is accessed
# Must include protocol. Used for generating share links.
CMD_DOMAIN: "hedgedoc.example.com"
CMD_PROTOCOL_USESSL: "true"
CMD_URL_ADDPORT: "false"
# Session secret — generate with: openssl rand -hex 32
CMD_SESSION_SECRET: "CHANGE_ME_GENERATE_RANDOM_HEX_STRING"
# Registration and permissions
CMD_ALLOW_ANONYMOUS: "true" # Allow anonymous editing (no login)
CMD_ALLOW_ANONYMOUS_EDITS: "true" # Allow anonymous users to edit shared notes
CMD_EMAIL: "true" # Enable email/password registration
CMD_ALLOW_EMAIL_REGISTER: "true" # Allow new account creation
# Image uploads
CMD_IMAGE_UPLOAD_TYPE: "filesystem"
CMD_UPLOADS_DIR: "/hedgedoc/public/uploads"
volumes:
- hedgedoc-uploads:/hedgedoc/public/uploads
depends_on:
hedgedoc-db:
condition: service_healthy
hedgedoc-db:
image: postgres:16-alpine
container_name: hedgedoc-db
restart: unless-stopped
environment:
POSTGRES_USER: hedgedoc
POSTGRES_PASSWORD: your_db_password # CHANGE THIS — must match CMD_DB_URL
POSTGRES_DB: hedgedoc
volumes:
- hedgedoc-pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U hedgedoc"]
interval: 10s
timeout: 5s
retries: 5
volumes:
hedgedoc-uploads:
hedgedoc-pgdata:
Start the stack:
docker compose up -d
Initial Setup
Open https://hedgedoc.example.com (or http://your-server-ip:3000). You’ll see the HedgeDoc landing page with options to create a new note.
- Create an account — click “Sign In” and register with email/password (if
CMD_EMAILis enabled). - Create your first note — click “New Note” or visit
/new. Start typing Markdown on the left; see the rendered preview on the right. - Share a note — copy the URL from your browser. Anyone with the link can view (and edit, if anonymous editing is enabled).
Configuration
Permission Modes
Each note has a permission level:
- Freely — anyone with the link can edit
- Editable — logged-in users can edit, anonymous can view
- Limited — only the owner can edit, others can view
- Locked — only the owner can view and edit
- Protected — logged-in users can view, only owner can edit
- Private — only the owner can access
Set the default with CMD_DEFAULT_PERMISSION:
CMD_DEFAULT_PERMISSION: "editable"
Authentication Options
HedgeDoc supports multiple auth providers:
# LDAP
CMD_LDAP_URL: "ldap://your-ldap-server"
CMD_LDAP_BINDDN: "cn=admin,dc=example,dc=com"
CMD_LDAP_BINDCREDENTIALS: "ldap_password"
CMD_LDAP_SEARCHBASE: "dc=example,dc=com"
# OAuth2 / OIDC (works with Keycloak, Authentik, etc.)
CMD_OAUTH2_BASEURL: "https://auth.example.com"
CMD_OAUTH2_CLIENT_ID: "hedgedoc"
CMD_OAUTH2_CLIENT_SECRET: "your_client_secret"
CMD_OAUTH2_AUTHORIZATION_URL: "https://auth.example.com/authorize"
CMD_OAUTH2_TOKEN_URL: "https://auth.example.com/token"
CMD_OAUTH2_USER_PROFILE_URL: "https://auth.example.com/userinfo"
# GitHub, GitLab, Google, Twitter, etc. also supported
Image Upload Options
# Local filesystem (default)
CMD_IMAGE_UPLOAD_TYPE: "filesystem"
# S3-compatible storage
CMD_IMAGE_UPLOAD_TYPE: "s3"
CMD_S3_BUCKET: "hedgedoc-uploads"
CMD_S3_ENDPOINT: "https://s3.example.com"
CMD_S3_ACCESS_KEY_ID: "your_key"
CMD_S3_SECRET_ACCESS_KEY: "your_secret"
# Imgur (public uploads)
CMD_IMAGE_UPLOAD_TYPE: "imgur"
CMD_IMGUR_CLIENTID: "your_imgur_client_id"
Disabling Registration
To run HedgeDoc as a private instance (no new signups):
CMD_ALLOW_EMAIL_REGISTER: "false"
CMD_ALLOW_ANONYMOUS: "false"
Create accounts manually or use an external auth provider.
Advanced Configuration (Optional)
Custom Branding
CMD_TITLE: "Team Notes" # Page title
CMD_DEFAULT_USE_HARD_BREAK: "true" # Hard line breaks in Markdown
CMD_HSTS_ENABLE: "true" # HTTP Strict Transport Security
CMD_CSP_ENABLE: "true" # Content Security Policy
Slide Mode
HedgeDoc can render Markdown as presentation slides using reveal.js. Add --- between slides in your document and access /slide/note-id for the presentation view. No extra configuration needed.
Note Aliases
Set custom URLs for notes by adding --- YAML frontmatter:
---
permalink: /team-meeting-notes
---
# Team Meeting Notes
...
Reverse Proxy
HedgeDoc runs on port 3000. Point your reverse proxy to http://hedgedoc:3000.
WebSocket support is required for real-time collaboration. Ensure your reverse proxy passes WebSocket upgrade headers:
Nginx:
location / {
proxy_pass http://hedgedoc:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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 $scheme;
}
Set CMD_DOMAIN, CMD_PROTOCOL_USESSL, and CMD_URL_ADDPORT to match your reverse proxy setup. See Reverse Proxy Setup.
Backup
Back up two things:
- PostgreSQL database — all notes, user accounts, permissions
- Uploads volume — images and files uploaded to notes
# Database backup
docker exec hedgedoc-db pg_dump -U hedgedoc hedgedoc > hedgedoc-db-$(date +%Y%m%d).sql
# Uploads backup
docker run --rm -v hedgedoc_hedgedoc-uploads:/data -v $(pwd):/backup alpine \
tar -czf /backup/hedgedoc-uploads-$(date +%Y%m%d).tar.gz /data
See Backup Strategy for a comprehensive approach.
Troubleshooting
Real-Time Collaboration Not Working
Symptom: Multiple users can’t see each other’s changes in real time.
Fix: WebSocket connections are required. Check your reverse proxy configuration — it must pass Upgrade and Connection headers. If using Nginx Proxy Manager, enable “WebSockets Support” for the proxy host.
”Forbidden” Error on Note Access
Symptom: Users get a 403 error when opening a note link.
Fix: Check CMD_ALLOW_ANONYMOUS. If set to false, users must log in before viewing any notes. If you want public read access, set:
CMD_ALLOW_ANONYMOUS: "true"
CMD_ALLOW_ANONYMOUS_EDITS: "false"
Images Not Loading
Symptom: Uploaded images show as broken links.
Fix: If using filesystem uploads, ensure the uploads volume is mounted correctly. If CMD_DOMAIN doesn’t match the actual access URL, image URLs will be wrong. Double-check CMD_DOMAIN and CMD_PROTOCOL_USESSL.
Database Connection Failed
Symptom: HedgeDoc crashes on startup with “connection refused” or “authentication failed.”
Fix: Verify CMD_DB_URL matches the PostgreSQL container’s credentials. The format is:
postgres://USER:PASSWORD@HOST:PORT/DBNAME
Ensure the database container is healthy before HedgeDoc starts (the healthcheck in the config above handles this).
Notes Lost After Upgrade
Symptom: After updating the HedgeDoc image, notes are gone.
Fix: Notes are in PostgreSQL, not in the HedgeDoc container. Ensure your hedgedoc-pgdata volume persists. If you accidentally removed the volume, restore from backup.
Resource Requirements
- RAM: ~150-200 MB idle (HedgeDoc + PostgreSQL), ~300-500 MB under active collaborative editing
- CPU: Low for editing. Moderate spikes when rendering complex Markdown or slides
- Disk: ~200 MB for the application. Database grows based on note count and uploads
Frequently Asked Questions
Is HedgeDoc free?
Yes. HedgeDoc is open source under the AGPL-3.0 license. No paid version, no feature restrictions.
What happened to CodiMD?
HedgeDoc was originally called CodiMD, which was itself a fork of HackMD. The project was renamed to HedgeDoc in 2020 to establish a distinct identity. If you find old references to CodiMD, they refer to the same project.
Can I use HedgeDoc without requiring user accounts?
Yes. Set CMD_ALLOW_ANONYMOUS: "true" to let anyone create and edit notes without logging in. Anyone with the note URL can view and (optionally) edit. This makes HedgeDoc great for quick collaboration sessions but less secure for sensitive content.
Does HedgeDoc support real-time collaboration?
Yes. Multiple users can edit the same document simultaneously with live cursor positions. Changes appear in real time for all participants. WebSocket support is required on your reverse proxy for this to work.
Can I export notes from HedgeDoc?
Yes. Each note can be downloaded as Markdown, HTML, or raw text. There’s no built-in bulk export feature, but you can use the API to programmatically export all notes from your instance.
How does HedgeDoc compare to Etherpad?
HedgeDoc uses Markdown with a split editor/preview layout. Etherpad uses rich text with a WYSIWYG editor. HedgeDoc is better for technical teams who write in Markdown. Etherpad is better for non-technical users who want a Google Docs-like experience.
Verdict
HedgeDoc is the best self-hosted option for real-time collaborative Markdown editing. The share-a-link-and-edit model is simple and intuitive. Slide mode is a nice bonus. If your team writes in Markdown and needs a shared scratch pad, HedgeDoc is the tool.
It’s not a knowledge base — there’s no folder structure, no search across notes, no wiki-style organization. For that, use BookStack or Outline. HedgeDoc is for collaborative editing sessions, meeting notes, and shared documents. For that specific use case, it’s excellent.
Etherpad is the main alternative for real-time collaborative editing, but it uses rich text instead of Markdown. If your team prefers Markdown, HedgeDoc wins.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments