Add joplin web article (#9)

This commit is contained in:
deytenit authored and GitHub committed 2026-03-20 01:32:26 +03:00
1 parent 90bf68c4c8
commit 575959ffa2
38 files changed
+1043 -554

No files matched your search

@@ -0,0 +1,227 @@
---
title: 'Joplin Web Deployment Guide'
description: 'Joplin Server & Web App deployment from scratch'
createdDate: 2026-03-20
tags: ['joplin', 'deployment', 'guide']
---
This guide describes how to deploy a private note-taking infrastructure using the Joplin Server and its web client.
## Why I Chose Joplin?
I have been using Joplin for a long time, and it has become my primary note-taking tool. There are several reasons why I chose it over other alternatives:
- **Local-First**: Notes are stored locally on your device, ensuring fast access and full ownership (especially when the internet is inaccessible).
- **Markdown Format**: Joplin uses Markdown for all notes, making it incredibly easy to export, import, or move your data to another platform if needed.
- **Easy Sharing**: The ability to share notes via the web makes collaboration or public sharing straightforward.
- **Backups**: Joplin provides robust backup options, giving me peace of mind that my data is safe.
One thing that was missing for me was the ability to quickly add or view notes when I don't have access to my primary devices (for example, at work). This article provides the solution: a self-hosted web client.
## Technical Stack Overview
1. **Joplin Server**: The synchronization server. It handles the Joplin sync protocol, account logic, and note synchronization across devices.
2. **Postgres**: The database. Essential for production performance.
3. **Joplin Web App**: A browser-based client built from the Joplin mobile app source code using React Native for Web.
## 1. The Deployment Stack
This configuration is generic, uses **Docker Volumes**, and provides a minimal setup for deploying the full stack.
### Main docker-compose.yml
This compose file is a minimal configuration to run the Joplin Server and the web app. It assumes you understand how to set up a reverse proxy, or better yet, already have your own Joplin setup.
```yaml
x-environment: &shared-environment
TZ: 'Europe/Moscow'
POSTGRES_DB: 'joplin'
POSTGRES_USER: ${SHARED_USERNAME?:error}
POSTGRES_PASSWORD: ${SHARED_PASSWORD?:error}
services:
postgres:
image: postgres:16
container_name: joplin-postgres
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
<<: *shared-environment
restart: unless-stopped
server:
image: joplin/server:3.5.2
container_name: joplin-server
depends_on:
- postgres
environment:
<<: *shared-environment
APP_PORT: 22300
APP_BASE_URL: 'https://example.com'
DB_CLIENT: 'pg'
POSTGRES_HOST: 'joplin-postgres'
POSTGRES_PORT: 5432
POSTGRES_DATABASE: 'joplin'
ports:
- '22300:22300'
restart: unless-stopped
app:
build:
context: ./app
args:
- GIT_TAG=v3.5.13
container_name: joplin-app
environment:
<<: *shared-environment
ports:
- '8080:8080'
restart: unless-stopped
volumes:
postgres_data:
```
### Dockerfile
Create an `app` directory and place this `Dockerfile` inside it to build the web client. We build our own image since the original authors don't provide one.
While there are repositories with pre-built images, it's easy enough to just create our own.
```dockerfile
# Stage 1: Build
FROM node:20-bookworm-slim AS builder
ARG GIT_TAG=v3.5.13
# Install build dependencies for Joplin monorepo
RUN apt-get update && apt-get install -y \
git python3 build-essential rsync \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Configure regional mirror and timeout for reliability
RUN corepack enable && \
yarn config set registry https://registry.npmmirror.com
# Clone specific tag
RUN git clone --depth 1 --branch ${GIT_TAG} https://github.com/laurent22/joplin.git .
# Install dependencies and build the web distribution
RUN yarn install --network-timeout 1000000
RUN cd packages/app-mobile/ && yarn web
# Stage 2: Production Server
FROM nginx:alpine
# Remove default assets
RUN rm -rf /usr/share/nginx/html/*
# Copy built app and custom nginx config
COPY --from=builder /app/packages/app-mobile/web/dist /usr/share/nginx/html/app
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]
```
### Nginx configuration
Place this `nginx.conf` alongside the `Dockerfile` in the `app` directory. Joplin is an SPA, meaning it doesn't matter where it's deployed since all navigation is handled internally without location dependency. So it's alright to just deploy it on a path that doesn't overlap with the main server, such as `/app`.
> This is a pretty minimal configuration; it assumes your reverse proxy is good enough to cover all questionable items, but you can expand it as you like.
```nginx
server {
listen 8080;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Gzip compression for performance
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1000;
# SPA Routing: Fall back to index.html if a file isn't found
location /app/ {
try_files $uri $uri/ /app/index.html;
}
# Cache static assets
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|webmanifest)$ {
expires 6M;
access_log off;
add_header Cache-Control "public, max-age=15552000, immutable";
}
}
```
## 2. Configuration
Create a `.env` file in the same directory as your `docker-compose.yml`. **Do not skip the secret generation step below.**
```bash
# --- Database Credentials ---
SHARED_USERNAME=joplin
SHARED_PASSWORD=generate_this_with_openssl
```
### Generating Secrets
Use `openssl` to easily generate secure, random strings for your `.env` entries:
```bash
# Generate SHARED_PASSWORD
openssl rand -hex 32
```
## 3. Deployment
Start your stack by running the following command:
```bash
docker compose up -d --build
```
## 4. Initial Server Setup
Before configuring the web app, you must initialize your Joplin Server:
Follow the official guide: [Joplin Server README](https://github.com/laurent22/joplin/blob/dev/packages/server/README.md)
Essentially, you need to ensure that basic synchronization via the app is functional.
## 5. Web App Showcase & Setup
Once the web app is running at `https://example.com/app/`, you will be greeted by it.
### About the Web App
![Joplin Web App Interface](https://static.ermnvldmr.com/www/articles/2026/joplin-web-deployment-guide/joplin-web-interface.webp)
It is basically the same mobile Joplin app, but in-browser. It leverages the LocalStorage API for data handling. Everything is still local-first, so after logging in, it will take some time to synchronize all remote notes.
But most importantly: _The Joplin web interface allows you to view and edit your notes directly from the browser._
> It is said that it's only guaranteed to work on Chrome due to the required API compatibility; however, I have had great success with Firefox as well. Browsers are catching up quickly.
### Authentication Setup
To connect to your self-hosted Joplin Server, go to **Settings > Synchronization** and configure the following parameters:
- **Sync Target**: Joplin Server
- **Joplin Server URL**: `https://example.com`
- **Joplin Server Email**: `your-email@example.com` (the one you just created/configured)
- **Joplin Server Password**: `your-password`
![Joplin Web App Setup](https://static.ermnvldmr.com/www/articles/2026/joplin-web-deployment-guide/joplin-web-setup.webp)
_Enjoy!_
## Resources
- [Joplin GitHub](https://github.com/laurent22/joplin)
- [Joplin Server README](https://github.com/laurent22/joplin/blob/dev/packages/server/README.md)