📝 [GUIDE] Self-Hosting Joplin Server with Docker + Nginx on Ubuntu

Hey everyone! Wanted to share a full walkthrough for getting Joplin Server up and running on your own Ubuntu box using Docker. Joplin is a great open-source note-taking and to-do app, and self-hosting the sync server means your notes never touch anyone else’s infrastructure. Here’s everything you need to know.


What You’ll Need Before Starting

Make sure you have these in place before diving in:

  • A fresh Ubuntu 22.04 server

  • A fully-qualified domain name (FQDN) pointed at your server’s IP — this guide uses joplin.example.com as the example

  • SSH access via a non-root sudo user

  • Docker Compose installed

  • Nginx installed


Step 1 — Install Joplin Server

First, create a directory under /opt to keep things organized, then switch into it:

bash

sudo mkdir /opt/joplin
cd /opt/joplin/

Now create the Docker Compose file:

bash

sudo nano joplin-docker-compose.yml

Paste in the following config. A few things to note before you do:

  • 5432 and 8080 are the default ports — change them if needed

  • Replace https://joplin.example.com with your actual domain

  • Replace the POSTGRES_PASSWORD, POSTGRES_DATABASE, and POSTGRES_USER values with your own

yaml

version: '3'

services:
  db:
    image: postgres:13
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    restart: always
    environment:
      - POSTGRES_PASSWORD=Your-Password-here
      - 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://joplin.example.com
      - DB_CLIENT=pg
      - POSTGRES_PASSWORD=Your-Password-here
      - POSTGRES_DATABASE=joplindb
      - POSTGRES_USER=joplin-user
      - POSTGRES_PORT=5432
      - POSTGRES_HOST=db

This spins up a Postgres 13 container alongside the Joplin Server, which listens on port 8080. Save and close the file, then bring everything up:

bash

sudo docker-compose -f joplin-docker-compose.yml up -d

Verify both containers are running:

bash

sudo docker ps

You should see output like this:

CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS         PORTS                                       NAMES
143a9e9cdaa5   joplin/server:latest   "tini -- node dist/a…"   2 minutes ago   Up 4 seconds   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   joplin-server
1e55ccad2d52   postgres:13            "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   joplin_db_1

If you see both containers up, you’re good to move on.


Step 2 — Configure Nginx as a Reverse Proxy

Create a new Nginx config file for Joplin:

bash

sudo nano /etc/nginx/conf.d/joplin-server.conf

Add the following, swapping in your actual domain name for joplin.example.com:

nginx

server {
  listen 80;
  listen [::]:80;
  server_name joplin.example.com;

  error_log /var/log/nginx/joplin-server.error;

  location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Save it, test the config, and restart Nginx:

bash

sudo nginx -t
sudo service nginx restart

Step 3 — Firewall Rules

UFW is active by default on Ubuntu, so open up HTTP and HTTPS:

bash

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload

Step 4 — Set Up HTTPS with Let’s Encrypt

Install Certbot with the Nginx plugin:

bash

sudo apt install python3-certbot python3-certbot-nginx -y

Request your free SSL certificate (replace the domain and email with yours):

bash

sudo certbot -d joplin.example.com -m admin@example.com

Certbot handles the certificate, Nginx config update, and auto-renewal all in one shot. Restart Nginx to apply:

bash

sudo service nginx restart

Step 5 — First Login and Admin Setup

Head to your domain in a browser:

https://joplin.example.com

Log in with the default credentials:

  • Email: admin@localhost

  • Password: admin

Once in, immediately update your admin profile — click your username (Admin) in the top right and fill in your real name, email, and a strong password, then hit Update Profile.

After that, go to Admin → Users → Add user to create a non-admin account. This is the account you’ll use for client sync — it’s best practice not to sync directly with the admin account.


Step 6 — Connect Your Joplin Clients

Download the Joplin client for your platform from the official site, then:

  1. Open Preferences (Mac) / Settings (Windows) / Configuration (Mobile)

  2. Go to the Synchronisation section

  3. Set the Synchronisation target dropdown to Joplin Server

  4. Fill in your domain in the Joplin Server URL field

  5. Enter the email and password for the non-admin user you created

  6. Set your preferred sync interval

  7. Click Apply (desktop) or Check Synchronization Configuration (mobile) to save