If you use Joplin for note-taking and want to self-host your own sync server, Joplin Server is the way to go. It requires a PostgreSQL database to handle note synchronisation, and I run the web interface on port 22300.
Early on I noticed that Joplin could occasionally spike CPU usage and bog down my virtual machine. To manage this, I added hard resource limits to the Docker Compose configuration. The spikes are still occasional but now manageable — I am still experimenting with the optimal values for my setup.
My Setup Context
This runs inside an Umbrel OS virtual machine on VMware Workstation. The VM has 2 cores and 8GB RAM allocated. Resource limits help prevent any single container from starving the others.
The Stack
Joplin Server needs two containers running together — a PostgreSQL database and the Joplin Server app itself. Both are managed in a single docker-compose.yml file.
Folder Structure
Create a dedicated folder for this stack:
/home/umbrel/joplin-stack/
└── docker-compose.yml
docker-compose.yml
Inside the joplin-stack folder, create this docker-compose.yml:
services:
db:
image: postgres:13
container_name: joplin-db
volumes:
- ./joplin-data:/var/lib/postgresql/data
restart: unless-stopped
environment:
- POSTGRES_PASSWORD=your_secure_password
- POSTGRES_USER=joplin
- POSTGRES_DB=joplin
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://[YOUR_SERVER_IP]:22300
- DB_CLIENT=pg
- POSTGRES_PASSWORD=your_secure_password
- POSTGRES_DATABASE=joplin
- POSTGRES_USER=joplin
- POSTGRES_PORT=5432
- POSTGRES_HOST=db
deploy:
resources:
limits:
cpus: '0.50'
memory: 512M
Important Notes
- Replace
your_secure_passwordwith a strong password of your choice - Replace
[YOUR_SERVER_IP]with your Umbrel VM’s local IP address - If using Cloudflare Tunnel, change
APP_BASE_URLto your full domain e.g.https://joplin.yourdomain.com - The
./joplin-datavolume stores your database data in the same folder as the compose file
Deploy the Stack
SSH into your Umbrel VM and run:
cd /home/umbrel/joplin-stack
sudo docker compose up -d
Once running, access the Joplin Server web interface at http://[YOUR_SERVER_IP]:22300 and create your admin account.
About the Resource Limits
The deploy.resources.limits section caps the Joplin Server container at 50% of one CPU core and 512MB of RAM. This prevents it from consuming resources needed by other containers running on the same VM.
Still Experimenting
These resource limit values are what I am currently running — I am still fine-tuning them. If you have a more powerful machine you can increase the limits. If Joplin Server crashes on startup, try increasing memory to 768M or 1G.
Connecting the Joplin Desktop App
Once the server is running, open the Joplin desktop or mobile app:
- Go to Tools → Options → Synchronisation
- Set synchronisation target to Joplin Server
- Enter your server URL →
http://[YOUR_SERVER_IP]:22300 - Enter your admin email and password
- Click Check synchronisation configuration
Key Takeaways
- Joplin Server needs PostgreSQL — both run as separate containers in the same compose file
- Add resource limits if you are running multiple containers on a low-powered VM
- Use
restart: unless-stoppedso the stack recovers automatically after a reboot - Keep your password out of version control — never commit a real password to a public repo
- If using Cloudflare Tunnel, update
APP_BASE_URLto your full domain
