Some weeks ago I decided to move my notes from Microsoft OneNote to Joplin. Microsoft OneNote is a great tool for taking notes collaborative, but sometimes it drives me insane and I wanted a more portable form at for my notes.
Markdown is a perfect portable format, and it is widly adopted. I really like the idea behind Markdown, and I even supported a Microsoft User Voice to add native Markdown support into OneNote. So my new note taking tool had to support Markdown. Long story short: Joplin was my tool of choice. It’s running on Windows and there is also an iOS app. Joplin offers a wide range of options to sync the notes, but none of them seemed to fit my use case - Except for the Joplin Server. I’m not afaraid in running my own infrastructure. I have some Azure credits available each months, so running a small VM for a Joplin Server is a good way to use them.
VM of choice was a Azure Standard B2s (2 vcpus, 4 GiB memory), running Ubuntu 22.04 LTS. Make sure that you give your VM a public IP and setup a Network Security Group (NSG) to secure what kind of network traffic can reach your VM. I will not going into the details of deploying a Azure VM. Just reach out on Twitter or Mastodon if you have any questions.
Install Docker on Ubuntu 22.04 LTS
To install Docker on my Ubuntu VM, I followed this article on DigitalOcean closely.
You need some prerequisite package to install Docker.
sudo apt install apt-transport-https ca-certificates curl software-properties-common
Then add the GPG key for the official Docker repository.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
No you can add the repository to the sources.list directory.
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Update the packages and then install Docker.
sudo apt install docker-ce docker-compose
Build Joplin Server
To deploy Joplin Server using Docker, it all starts with a YAML file. Create the necessary folders and copy the YAML file into it.
sudo mkdir /opt/joplin-server
Create the joplin-docker-compose.yml
under /opt/joplin-server
. Please change APP_BASE_URL
and MAILER_HOST
etc. to reflect your environment.
version: '3'services: db: image: postgres:13 volumes: - ./data/postgres:/var/lib/postgresql/data ports: - "5432:5432" restart: always environment: - POSTGRES_PASSWORD=randomString4711 - POSTGRES_USER=joplin-user - POSTGRES_DB=joplindb app: image: joplin/server:latest container_name: joplin-server depends_on: - db ports: - "8080:8080" restart: always environment: - APP_PORT=8080 - APP_BASE_URL=https://notes.blazilla.de/ - DB_CLIENT=pg - POSTGRES_PASSWORD=randomString4711 - POSTGRES_DATABASE=joplindb - POSTGRES_USER=joplin-user - POSTGRES_PORT=5432 - POSTGRES_HOST=db - MAILER_ENABLED=1 - MAILER_HOST=smtp.mailbox.org - MAILER_PORT=587 - MAILER_SECURITY=starttls - MAILER_AUTH_USER=user@domain.tld - MAILER_AUTH_PASSWORD=LalalaSecurePassword4711 - MAILER_NOREPLY_NAME=Joplin Server - MAILER_NOREPLY_EMAIL=joplin-admin@blazilla.de
Start the Joplin Server.
sudo docker-compose -f joplin-docker-compose.yml up -d
When everything went smooth, you should see the running container using sudo docker ps
.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES1dd0cdc5e8af joplin/server:latest "tini -- yarn start-…" 4 weeks ago Up 2 weeks 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp joplin-server1d0be5cf36cc postgres:13 "docker-entrypoint.s…" 4 weeks ago Up 2 weeks 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp joplin-server_db_1
Setting up the reverse proxy
The Joplin Server listens in 8080/tcp, which is a bit unhandy. To connect to the Joplin Server using 443/tcp, we need to setup a reverse proxy with NGINX. First step is to install NGINX.
sudo apt install nginx
Then we need to edit the /etc/nginx/sites-available/default
. I’m using Let’s Encrypt for TLS certificates. Make sure that you get some using certbot
and modify the ssl_certificate
and ssl_certificate_key
in the default
config.
# Default server configuration#server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name _; location / { try_files $uri $uri/ =404; }}server { root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name notes.blazilla.de; location / { proxy_pass http://127.0.0.1:8080$request_uri; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; if ($request_method ~* "(GET|POST)") { add_header "Access-Control-Allow-Origin" *; } if ($request_method = OPTIONS ) { add_header "Access-Control-Allow-Origin" *; add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS, HEAD"; add_header "Access-Control-Allow-Headers" "Authorization, Origin, X-Requested-With, Content-Type, Accept"; return 200; } } listen [::]:443 ssl ipv6only=on; listen 443 ssl; ssl_certificate /etc/letsencrypt/live/notes.blazilla.de/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/notes.blazilla.de/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;}server { if ($host = notes.blazilla.de) { return 301 https://$host$request_uri; } listen 80 ; listen [::]:80 ; server_name notes.blazilla.de; return 404;}
Final test
When everything went well, you should be able to connect to the Joplin Server admin interface by using the APP_BASE_URL
. Login with the default credentials (admin user with email admin@localhost
and password admin
). Make sure to change them! Then you can add new users and setup the sync from your Joplin Desktop or smartphone App.