Hi,
this is an extensive guide on how to host your own Joplin server on a Raspberry Pi. Until now I had a setup like this running on a Pi 4 and a Pi 5.
If you spot any mistakes, please reply to me!
The guide was overhauled on 10.12.2023.
1 Dynamic DNS
If you don't get a static IP address from your ISP, you will need a Dynamic DNS service. This sets a hostname which will be redirected to your IP. There are a lot of providers for this, currently I use No-IP because it is free and has always worked out for me. So create an account here and set a hostname with your (external) IP address, which you can read here. Make sure you don't have a VPN active, because then the IP address will differ.
2 Port forwarding
For all this fun to work, you need to give your Pi a static IP in your router and set up port forwarding to it for port 80 and 443. There are enough instructions on how to do this all over the internet.
3 Raspberry Pi OS 64-bit
Raspberry Pi OS (formerly known as Raspbian) is 32-bit by default. But for the server you need a 64-bit system. Starting with the Raspberry Pi 3 (and some models of the 2nd generation) a 64-bit chip is installed.
To install the system image, you now need a SD card (I recommend at least 8 GB) and the Raspberry Pi Imager. After opening it up, select your Raspberry Pi and under "Operating System" go to "Raspberry Pi OS (other)" and choose "Raspberry Pi OS Lite (64-bit)". Then select your SD card, click on "Next" and "Edit settings":
General:
- Activate "Set username and password", choose a username ("pi" is often used) and a strong password.
- If needed, setup your WiFi credentials. Note: LAN is recommended as WiFi is often unstable.
- Set your locale settings.
Services:
- If you plan using your Pi headless (without keyboard and monitor), enable SSH and paste you public-key(s). If you don't know what a public key is, choose "password authentication".
Click "Save" and "Yes". After the image has been written, remove the SD card, insert it into your Pi and connect a keyboard and monitor to it or connect via SSH (tutorials for this can be found on the web) and login using your specified credentials.
4 Docker and docker-compose
Type in the following commands (each line separately):
sudo apt update; sudo apt upgrade
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
5 Joplin server
Now create a docker-compose.yml
file
nano docker-compose.yml
and paste the following:
version: '3'
services:
db:
restart: unless-stopped
image: postgres:latest
ports:
- "5432:5432"
volumes:
- /data/joplin-data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=CHANGEME
- POSTGRES_USER=joplin
- POSTGRES_DB=joplin
app:
environment:
- APP_BASE_URL=https://YOUR-DOMAIN.COM/joplin
- APP_PORT=22300
- POSTGRES_PASSWORD=CHANGEME
- POSTGRES_DATABASE=joplin
- POSTGRES_USER=joplin
- POSTGRES_PORT=5432
- POSTGRES_HOST=db
- DB_CLIENT=pg
restart: unless-stopped
image: etechonomy/joplin-server:latest
ports:
- "22300:22300"
depends_on:
- db
Replace YOUR-DOMAIN.COM
with your hostname from No-IP and the two CHANGEME
's with the same strong password.
Note: This guide configures the server to serve Joplin out of a subdirectory (https://YOUR-DOMAIN.COM/joplin
). If you'd like to have it served on your root (directly via https://YOUR-DOMAIN.COM
), simply omit the /joplin
in the APP_BASE_URL
.
Now enter the following command to start Docker compose. This process will take a good while.
sudo docker compose up -d
6 Webserver / Proxy
You have several options for proxying encrypted network traffic from outside to your Joplin server. For beginners I recommend Apache.
Apache (recommended)
6.1 Apache web server
To install Apache type the following command:
sudo apt install apache2
Further configuration is not necessary until later.
6.2 Certbot / Let's Encrypt:
To install Certbot and thus create a Let's Encrypt SSL certificate, enter the following commands:
sudo apt install snapd
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --apache
After the last command you have to register with your email address (for important notifications about your certificates) and accept the terms. You can decide if you want to share your e-mail address with EFF. Then enter your previously chosen hostname from No-IP.
Afterwards check the success by typing the hostname of No-IP into your browser. You should now be taken to the default Apache page via HTTPS.
6.3 Apache again
Now the further configuration. Enable the proxy modules:
sudo a2enmod proxy
sudo a2enmod proxy_http
And open the config for ssl:
sudo nano /etc/apache2/sites-enabled/000-default-le-ssl.conf
Add the following between <VirtualHost *:443>
and </VirtualHost>
:
ProxyPreserveHost On
ProxyPass "/joplin" http://localhost:22300
ProxyPassReverse "/joplin" http://localhost:22300
Note: If you'd like to have Joplin served from your root domain, replace the two /joplin
's by /
.
Quit by pressing Ctrl + O
, Enter
, Ctrl + X
and restart Apache:
sudo apachectl -k graceful
The Joplin interface should now be available under HTTPS://YOUR-DOMAIN.COM/joplin
.
Nginx
6.1 Nginx web server
To install Nginx type the following command:
sudo apt install nginx
Further configuration is not necessary until later.
6.2 Certbot / Let's Encrypt:
To install Certbot and thus create a Let's Encrypt SSL certificate, enter the following commands:
sudo apt install snapd
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --nginx
After the last command you have to register with your email address (for important notifications about your certificates) and accept the terms. You can decide if you want to share your e-mail address with EFF. Then enter your previously chosen hostname from No-IP.
Afterwards check the success by typing the hostname of No-IP into your browser. You should now be taken to the default Nginx page via HTTPS.
6.3 Nginx again
Now the further configuration. Open the config:
sudo nano /etc/nginx/sites-enabled/default
Add the following into the second last server block (the one where ssl is handled):
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
location /joplin/ {
proxy_redirect off;
rewrite ^/joplin/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:22300;
}
(copied from here)
Note: If you'd like to have Joplin served from your root domain, replace the /joplin/
with a /
and remove the two lines under it.
Quit by pressing Ctrl + O
, Enter
, Ctrl + X
and restart Nginx:
sudo nginx -s reload
The Joplin interface should now be available under HTTPS://YOUR-DOMAIN.COM/joplin
.
Nginx Proxy Manager (only root domain, no subdirectory)
To use Nginx Proxy Manager, you first have to add another container to the docker-compose.yml
file:
sudo docker compose down
nano docker-compose.yml
Add the following (be sure the indents match the rest of the file):
npm:
image: "jc21/nginx-proxy-manager:latest"
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "81:81"
volumes:
- /data/nginx-proxy-manager:/data
- /data/letsencrypt:/etc/letsencrypt
And fire it back up:
sudo docker compose up -d
Now browse to the local IP of your Pi, followed by :81
(for example 192.168.0.100:81
) and type in admin@example.com
as e-mail and changeme
as password. Then setup a new user with a strong password.
Click on "Hosts", "Proxy Hosts", "Add Proxy Host", type in your domain name from No-IP. Leave the protocol on http
and type the local IP of your Pi into "Forward Hostname / IP". Port will be 22300
. You can optionally enable "Cache Assets" and "Block Common Exploits". In the SSL tab, select "Request a new SSL Certificate" and activate "Force SSL" as well as "HTTP/2 Support" and agree to the terms of service. The e-mail adress you type in here is for important notifications about your certificates.Then click "Save".
The Joplin interface should now be available under HTTPS://YOUR-DOMAIN.COM
.
7 Login
To login, browse to YOUR-DOMAIN.COM/joplin
. The default e-mail is admin@localhost
with admin
as password. Please change those credentials immediately and add a non-admin user under the Users
tab for syncing your notes. Keep in mind that the server is accessible to anyone on the internet and therefore strong passwords are highly recommended.
8 Activate Dynamic-DNS
Note: some routers have in-built capabilities to update your DynDNS IP. You can use those as well.
To keep the IP address at No-IP up to date, you have to install and set up the update client of No-IP per these instructions. In order to keep the service active after a reboot, enter the following command:
sudo crontab -e
and add the following line to the end of the document:
@reboot sudo /usr/local/bin/noip2
9 Unattended security updates (Optional)
To enable automatic security updates install the unattended-upgrades
package and configure it:
sudo apt install unattended-upgrades apt-listchanges
echo unattended-upgrades unattended-upgrades/enable_auto_updates boolean true | sudo debconf-set-selections
sudo dpkg-reconfigure -f noninteractive unattended-upgrades
10 Joplin server updates
Be sure to always have a backup of your data before changing anything!
If you want to update the server, stop the server, pull the new image and bring it back up again:
sudo docker compose down; sudo docker compose pull; sudo docker compose up
Check if everything runs fine. If so, stop the server again with Ctrl + C
and start it in detached
mode to let it run in the background:
sudo docker compose up -d
Note: If you don't want to do updates to your server regularly, check out the watchtower container. I didn't include this into my guide as you should be very careful when automatically updating a database.
Thanks for any hints and improvements as well as the arm-compiled images:
Kind regards
MrKanister