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.
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:
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
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.
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
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...
and then Accept the Risk and Continue
Login to the Joplin server
To login to the Joplin server use the default credentials:
username: admin@localhost
password: admin
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)
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
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
Select CA certificate
Select your certificate and at the final screen tap on Install anyway
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]