Joplin Server on Raspberry PI

Joplin
Among the numerous Note taking applications Joplin is the one I prefer to use on my daily basis. In this guide you can learn how to set up a Joplin Server on a Raspberry PI to sync your notes across different devices.

Updated 24th of September 2023

After updating to the last version on Windows the synchronization of the client failed and the message "Last error:FetchError: request to https://mydomain/joplin/api/sessions failed, reason: unable to verify the first certificate" appeared to the sidebar.

Joplin FetchError

This is clearly an indication that has to do with the certificate. I navigated to the path where I had previously installed the certificate (%userprofile%\AppData\Local\Programs\Joplin) but the certificate was missing. So, my guess is that it was removed during the update. To avoid this in the next update, I copied the certificate from my raspberry to C:\certs\local_ca.crt and changed Joplin’s client settings (Tools > Options > Synchronisation > Show Advanced Settings > Custom TLS certificates) to point to the new path:

Joplin Certificate Configuration

I closed and relaunch Joplin and the problem fixed! So it’s better to avoid using Joplin’s directory to store the certificate!


The following guide was applied on a fresh install of Raspberry Pi OS (64-bit) Lite (Release date: May 3rd 2023) on a Raspberry Pi 4 Model B. The Operating system was deployed using the official Raspberry PI Imager and raspberrypi was used as the hostname of the device.

Update and upgrade your distribution:

sudo apt update
sudo apt upgrade -y

Install Docker

Install Docker using the convenience script:

curl -sSL https://get.docker.com | sh

Check that docker started and is sunning normally by issuing the command:

sudo systemctl status docker

Docker status
Add your current user to the docker group.

sudo usermod -aG docker $USER

Reload user’s permissions without rebooting the device:

# after running this command you will be asked for your password
exec su -l $USER

Install docker compose

First install the prerequisites:

sudo apt install -y libffi-dev libssl-dev python3-dev python3-pip

and then docker-compose:

sudo pip3 install docker-compose

Set device’s Fully Qualified Domain Name (FQDN)
Edit /etc/hosts using the command

sudo nano /etc/hosts

and at the first line replace localhost with your hostname.local hostname
At this example I am using raspberrypi as the device’s hostname.
hostname

Install nginx webserver

sudo apt install -y nginx

Create a certificate authority

Generate CA’s AES private key

sudo openssl genrsa -aes256 -out /etc/ssl/private/local_ca.key 4096

When asked for a passprhase, it’s better to provide one, so if a malicious user get access to the key will not be able to create new certificates without the passphrase

Create CA’s certificate, 1826 days = 5 years

sudo openssl req -x509 -new -nodes -key /etc/ssl/private/local_ca.key -sha256 -days 1826 -out /etc/ssl/certs/local_ca.crt

You will asked for the key’s passphrase so you will need to provide the same passphrase of the previous step. (You will not be asked if you skip the passphrase in the previous step). While generating the certificate for your Certificate Authority you will be asked to provide additional information. All the fields can be skipped using the dot (.). You can use the Common Name field to name your Certificate Authority whatever you want.

Generate a self signed certificate for nginx service

sudo openssl req -new -nodes -out /etc/ssl/certs/nginx.csr -newkey rsa:4096 -keyout /etc/ssl/private/nginx.key -subj '/CN=Nginx Service'

Create the required v3 extension file for nginx service

The v3.ext file contains the properties of the v3 extension of certificates. This includes especially the SAN (subject alternative names) which contains the information about DNS or IP, which the browser needs to trust the certificate (you somehow need to make sure, that raspberry.local uses the certificate that was issued for raspberry.local). Before copying and pasting the following command you have to replace DNS.1 and IP.1 to the dns name and the IP of your Raspberry PI.

cat > nginx.ext << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = [Type Raspberry's hostname here]
IP.1 = [Type Raspberry's IP here]
EOF

You can verify the contents of the file by using:

cat nginx.ext

v3 ext

Sign nginx’s certificate

sudo openssl x509 -req -in /etc/ssl/certs/nginx.csr -CA /etc/ssl/certs/local_ca.crt -CAkey /etc/ssl/private/local_ca.key -CAcreateserial -out /etc/ssl/certs/nginx.crt -days 3650 -sha256 -extfile nginx.ext

Again, you will asked for CA’s key passphrase so you will need to provide the same passphrase as the previous step.

Create a new nginx configuration for Joplin

You can create a new configuration using nano text editor:

sudo nano /etc/nginx/sites-enabled/joplin

and then copy and paste the following configuration:

server {
  listen 443 ssl http2;
  server_name raspberrypi.local;

  ssl_certificate      /etc/ssl/certs/nginx.crt;
  ssl_certificate_key  /etc/ssl/private/nginx.key;

  location /joplin/ {
    proxy_redirect off;
    proxy_pass http://127.0.0.1:22300;
    rewrite ^/joplin/(.*)$ /$1 break;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

  }
}

Use CTRL+X and then [Y] and [Enter] to save the configuration. Restart nginx to apply the new configuration

sudo systemctl restart nginx.service

Compose Joplin Server

Create a new docker-compose.yml file

nano docker-compose.yml

and paste the following content (replace the hostname in APP_BASE_URL and username, password and database name for the postgres database at both db and app services.)

version: '3'
services:
    db:
        restart: unless-stopped
        image: postgres:13.1
        ports:
            - "5432:5432"
        volumes:
            - /data/joplin-data:/var/lib/postgresql/data
        environment:
            - POSTGRES_PASSWORD=[Enter postgres password here]
            - POSTGRES_USER=[Enter postgres username here]
            - POSTGRES_DB=[Enter postgres db name here]
    app:
        environment:
            - APP_BASE_URL=https://[raspberry hostname here]/joplin
            - APP_PORT=22300
            - POSTGRES_PASSWORD=[Enter postgres password here]
            - POSTGRES_DATABASE=[Enter postgres db name here]
            - POSTGRES_USER=[Enter postgres username here]
            - POSTGRES_PORT=5432
            - POSTGRES_HOST=db
            - DB_CLIENT=pg
        restart: unless-stopped
        image: etechonomy/joplin-server:latest
        ports:
            - "127.0.0.1:22300:22300"
        depends_on:
            - db

As before, use CTRL+X and then [Y] and [Enter] to save the configuration.

Compose the configuration

Compose the configuration file using:

docker-compose up -d

Test that the server is running

Open a new web browser window and navigate to

https://[hostname].local/joplin

Accept the certificate warnings (You can import the certificate to the browser manually to avoid this confirmation but it’s not required), by clicking Advanced...

Certificate Warning

and then Accept the Risk and Continue

Accept certificate

Login to the Joplin server

To login to the Joplin server use the default credentials:

username: admin@localhost
password: admin

Joplin Login

Don’t forget to change your default credentials, to avoid unauthorized access.

Import Certificate Authority’s Certificate to your devices for apps syncing

In order to be able to use and correctly sync your notes using the official Joplin applications you must import CA’s certificate to your devices.

Transfer the certificate file to your device

Using email or any other mean (scp, python’s http.server module etc) transfer the CA’s certificate (/etc/ssl/certs/local_ca.crt) to each of your device you want to access your Joplin Server.

Windows Joplin App [Updated: 24/09/2023]

Before importing the certificate, the app will be unable to synchronize and the following error will appear:
Error. Please check that URL, username, password, etc. are correct and that the sync target is accessible. The reported error was: request to https://[hostname].local/joplin/api/sessions failed, reason: unable to verify the first certificate (Code UNABLE_TO_VERIFY_LEAF_SIGNATURE)

joplin_win_app

To solve this error copy and paste your CA’s certificate (local_ca.crt) from your Raspberry PI (/etc/ssl/certs/local_ca.crt) to Joplin’s data directory any directory on your computer, for example:

C:\certs\

Go to Tools > Options > Synchronisation enter the following settings:

Joplin Server URL: https://[hostname].local/joplin
Joplin Server email: [admin@localhost or any new user created in joplin's web interface]
Joplin Server password: [user's password]

click Show Advanced Settings, and in Custom TLS certificates type the full path to the certificate:

C:\certs\local_ca.crt

Joplin Certificate Configuration
Click Ok. Close and re-open Joplin and test synchronisation.

Android Joplin app

To import the certificate file, after transferring it to your Android device, go to Settings -> Encryption & credentials and tap on Install a certificate
AndroidCA
Select CA certificate
AncroidCA_2
Select your certificate and at the final screen tap on Install anyway
AndroidCA_3
After those steps launch the Joplin app, navigate to Configuration and at the Synchronisation section set the following settings:

Synchronisation target: Joplin Server(Beta)
Joplin Server URL: https://[hostname].local/joplin
Joplin Server email: [admin@localhost or any new user created in joplin's web interface]
Joplin Server password: [user's password]
0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments