How to Install Joplin Server: Docker Compose Setup for Private Sync

A practical Docker Compose guide for deploying a private Joplin Server, covering PostgreSQL, APP_BASE_URL, admin initialization, user activation, client sync, HTTPS reverse proxy, and backups.

Joplin Server is the official sync server for Joplin. Once you host your own instance, your notes can stay on your VPS, NAS, or home server, while your desktop and mobile clients sync without depending on a third-party cloud drive.

The easiest deployment method today is Docker Compose: one PostgreSQL container, one Joplin Server container, and a correctly configured APP_BASE_URL.

This guide is aimed at practical self-hosting on Ubuntu, Debian, CentOS, Synology, Unraid, OpenMediaVault, or any other environment that can run Docker.

Requirements

Before starting, prepare:

  • a server or NAS that can stay online;
  • Docker and Docker Compose;
  • an internal IP if you only need LAN sync;
  • a domain name and HTTPS reverse proxy if you need sync from outside your network;
  • a real database password. Do not keep the sample password.

If you only sync between devices at home, http://LAN-IP:22300 is enough to get started. If you need external access from a phone or laptop, use Nginx Proxy Manager, Caddy, Traefik, or a similar HTTPS reverse proxy. Avoid exposing a plain HTTP service directly to the public internet.

Create a Joplin working directory

Create a dedicated directory for Joplin Server configuration and database data:

1
2
mkdir -p /data/joplin
cd /data/joplin

You can use another path, such as /opt/joplin or /volume1/docker/joplin. The important part is that the database directory must be persistent, so PostgreSQL data is not deleted with the container.

Write docker-compose.yml

Create the Compose file in the working directory:

1
nano docker-compose.yml

Paste this configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
version: '3.8'

services:
  db:
    image: postgres:16
    container_name: joplin-db
    restart: unless-stopped
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=joplin
      - POSTGRES_PASSWORD=change_this_database_password
      - POSTGRES_DB=joplin

  app:
    image: joplin/server:latest
    container_name: joplin-app
    depends_on:
      - db
    restart: unless-stopped
    ports:
      - "22300:22300"
    environment:
      - APP_PORT=22300
      - APP_BASE_URL=http://your-server-ip:22300
      - DB_CLIENT=pg
      - POSTGRES_USER=joplin
      - POSTGRES_PASSWORD=change_this_database_password
      - POSTGRES_DATABASE=joplin
      - POSTGRES_HOST=db
      - POSTGRES_PORT=5432

The two values you must change are:

  • POSTGRES_PASSWORD: the database password. It must be identical in both the db and app services;
  • APP_BASE_URL: the fixed address that Joplin clients will use to reach the server.

APP_BASE_URL is critical. It must be the address your clients can actually open:

  • LAN only: http://192.168.1.10:22300
  • public IP: http://your-public-ip:22300
  • domain with HTTPS: https://joplin.example.com

If you later change the access address, update APP_BASE_URL and restart the service. Otherwise client sync, web redirects, or attachment links may behave oddly.

Start Joplin Server

Run this in the directory containing docker-compose.yml:

1
docker compose up -d

Check the containers:

1
docker compose ps

If the first startup takes a while, watch the logs:

1
docker compose logs -f

By default, Joplin Server listens on port 22300. Open your configured APP_BASE_URL in a browser. If the login page appears, the basic deployment is working.

First admin login

The default administrator account is:

1
admin@localhost

The default password is:

1
admin

After the first login, do one thing immediately: change the administrator password. Do not leave the default password on the server, especially if the service is reachable from the internet.

In the admin UI, open the Change Password page and replace admin with a strong password.

Create a daily sync account

Do not use the administrator account for daily note sync. A cleaner setup is to create a normal user and use that account on your desktop and mobile clients.

In the admin panel:

  1. open Users;
  2. click Add user;
  3. enter the email and password you want to use;
  4. create the user.

There is one common trap: if SMTP is not configured, Joplin Server will say it sent an activation email, but you will not receive it.

The workaround is simple:

  1. go back to the admin panel;
  2. open the Emails menu;
  3. find the unsent activation email;
  4. copy the activation link inside it;
  5. open the link in a new browser tab to activate the account.

After activation, this normal user can be used for client sync.

Configure Joplin client sync

In the Joplin desktop or mobile app:

  1. open Options or settings;
  2. go to Synchronization;
  3. select Joplin Server as the synchronization target;
  4. enter your APP_BASE_URL in Joplin Server URL;
  5. enter the activated normal user’s email in Email / Username;
  6. enter that user’s password;
  7. click Check sync configuration.

If the check passes, save the settings and start syncing.

If it fails, check these first:

  • can the client open APP_BASE_URL in a browser?
  • does APP_BASE_URL match the Compose file?
  • has the normal user been activated?

Use HTTPS for external access

HTTP is usually fine for LAN-only use. For public access, use a reverse proxy and HTTPS.

Common options include:

  • Nginx Proxy Manager;
  • Caddy;
  • Traefik;
  • manual Nginx configuration.

When using a reverse proxy, APP_BASE_URL must be the final HTTPS address used by clients, for example:

1
- APP_BASE_URL=https://joplin.example.com

If you configure Nginx manually, pay attention to at least two things:

  • increase the upload limit, for example client_max_body_size 100M;, otherwise notes with large attachments may fail to sync;
  • forward Host, X-Forwarded-For, X-Forwarded-Proto, and related headers correctly, so Joplin Server can infer the right URL and protocol.

A simplified Nginx reverse proxy block:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
server {
    listen 443 ssl http2;
    server_name joplin.example.com;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:22300;
        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;
    }
}

With Nginx Proxy Manager, you usually only need to proxy the domain to port 22300 and enable an SSL certificate. Remember to change APP_BASE_URL in Compose to the HTTPS domain.

Common issues

APP_BASE_URL changes do not take effect

After editing docker-compose.yml, recreate the containers:

1
docker compose up -d

If it still behaves incorrectly, verify that the container environment variables have really changed. Editing the file alone is not enough if the service was not restarted.

Client sync reports a network error

Check these first:

  • can your phone or computer open Joplin Server in a browser?
  • is the reverse proxy certificate valid?
  • is APP_BASE_URL the actual client-facing address?
  • does the firewall allow 22300 or the HTTPS port?
  • has the normal user been activated?

Large attachments fail to sync

If you access Joplin Server through Nginx or another reverse proxy, check the upload size limit first. Nginx defaults may be too small, so set:

1
client_max_body_size 100M;

Increase it further if your note attachments are larger.

Can I use it without SMTP?

Yes. For personal or family use, SMTP is not required. After creating a user, open the Emails page in the admin panel and copy the activation link manually.

For long-term team use, configure SMTP so registration, password resets, and notifications work properly.

Backup advice

The most important Joplin Server data is in PostgreSQL. In the example above, it is stored under:

1
/data/joplin/data/postgres

Back up this directory regularly, or use PostgreSQL pg_dump for database backups. Backing up only the Joplin Server container is not useful; the container can be pulled again, but the database contains your sync data.

The local clients also keep copies of your notes, but do not treat them as your only backup. A more robust setup is server database backup + local client copies + occasional JEX exports.

Deploy Joplin Server on Synology DSM 7.x

On Synology DSM 7.x, the easiest way to deploy Joplin Server is to use the “Project” feature in Container Manager. Under the hood, it is Docker Compose: one PostgreSQL database container, one Joplin Server container, and Synology handles image pulls, container creation, and day-to-day startup management.

This is the Synology-specific version of the setup. It focuses on File Station directories, Container Manager projects, LAN access, remote sync, and reverse proxy details. If you already write docker-compose.yml by hand on Linux servers, the flow will look familiar. If you mostly use Synology’s GUI, you can follow along directly.

When this setup makes sense

Joplin Server is useful if you want to keep note sync data on your own device. It lets Windows, macOS, iOS, Android, and other Joplin clients sync through your own server instead of relying on a third-party cloud drive.

Deploying it on Synology is a good fit when:

  • your NAS stays online and can act as a home or personal sync server;
  • you only need to sync computers and phones on the LAN;
  • you want remote sync through Tailscale, WireGuard, or a reverse proxy;
  • you prefer managing containers through Container Manager instead of SSH all the way.

If you are only trying Joplin temporarily, you do not necessarily need Joplin Server. Joplin also supports WebDAV, S3, Dropbox, and other sync methods. For long-term self-hosting, however, Joplin Server is the more complete option.

Step 1: Prepare directories in File Station

Open Synology File Station and go to the docker shared folder.

Create a directory:

1
docker/joplin

Inside joplin, create another directory:

1
postgres_data

The final structure should look like this:

1
2
3
docker/
└── joplin/
    └── postgres_data/

postgres_data stores the PostgreSQL database. Joplin Server’s sync data mainly lives in the database, so this directory must be persistent. When you update or recreate containers later, the data will remain as long as this directory still exists.

Step 2: Create a project in Container Manager

Open Container Manager on Synology:

  1. click Project on the left;
  2. click Create;
  3. set the project name to joplin-server;
  4. choose the /docker/joplin path you created;
  5. choose Create docker-compose.yml as the source.

Paste this Compose configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
version: '3'

services:
  db:
    image: postgres:16
    container_name: joplin-db
    volumes:
      - ./postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    environment:
      - POSTGRES_PASSWORD=change_this_database_password
      - POSTGRES_USER=joplin_user
      - POSTGRES_DB=joplin_db

  app:
    image: joplin/server:latest
    container_name: joplin-server
    depends_on:
      - db
    ports:
      - "22300:22300"
    restart: unless-stopped
    environment:
      - APP_PORT=22300
      - APP_BASE_URL=http://192.168.1.100:22300
      - DB_CLIENT=pg
      - POSTGRES_PASSWORD=change_this_database_password
      - POSTGRES_DATABASE=joplin_db
      - POSTGRES_USER=joplin_user
      - POSTGRES_PORT=5432
      - POSTGRES_HOST=db

Two values must be changed:

  • POSTGRES_PASSWORD: the database password. It must be identical in both places;
  • APP_BASE_URL: the actual address Joplin clients will use to reach the server.

If you only use it on the LAN, set APP_BASE_URL to your Synology LAN IP:

1
- APP_BASE_URL=http://192.168.1.100:22300

If you already have an HTTPS reverse proxy, use the public domain directly:

1
- APP_BASE_URL=https://joplin.example.com

Do not fill in APP_BASE_URL casually. Joplin client sync, web redirects, and attachment links all depend on it. The address you actually use to access the service is the address you should put here.

After confirming the configuration, continue through the wizard until it finishes. Container Manager will download postgres:16 and joplin/server:latest, then start both containers.

Step 3: Check container status

After the project is created, open the joplin-server project page in Container Manager.

You should normally see two containers:

  • joplin-db
  • joplin-server

If both are green and running, continue to the next step.

If they do not start correctly, check the project logs first. Common causes are:

  • the two database passwords do not match;
  • the postgres_data directory has permission issues;
  • port 22300 on Synology is already used by another service;
  • YAML indentation was broken.

Step 4: First login to Joplin Server

Open this in a browser:

1
http://群晖IP:22300

For example:

1
http://192.168.1.100:22300

The default administrator account is:

1
admin@localhost

The default password is:

1
admin

After the first login, change the administrator password immediately. Do not skip this step, especially if you plan to expose the service through remote access.

If the admin UI allows changing the administrator email, it is also a good idea to replace it with your own email for easier account identification later.

Step 5: Should you create a normal user?

If you are the only user, syncing with the updated administrator account works. A cleaner setup is to create a normal user and use that account for note sync, while keeping the administrator account for management only.

In the admin UI:

  1. open Users;
  2. click Add user;
  3. enter an email and password;
  4. save.

If SMTP is not configured, the system will say it sent an activation email, but you will not receive it. In that case, open the Emails page in the admin UI, find the unsent activation email, copy the activation link, and open it in a browser to activate the account.

For personal use, running without SMTP is fine. For multiple long-term users, configure SMTP later so registration, activation, and password reset are less painful.

Step 6: Configure Joplin client sync

Open the Joplin client on your computer or phone:

  1. go to Options / Settings;
  2. open Synchronization;
  3. choose Joplin Server as the sync target;
  4. enter the APP_BASE_URL you configured earlier in Joplin Server URL;
  5. enter the administrator email or normal user email;
  6. enter the corresponding password;
  7. click Check synchronization configuration.

If the check succeeds, save the settings and start syncing.

If it fails, first confirm whether the client can open Joplin Server in a browser. Many sync issues are not Joplin problems, but wrong APP_BASE_URL, an inactive account, a broken reverse proxy certificate, or a phone that is not on the same network.

Remote sync option 1: Tailscale or WireGuard

The safest and simplest way to sync remotely is to connect your phone and computer back to your home network through a VPN.

Common choices:

  • Tailscale;
  • WireGuard;
  • ZeroTier.

The benefit is that Joplin Server does not need to be exposed directly to the public internet. The URL in the Joplin client can still be your Synology LAN address, for example:

1
http://192.168.1.100:22300

When your phone is outside, connect Tailscale or WireGuard first, then open Joplin and sync.

If you do not want to deal with public IPs, DDNS, certificates, and port forwarding, this is the most stable route. The downside is that every external device must join the VPN first.

Remote sync option 2: Synology reverse proxy and HTTPS

If you want Joplin to sync directly from any network, configure an HTTPS domain for it.

The rough process is:

  1. prepare a domain or DDNS;
  2. forward port 443 on your router to Synology;
  3. in Synology Control Panel -> Login Portal -> Advanced -> Reverse Proxy, create a new rule;
  4. set the source to https://joplin.example.com:443;
  5. set the destination to http://127.0.0.1:22300 or http://Synology-LAN-IP:22300;
  6. request and bind an HTTPS certificate for the domain;
  7. change APP_BASE_URL in Compose to https://joplin.example.com;
  8. redeploy the project in Container Manager.

For reverse proxy headers, add common forwarded headers such as:

1
2
3
4
Host: $host
X-Real-IP: $remote_addr
X-Forwarded-For: $proxy_add_x_forwarded_for
X-Forwarded-Proto: $scheme

If you use Synology’s built-in reverse proxy UI, field names may vary slightly between DSM minor versions. Add them through the “custom header” or “WebSocket” related options in the interface.

Joplin may also hit upload size limits when syncing large attachments. If you use Nginx Proxy Manager or a manual Nginx setup, set:

1
client_max_body_size 100M;

If Synology’s built-in reverse proxy does not expose that option, test normal attachment sync first. If you often sync large files, Nginx Proxy Manager or Caddy will be more flexible.

Redeploy after changing APP_BASE_URL

Many people start with a LAN IP for testing and later switch to an HTTPS domain. That is fine, but do not only change the client.

You must also update the Compose configuration in the Container Manager project:

1
- APP_BASE_URL=https://joplin.example.com

Then redeploy the project so the container environment variables take effect.

If APP_BASE_URL still points to the old address, you may see:

  • client sync check failures;
  • login redirects to the wrong address;
  • broken attachment links;
  • wrong protocol behavior behind the reverse proxy.

Backup priorities

On Synology, the most important directory is:

1
docker/joplin/postgres_data

It stores the PostgreSQL database, which is the core sync data for Joplin Server. Add it to Hyper Backup or another backup plan.

A more robust setup is:

  • back up docker/joplin/postgres_data regularly;
  • keep a local copy of notes in Joplin clients;
  • export important notes as JEX from time to time;
  • confirm backups before updating containers.

Do not only back up the Joplin Server image or container configuration. Images can be downloaded again; the database is your data.

Summary

Joplin Server is not hard to deploy with Docker Compose. The real pitfalls are mostly these:

  • APP_BASE_URL must be the real address used by clients;
  • the default administrator password admin must be changed immediately;
  • without SMTP, new users need to be activated from the Emails page in the admin panel.

For LAN use, http://IP:22300 is enough. For public access, use an HTTPS reverse proxy and increase the upload size limit. Once those details are handled, Joplin Server is a stable private note sync solution.

Sources