JP / EN

Self-Hosting HedgeDoc On-Premises


This article is Day 1 of coins Advent Calendar 2024.

What is HedgeDoc?

Official Site A self-hosted HackMD-like service that lets you write in Markdown, with login authentication, sharing, and collaborative editing.

Running Without a Global IP

Typically, self-hosting requires renting a VPS for a global IP, but we’ll use Cloudflare Tunnel to punch through. Your domain management needs to be under Cloudflare.

Installation

First, prepare a server. Install Docker as a prerequisite. I set up an Ubuntu 24.04 server on Proxmox. For Docker, 2 cores and 2GB+ RAM should work.

Cloudflare Tunnel Setup

This is just copying the setup code shown when creating a Tunnel in the Cloudflare dashboard, so I won’t explain in detail.

Docker Setup

sudo usermod -aG docker $USER

First add your current user to the group (if not done).

Create docker-compose.yml:

nano docker-compose.yml

Write the following:

version: '3'
services:
  database:
    image: postgres:13.4-alpine
    environment:
      - POSTGRES_USER=hedgedoc
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=hedgedoc
    volumes:
      - database:/var/lib/postgresql/data
    restart: always
  app:
    image: quay.io/hedgedoc/hedgedoc:1.9.9
    environment:
      - CMD_DB_URL=postgres://hedgedoc:password@database:5432/hedgedoc
      - CMD_DOMAIN={your-cloudflare-domain}
      - CMD_PROTOCOL_USESSL=true
      - CMD_URL_ADDPORT=false
      - CMD_TRUST_PROXY=true
      - CMD_CSP_ENABLE=true
      - CMD_CSP_REPORT_ONLY=false
      - "CMD_CSP=default-src 'self' https://{your-cloudflare-domain} https://*.cloudflareusercontent.com; connect-src 'self' https://{your-cloudflare-domain} wss://{your-cloudflare-domain} https://*.cloudflareusercontent.com; font-src 'self' data: https://{your-cloudflare-domain} https://*.cloudflareusercontent.com https://cdnjs.cloudflare.com https://fonts.gstatic.com; img-src 'self' data: blob: https://{your-cloudflare-domain} https://*.cloudflareusercontent.com; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://{your-cloudflare-domain} https://*.cloudflareusercontent.com https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://{your-cloudflare-domain} https://*.cloudflareusercontent.com https://cdnjs.cloudflare.com https://fonts.googleapis.com; base-uri 'self'; manifest-src 'self'; frame-src *"
    volumes:
      - uploads:/hedgedoc/public/uploads
    ports:
      - "3000:3000"
    restart: always
    depends_on:
      - database
volumes:
  database:
  uploads:

Replace with your configured domain.

{your-cloudflare-domain}

Then:

docker compose up -d

to start. Success looks like:

Access

Access the domain,

and register an account. You can use a fake email address.

[email protected]

Note: the part before @ becomes the username.

Disabling New Registrations

Edit the yml:

version: '3'
services:
  database:
    image: postgres:13.4-alpine
    environment:
      - POSTGRES_USER=hedgedoc
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=hedgedoc
    volumes:
      - database:/var/lib/postgresql/data
    restart: always
  app:
    image: quay.io/hedgedoc/hedgedoc:1.9.9
    environment:
      - CMD_DB_URL=postgres://hedgedoc:password@database:5432/hedgedoc
      - CMD_DOMAIN=md.{your-cloudflare-domain}
      - CMD_PROTOCOL_USESSL=true
      - CMD_URL_ADDPORT=false
      - CMD_TRUST_PROXY=true
      # Email settings
      - CMD_EMAIL=true
      - CMD_ALLOW_EMAIL_REGISTER=false
      # Disable anonymous access
      - CMD_ALLOW_ANONYMOUS=false
      - CMD_ALLOW_ANONYMOUS_EDITS=false
      # CSP settings
      - CMD_CSP_ENABLE=true
      - CMD_CSP_REPORT_ONLY=false
      - "CMD_CSP=default-src 'self' https://*.{your-cloudflare-domain} https://*.cloudflareusercontent.com; connect-src 'self' https://*.{your-cloudflare-domain} wss://*.{your-cloudflare-domain} https://*.cloudflareusercontent.com; font-src 'self' data: https://*.{your-cloudflare-domain} https://*.cloudflareusercontent.com https://cdnjs.cloudflare.com https://fonts.gstatic.com; img-src 'self' data: blob: https://*.{your-cloudflare-domain} https://*.cloudflareusercontent.com; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.{your-cloudflare-domain} https://*.cloudflareusercontent.com https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://*.{your-cloudflare-domain} https://*.cloudflareusercontent.com https://cdnjs.cloudflare.com https://fonts.googleapis.com; base-uri 'self'; manifest-src 'self'; frame-src *"
    volumes:
      - uploads:/hedgedoc/public/uploads
    ports:
      - "3000:3000"
    restart: always
    depends_on:
      - database
volumes:
  database:
  uploads:

Configuration is done with:

      - CMD_ALLOW_EMAIL_REGISTER=false
      - CMD_ALLOW_ANONYMOUS=false
      - CMD_ALLOW_ANONYMOUS_EDITS=false

See the configuration list for details. Restart Docker and confirm only sign-in is available.

Want to Use GitHub Login, but…

Following the official documentation works, but you can’t restrict by organization, effectively allowing anyone to register. Therefore, you need to either use authentik for authentication, or restrict access via Cloudflare Access with a proxy.

Conclusion

This was the first day’s article, but it ended up being a geeky tech post. Tomorrow is Ya-’s article, looking forward to it!

Back to list