Install Leanote on Docker (and automatic backups)

Leanote is an open-source Evernote alternative with markdown support, making it incredibly useful for programmers. While the notetaking application itself is as feature-rich as you’d hope and an excellent, free alternative, there are honestly no good things to say about its installation experience. This post shows how to (easily) run Leanote in Docker on a Raspberry Pi (all images provided)!

Leanote requires a MongoDB server to connect to, as well as the Go language and Revel framework. As part of my craze to containterize everything I’ve figured out a way to self-host Leanote on a Raspberry Pi.

This does come with a few obvious prerequisites:

Basic configuration

Save the following file as docker-compose.yaml in an empty directory and run docker-compose up.

The Docker Compose File

version: '3.3'

services:
  mongodb:
    restart: always
    image: danobot/mongo-rpi
    volumes:
      - /home/pi/mongo:/data/db
      # - docker_shares:/docker-shares
      # - mongodb_data:/var/lib/mongodb
    ports:
      - 27017:27017
  populate:
    image: danobot/populate-leanote
    links:
      - mongodb
  leanote:
    environment:
      - SITE_URL="http://raspberrypi:9000"
    depends_on:
      - mongodb
    restart: always
    volumes:
      - ./leanote/leanote.conf:/conf/app.conf
    image: joseba/rpi-leanote
    ports:
     - 9000:9000
    links:
      - mongodb

volumes:
  docker_shares:
  mongodb_data:

If your mongo container fails to start up due to unclean shutdowns, make sure to delete the mongod.lock file inside the leanote_data volume. This is due to killing the container. Running docker stop mongodb instead should shut down the container cleanly.

Ok, my friend. It turns out what I suggested above is, like, extremely bad practise. They recommend you run the Mongo integrity check when you get that error message and do all sorts of stuff to try and resolve the issue without deleting the mongod.lock file. Thing is.. I haven’t had any problems with deleting the mongod.lock file. Plus you should have archived database backups anyway.

The docker compose configuration references a leanote.conf file as shown below:

leanote.conf

#------------------------
# leanote config
#------------------------

http.port=9000

site.url=http://localhost:9000 # or http://x.com:8080, http://www.xx.com:9000

# admin username
adminUsername=youradminusername

# mongdb
db.host=mongodb
db.port=27017
db.dbname=leanote # required
db.username= # if not exists, please leave it blank
db.password= # if not exists, please leave it blank

# You Must Change It !! About Security!!
app.secret=yoursecretstringofrandomcharacteres3158794025237847muognsdgsiomf #

#--------------------------------
# revel config
# for dev
#--------------------------------
app.name=leanote
http.addr=
http.ssl=false
cookie.httponly=false
cookie.prefix=LEANOTE
cookie.domain= # for share cookie with sub-domain
cookie.secure=false
session.expires=3h # 3 hour. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
format.date=2006-01-02
format.datetime=2006-01-02 15:04:05 # 必须这样配置
results.chunked=false

log.trace.prefix = "TRACE "
log.info.prefix  = "INFO  "
log.warn.prefix  = "WARN  "
log.error.prefix = "ERROR "

# The default language of this application.
i18n.default_language=en-us

module.static=github.com/revel/modules/static

[dev]
mode.dev=true
results.pretty=true
watch=true

module.testrunner = # github.com/revel/modules/testrunner

log.trace.output = stderr
log.info.output  = stderr
log.warn.output  = stderr
log.error.output = stderr

[prod]
mode.dev=false
results.pretty=true
watch=false

module.testrunner =

log.trace.output = off
log.info.output  = off
log.warn.output  = %(app.name)s.log
log.error.output = %(app.name)s.log

All images referenced in this file have been specially generated for use on a Raspberry Pi. Docker images and existing configurations are plentiful on the internet, however, getting containers to work on an ARM architecture requires manual image generation more often than not. I’ve built all images and pushed them to Docker Hub to make the installation as simple as possible for you.

Populating the Mongo Database

The following is the Dockerfile for a temporary container we are going to use in order to populate our database to make it usable. You can either build the file yourself or use my image on Dockerhub danobot/populate-leanote (as specified in Docker Compose above)

FROM resin/rpi-raspbian
RUN apt update
RUN apt install mongodb-clients subversion -y
RUN svn export https://github.com/leanote/leanote/trunk/mongodb_backup/leanote_install_data/ /leanote_data
ENV MONGO_HOST mongodb
ENV LEANOTE_COLLECTION leanote
CMD mongorestore -h $MONGO_HOST -d $LEANOTE_COLLECTION --dir /leanote_data

You should be able to run docker-compose up populate in the directory containing the docker-compose.yaml file listed at the top of this post. Alternatively, you can create the container manually using the following command.

docker run --rm -it --link mongodb danobot/populate-leanote

Getting Leanote to work with SSL

If you want to integrate Leanote with the reverse proxy created in a previous post, then add the labels section to your docker-compose.yaml file.

docker-compose.yaml - leanote with labels section

leanote:
  container_name: leanote
  environment:
    - SITE_URL="https://yourdomain.com"
  depends_on:
    - mongodb
  restart: unless-stopped
  volumes:
    - ./leanote/leanote.conf:/conf/app.conf
  image: joseba/rpi-leanote
  expose:
    - 9000
  networks:
    - web
    - default
  links:
   - mongodb
  labels:
    - "traefik.backend=leanote"
    - "traefik.docker.network=web"
    - "traefik.frontend.rule=Host:yourdomain.com"
    - "traefik.enable=true"
    - "traefik.port=9000"
    - "traefik.default.protocol=http"

Automatic Daily Database Backups

Check out my post titled Automating Docker Volume Backups to find out how to configure an automatic backup script to commit daily archives of your docker images to version control.