Radet Hannibal-5
Dead Simple Deployment: NoteDiscovery
verified on NoteDiscovery v0.7.6
Recently I've been quite excited by a new open source note taking application called NoteDiscovery. It has a ton of features already and seems to be growing daily at this point thanks to the dedication of its developer Guillermo Villar. The application is self-hosted and super easy to deploy thanks to the excellent docker setup and documentation.
Follow along with my tutorial here to get up and running in about 30 minutes!
Stack Overview
| OS | Ubuntu 24.04 |
| Proxy Server | Caddy |
| Hosting | Digitalocean |
For this tutorial I'm going to assume you've got a fairly fresh Ubuntu 24.04 installation running. You're free to use any hosting you like; I went with digitalcoean simply because I'm already familiar with their services and their droplets are cheap and easy to spin up. You can also just run the docker container on your local machine, but I wanted to be able to access my notes on-the-go. If you want the same you're in the right place!
Caddy reverse proxy
I went with Caddy as my reverse proxy server because it does everything I need and is very easy to set up. It even handles setting up your SSL certificates automatically! Nginx and even Apache are also options, but require quite a bit more configuration to get up and running safely.
Install caddy
apt install caddyBASHConfigure the proxy by editing /etc/caddy/Caddyfile. replace [exernal url] with a domain/subdomain pointed to your server. By default NoteDiscovery runs on port 8000, so replace [internal port] with that.
[external url] { reverse_proxy localhost:[internal port]}CADDYIn my case I pointed my subdomain notediscovery on radet5.com at my server so my config looks like this
notediscovery.radet5.com { reverse_proxy localhost:8000}CADDYThen just restart the caddy service
systemctl restart caddyBASHAlso wouldn't hurt to double check its status to make sure it is running successfully and is enabled
systemctl status caddyBASHIf that looks good, you're all set with a SSL secured reverse proxy!
Basic Auth
To lock down your server a little bit further you can also protect the proxy endpoint with a simple password. This takes a little pressure off of NoteDiscovery to handle your authentication. Since it is currently designed more for local network use this is wise.
This example is from Caddy's documentation.
basicauth { # Username "Bob", password "hiccup" Bob $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG}CADDYIt fits into your overall config like this:
notediscovery.radet5.com { reverse_proxy localhost:8000
basicauth { radet $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG }}CADDYThe basic auth configuration takes a username and a bcrypt hash; you'll need to hash your own password with bcrypt. (Check the authentication section of this tutorial for a built-in bcrypt hash generator you can use for this purpose as well as its intended use)
Note that for versions of Caddy v2.8.0 and up basicauth has been changed to basic_auth. But at the time of writing ubuntu is still using the older version in its package manager.
Creating a user
I've created a dedicated user named notediscovery on my server for running the NoteDiscovery docker container in order to isolate it from other services I'm hosting. You can use any user you like, but do not use the root account to run the docker container.
Set this variable to just copy/paste the following commands, otherwise be sure to replace every instance of $user for the rest of the commands in this tutorial with the proper username. This variable will need to be reset if you log out.
user='notediscovery'BASHAdd user
adduser $userBASHInstalling and Preparing Rootless Docker
There are two recommended ways of installing Docker on Ubuntu 24.04, either via the Ubuntu maintained package docker.io or the docker maintained package docker-ce. Each package handles the docker installation a bit differently. I decided to stick with the Ubuntu approach.
In order to avoid running the Docker container with root privileges I've also configured the system to support running Docker with user level privileges in the interest of security.
Install the docker.io base package and uidmap
apt install docker.io uidmapBASHuidmap is required for the user ID mapping used for rootless
Before we can run the docker-rootless installation script Ubuntu requires a little extra configuration. The following adds a rule to the /etc/apparmor.d/ directory as specified on the Ubuntu Blog in order to allow just our unprivileged rootlesskit process the limited kernel access it needs to run the docker deamon.
cat <<EOT | sudo tee "/etc/apparmor.d/home.$user.bin.rootlesskit"# ref: https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespacesabi <abi/4.0>,include <tunables/global>
/home/$user/bin/rootlesskit flags=(unconfined) { userns,
# Site-specific additions and overrides. See local/README for details. include if exists <local/home.$user.bin.rootlesskit>}EOTsystemctl restart apparmor.serviceBASHFinally, enable linger to allow the user level docker instance to continue running after the user has logged out. This way the service will stay up!
loginctl enable-linger $userBASHRootless setup
With that done we can log in as our user to download and run docker rootless install script. Note that you cannot su into the user account you must actually log in.
This must be run as the user who will be running the docker container, in their home direcotry
curl -fsSL https://get.docker.com/rootless | shBASHI found that in order to run docker compose properly I needed docker v2; this will download it and install it where it needs to be
mkdir -p .docker/cli-pluginscurl -SL https://github.com/docker/compose/releases/download/v2.40.3/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-composechmod +x ./.docker/cli-plugins/docker-composeBASHIt should already be running and enabled, but to just to be sure go ahead and enable and run the user level docker service
systemctl --user enable dockersystemctl --user start dockerBASHNoteDiscovery install & config
From here you can follow any of the setup instructions, but I'll go over the easiest one here: using the pre-built GHCR image.
First we create the required directories. Your markdown notes will be stored in the data directory.
mkdir -p data plugins themesBASHNext we download the default config file along with two of the themes (there are several others you're encouraged to grab from the repo! I'm a fan of Monokai personally)
curl -O https://raw.githubusercontent.com/gamosoft/notediscovery/main/config.yamlcurl -o themes/light.css https://raw.githubusercontent.com/gamosoft/notediscovery/main/themes/light.csscurl -o themes/dark.css https://raw.githubusercontent.com/gamosoft/notediscovery/main/themes/dark.cssBASHFinally, we'll need the container image itself
curl -O https://raw.githubusercontent.com/gamosoft/notediscovery/main/docker-compose.ghcr.ymlBASHAuthentication setup
Alright, let's lock it down. As per the documentation, the dev has included some handy functions for generating a password hash as well as a secret key both of which we'll need to add to our config file.
We'll need to spin up our docker image, but first let's disable networking on it temporarily since we don't have the auth set up yet. Edit docker-compose.ghcr.yml and add network_mode: "none" like this:
services: notediscovery: network_mode: "none"YAMLSpin up the container
docker compose -f docker-compose.ghcr.yml up -dBASHThis will ask you for a password and generate a bycrypt password hash for you:
docker compose -f docker-compose.ghcr.yml exec notediscovery python generate_password.pyBASHAnd this will generate a random secret key:
docker compose -f docker-compose.ghcr.yml exec notediscovery python -c "import secrets; print(secrets.token_hex(32))"BASHNow we can edit the config.yaml and copy the values we've generated into the right spots. Be sure to also enable authentication!
authentication: # Enable authentication enabled: true # Session secret key (paste the output from Step 2) secret_key: "your_generated_secret_key_here" # Password hash (paste the output from Step 1) password_hash: "$2b$12$..."YAMLIt's also a good idea to update the allowed origins, mine looks something like this:
server: allowed_origins: ["https://notediscovery.radet5.com"]YAMLOK, we should be ready to go! Remove the network_mode: "none" from the docker-compose.ghcr.yml file and then restart the container
docker compose -f docker-compose.ghcr.yml downdocker compose -f docker-compose.ghcr.yml up -dBASHIn your browser navigate to your domain and can log in and get started building out your own personal knowledge store!
Checkout the official documentation for more details on further configuration and features available to you
A final note on security
Please do be wary exposing anything to the public internet like this! I've tried to make everything moderately secure in this setup, but it is not perfect. It is important to mitigate your risks. For my own system this is an isolated server with no sensitive information and which I can easily disable should anything go awry. I recommend backing up your notes periodically and not storing sensitive information in them if you are going to put them on a publicly accessible server like this!
Thank you for following along, have fun!