3 min read

How to install Briefkasten using Docker

So while doing yet another research for my self-hosted awesome list I first introduced a note taking app called Joplin. Joplin is awesome, but there is one big big big issue with it: no API. At least no server side API, but a client API. That however means that you can only use this API if you client is open on your computer. That's a bummer if you want to do some work arounds with tools like n8n.

The reason I wanted to use this API in the first place was that I wanted to save websites to Joplin. Sure there is the Joplin web clipper but that one works only on desktop. On mobile there is a very bad implementation of a share API which only saves the URL of a website into a note.

So as I still liked Joplin and didn't find a better replacement that also offers a nice REST API, I went to search for a dedicated tool to save my websites. I came across stuff like Wallabag or ArchiveBox but honestly: they didn't look great. Then I found Briefkasten on this awesome self-hosted list.

Cudos to Nico

A guy called Nico (ndom91) is the single author of the project and he gave the whole thing completely free to us, which is awesome. I also checked out the whole code and to me it seems as he is still learning as a dev (as we all do) as there is some quirks in the code and architectural questionable decisions but nonetheless he put this stuff out there and it works. The UX is clean and simple, it's a pleasure to use. The good thing about the code: it's simple to read and understand so you can dig into it yourself. No engineering overkill.

The docs are incomplete and misleading

In the docs it says that you need to use some kind of Object Storage in order to get Image capturing working for example Supabase. Well I recommend you to use Supabase in that case because if you don't you actually gonna have to do some changes to the source code. The good thing is: Supabase can be self hosted. The bad thing: it's pretty complex to setup. Another good thing: the free tier is quite usable. The questions is why he even went for Supabase as it's just used to store images, but that's another story.

So this is the misleading statement in the docs:

"you then simply need to pass the SUPABASE_URL and SUPABASE_KEY as environment variables for it to work"

That's actually not true, because you will first need to setup his second project briefkasten-scrape.

Hardcoded IDs

At the time of writing this project contains some bugs in the form of hardcoded stuff.

  1. The author left the ID of his own Supabase project in the code so there is currently no way this could work with your own project. Luckily there is already an open Pull Request which fixes hardcoded IDs for the briefkasten-scrape project.
  2. Then the bucket ID (it's actually the buckets name) is also hard coded into the briefkasten repository. So right now you need to setup a bucket on Supabase called bookmark-imgs and make it public. There is an ENV variable called SUPABASE_BUCKET_ID but that's actually not respected at the moment but it's required so you still have to set it.

briefkasten-scrape

So as mentioned this project is also required but there is another quirks: first it's not published on Docker Hub and second it contains bugs. So we have to build it ourselves from the Dockerfile to get it working.

  1. clone the repository via git clone https://github.com/ndom91/briefkasten-scrape.git (at the time of writing this you have to clone the repository of the pull request until it's merged: git clone https://github.com/ingeniumstudio/briefkasten-scrape)
  2. cd briefkasten-scrape
  3. build the Docker image docker build . -t briefkasten-scrape:latest

For Synology NAS users

  1. Make sure the Git package is installed
  2. Make sure Docker package is installed
  3. Install Portainer
  4. Enable SSH and connect to your NAS
  5. Clone the repository as mentioned above and build the Docker image
  6. You will find the Image in your Docker package as well as in your Portainer instance

docker-compose.yml

Here is my docker-compose.yml as a sample for you which you can use with Portainer

version: '3.8'

networks:
  internal:
    external: false
    
services:
  db:
    image: postgres
    restart: unless-stopped
    networks:
      - internal
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=postgres
    volumes:
      - /volume1/docker/briefkasten/db:/var/lib/postgresql/data
  app:
    image: ndom91/briefkasten
    networks:
      - internal
    restart: unless-stopped
    ports:
      - 3000:3000
    depends_on:
      - 'db'
    environment:
      - DATABASE_URL=postgres://postgres:postgres@db/postgres
      - NEXTAUTH_URL=https://bookmarks.foo.com
      - NEXTAUTH_SECRET=xxxx
      - SMTP_SERVER=smtp://foo@bar.com:xxxx@smtp.host.com:587
      - SMTP_FROM="Briefkasten <no-reply@foo.com>"
      - NEXTAUTH_URL_INTERNAL=http://localhost:3000
      - SUPABASE_URL=https://xxxx.supabase.co
      - SUPABASE_KEY=ey...
      - SUPABASE_BUCKET_ID=xxxx
  scraper:
    image: briefkasten-scrape
    networks:
      - internal
    restart: unless-stopped
    environment:
      - DATABASE_URL=postgres://postgres:postgres@db/postgres
      - SUPABASE_URL=https://SUPABASE_BUCKET_ID_HERE.supabase.co
      - SUPABASE_KEY=ey...
      - SUPABASE_BUCKET_ID=xxxx