HedgeDoc

HedgeDoc (formerly CodiMD / HackMD) is an open-source software written in Node.js. HedgeDoc lets you create real-time collaborative markdown notes. It is inspired by Hackpad, Etherpad and similar collaborative editors.

HedgeDoc is licensed under the AGPLv3.


Note

For this guide you should be familiar with the basic concepts of

Prerequisites

Use the recommended Node.js version as mentioned in the HedgeDoc setup documentation.

[isabell@stardust ~]$ uberspace tools version use node 20
Selected Node.js version 20
The new configuration is adapted immediately. Minor updates will be applied automatically.
[isabell@stardust ~]$

Setup your Domain:

[isabell@stardust ~]$ uberspace web domain list
isabell.uber.space
[isabell@stardust ~]$

You’ll need your MySQL credentials. Get them with my_print_defaults:

[isabell@stardust ~]$ my_print_defaults client
--default-character-set=utf8mb4
--user=isabell
--password=MySuperSecretPassword
[isabell@stardust ~]$

Installation

Download

Check whether the marked line is the latest release.

[isabell@stardust ~]$ VERSION=1.9.8
[isabell@stardust ~]$ wget https://github.com/hedgedoc/hedgedoc/releases/download/$VERSION/hedgedoc-$VERSION.tar.gz
[...]
100%[======================================================>] 50,784,713  16.8MB/s   in 2.9s
[isabell@stardust ~]$ tar --extract --gzip --file=hedgedoc-$VERSION.tar.gz
[isabell@stardust ~]$ rm --verbose hedgedoc-$VERSION.tar.gz
removed hedgedoc-1.X.Y.tar.gz
[isabell@stardust ~]$

Setup

Then install the dependencies. This step may take a few minutes.

[isabell@stardust ~]$ cd hedgedoc
[isabell@stardust hedgedoc]$ bin/setup
Copying config files...
Installing packages...
yarn install v1.22.5
[1/5] Validating package.json...
[2/5] Resolving packages...
[3/5] Fetching packages...
...some info messages you can ignore
[4/5] Linking dependencies...
[5/5] Building fresh packages...
Done in 253.95s.
yarn install v1.22.5
[1/5] Validating package.json...
[2/5] Resolving packages...
success Already up-to-date.
Done in 1.15s.

Edit the following config file to setup HedgeDoc server and client.
Read more info at https://docs.hedgedoc.org/configuration/

* config.json           -- HedgeDoc config
[isabell@stardust hedgedoc]$ mkdir --verbose ~/hedgedoc_uploads
mkdir: created directory ‘/home/isabell/hedgedoc_uploads’
[isabell@stardust hedgedoc]$

Database

Create a Database.

[isabell@stardust hedgedoc]$ mysql --verbose --execute="CREATE DATABASE ${USER}_hedgedoc"
--------------
CREATE DATABASE isabell_hedgedoc
--------------

[isabell@stardust hedgedoc]$

Configuration

In order to run bin/manage_users the script needs to know the database credentials.
Edit the ~/hedgedoc/config.json file with the following lines and adapt your database credentials, domain and uploads path.
You can delete everything else as we only run the app in production mode.
{
  "production": {
    "db": {
      "username": "isabell",
      "password": "isabells_MySQL_password",
      "database": "isabell_hedgedoc",
      "host": "localhost",
      "port": "3306",
      "dialect": "mysql"
    },
    "domain": "isabell.uber.space",
    "uploadsPath": "/home/isabell/hedgedoc_uploads",
    "protocolUseSSL": "true"
  }
}

Note

You can set here some options in json format you can’t yet set with environment variables. For other configuration options, check the configuration documentation.

Generate session secret

The cookie session secret is used to sign the session cookie. If none is set, one will randomly be generated on each startup, meaning all your users will be logged out.
You will need the highlighted string at the next step for the ~/etc/services.d/hedgedoc.ini.
[isabell@stardust ~]$ pwgen 32 1
somethingSuperRandom
[isabell@stardust ~]$

Setup daemon

Note

You can set a lot of environment variables. For other configuration options, check the configuration documentation. The prefix for the variables may change in a future release because of the renaming of the project.

Create ~/etc/services.d/hedgedoc.ini with the following content:

[program:hedgedoc]
environment=
  NODE_ENV="production",
  CMD_ALLOW_EMAIL_REGISTER="false",
  CMD_ALLOW_ANONYMOUS="false",
  CMD_ALLOW_FREEURL="true",
  CMD_REQUIRE_FREEURL_AUTH="true",
  CMD_SESSION_SECRET="somethingSuperRandom"
directory=%(ENV_HOME)s/hedgedoc
command=yarn start
startsecs=60
autostart=yes
autorestart=yes

After creating the configuration, tell supervisord to refresh its configuration and start the service:

[isabell@stardust ~]$ supervisorctl reread
SERVICE: available
[isabell@stardust ~]$ supervisorctl update
SERVICE: added process group
[isabell@stardust ~]$ supervisorctl status
SERVICE                            RUNNING   pid 26020, uptime 0:03:14
[isabell@stardust ~]$

If it’s not in state RUNNING after one minute (at first you will see STARTING), check your configuration. You can also check the run log with supervisorctl tail -f hedgedoc.

Configure web server

Note

HedgeDoc is running on port 3000 in the default configuration.

To make the application accessible from the outside, configure a web backend:

[isabell@stardust ~]$ uberspace web backend set / --http --port <port>
Set backend for / to port <port>; please make sure something is listening!
You can always check the status of your backend using "uberspace web backend list".
[isabell@stardust ~]$

Create a User

Even if you have deactivated the web based user registration you can always create users with the following command. The username has to be in the form of an email address. You will then be asked to choose a password.

[isabell@stardust hedgedoc]$ NODE_ENV=production bin/manage_users --add isabell@uber.space
Password for isabell@uber.space:*************
Created user with email isabell@uber.space
[isabell@stardust hedgedoc]$

You should now be able to access your HedgeDoc via https://isabell.uber.space

Updates

Note

Check the release notes regularly or subscribe to the project’s GitHub release feed with your favorite feed reader to stay informed about new updates and releases.

While HedgeDoc 2.0 is currently under development and the 1.x releases are also having changes you should watch HedgeDocs manual installation guide to notice if instructions have been changed. You should also read the release notes. Make sure you always download the already build tarball as the building process needs at least 2 GB RAM, so building is not possible on uberspace.

Manual update

Check whether the marked line is the latest release or the version you like to update to.

[isabell@stardust ~]$ supervisorctl stop hedgedoc
hedgedoc: stopped
[isabell@stardust ~]$ mv --verbose hedgedoc hedgedoc_old
‘hedgedoc’ -> ‘hedgedoc_old’
[isabell@stardust ~]$ VERSION=1.8.2
[isabell@stardust ~]$ wget https://github.com/hedgedoc/hedgedoc/releases/download/$VERSION/hedgedoc-$VERSION.tar.gz
[...]
100%[======================================================>] 50,784,713  16.8MB/s   in 2.9s
[isabell@stardust ~]$ tar --extract --gzip --file=hedgedoc-$VERSION.tar.gz
[isabell@stardust ~]$ rm --verbose hedgedoc-$VERSION.tar.gz
removed ‘hedgedoc-1.8.2.tar.gz’
[isabell@stardust ~]$ cp --verbose hedgedoc_old/config.json hedgedoc/config.json
‘hedgedoc_old/config.json’ -> ‘hedgedoc/config.json’
[isabell@stardust ~]$ cd hedgedoc
[isabell@stardust hedgedoc]$ bin/setup
Copying config files...
Installing packages...
yarn install v1.22.5
[1/5] Validating package.json...
[2/5] Resolving packages...
[3/5] Fetching packages...
...some info messages you can ignore
[4/5] Linking dependencies...
[5/5] Building fresh packages...
Done in 597.69s.
yarn install v1.22.5
[1/5] Validating package.json...
[2/5] Resolving packages...
success Already up-to-date.
Done in 1.22s.

Edit the following config file to setup HedgeDoc server and client.
Read more info at https://docs.hedgedoc.org/configuration/

* config.json           -- HedgeDoc config
[isabell@stardust hedgedoc]$ supervisorctl start hedgedoc
hedgedoc: started
[isabell@stardust hedgedoc]$ supervisorctl tail -f hedgedoc
==> Press Ctrl-C to exit <==
[...] no errors (red colored) should appear
[isabell@stardust hedgedoc]$ cd
[isabell@stardust ~]$ rm --recursive hedgedoc_old
[isabell@stardust ~]$

Note

Under usual circumstances you don’t need to change the config files. The setup script does not override your config files even if it says Copying config files....

Update script

Create ~/bin/hedgedoc-update with the following content:

#!/usr/bin/env bash
APP_NAME=HedgeDoc
ORG=hedgedoc # Organisation or GitHub user
REPO=hedgedoc
LOCAL_VERSION=$(jq --raw-output .version ~/hedgedoc/package.json)
LATEST_VERSION=$(curl --silent https://api.github.com/repos/$ORG/$REPO/releases/latest |
  jq --raw-output .tag_name)

function do_upgrade
{
  supervisorctl stop hedgedoc
  echo "waiting 1 minute until all processes are stopped"
  sleep 1m
  mv --verbose ~/hedgedoc ~/hedgedoc_"$LOCAL_VERSION"
  VERSION=$LATEST_VERSION
  cd || exit
  wget https://github.com/hedgedoc/hedgedoc/releases/download/"$VERSION"/hedgedoc-"$VERSION".tar.gz
  tar --extract --gzip --file=hedgedoc-"$VERSION".tar.gz
  rm --verbose hedgedoc-"$VERSION".tar.gz
  cp --verbose hedgedoc_"$LOCAL_VERSION"/config.json hedgedoc/config.json
  cd ~/hedgedoc || exit
  bin/setup
  echo "You may need to wait a minute until HedgeDoc is up and running."
  supervisorctl start hedgedoc
  echo "If everything works fine you can delete ~/hedgedoc_$LOCAL_VERSION"
  echo "Please consider that there might be uploaded files in ~/hedgedoc_$LOCAL_VERSION/public/uploads which were not migrated to the new version if you are using the default setting."
  #rm --recursive ~/hedgedoc_"$LOCAL_VERSION"
}

function yes_no_question
{
  local question=$1
  while true
  do
    read -r -p "$question (Y/n) " ANSWER
    if [ "$ANSWER" = "" ]
    then ANSWER='Y'
    fi
    case $ANSWER in
      [Yy]* | [Jj]* )
        return 0 ;;
      [Nn]* )
        return 1 ;;
      * ) echo "Please answer yes or no." ;;
    esac
  done
}

# is_version_lower_than A B
# returns whether A < B
function is_version_lower_than
{
  test "$(echo "$@" |
    tr " " "\n" |
    sort --version-sort --reverse |
    head --lines=1)" != "$1"
}

function is_update_available
{
  if is_version_lower_than "$LOCAL_VERSION" "$LATEST_VERSION"
  then return 0
  else return 1
  fi
}

function main
{
  if is_update_available
  then
    echo "There is a new Version available of $APP_NAME"
    echo "The latest Version is $LATEST_VERSION"
    echo "Your local Version is $LOCAL_VERSION"
    echo "Upgrades to next major releases are not tested."
    echo "Please read the release notes."
    echo "Also check if the upgrade instructions have changed."
    echo "Your instance might break."
    if yes_no_question "Do you wish to proceed with the upgrade?"
    then do_upgrade
    fi
  else echo "Your HedgeDoc is already up to date."
  fi
}

main "$@"
exit $?

To make this script executable you have to run this once:

[isabell@stardust ~]$ chmod u+x --verbose ~/bin/hedgedoc-update
mode of ‘/home/isabell/bin/hedgedoc-update’ changed from 0664 (rw-rw-r--) to 0764 (rwxrw-r--)
[isabell@stardust ~]$

You can run this script with:

[isabell@stardust ~]$ hedgedoc-update
Your HedgeDoc is already up to date.
[isabell@stardust ~]$

Tested with HedgeDoc 1.10.0, Node.js 20, Uberspace 7.16.0

Written by: stunkymonkey <http://stunkymonkey.de>, Matthias Kolja Miehl <https://makomi.net>, Kevin Jost <https://github.com/systemsemaphore>, EV21 <uberlab@ev21.de>