Deploying Joplin Server on Docker
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 NAMES
1dd0cdc5e8af joplin/server:latest "tini -- yarn start-…" 4 weeks ago Up 2 weeks 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp joplin-server
1d0be5cf36cc 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.