Joplin Server в Docker Compose: готовый файл
Joplin — отличный редактор заметок, но синхронизация через Joplin Cloud стоит подписку, а Dropbox или OneDrive в качестве бэкенда для синхронизации работают медленно и не дают контроля над данными. Joplin Server решает это: вы поднимаете свой сервер синхронизации на VPS, подключаете к нему desktop и мобильные клиенты, и заметки живут только у вас — без чужого облака и без ежемесячной платы за синхронизацию. Ниже — рабочий docker-compose.yml с Postgres, разбор переменных окружения и подключение HTTPS через Caddy.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что нужно для запуска
Joplin Server — это Node.js-приложение плюс база данных. Официально поддерживаются PostgreSQL (рекомендуется для продакшена) и SQLite (годится для теста, но при синхронизации нескольких устройств лучше сразу брать Postgres — меньше шансов упереться в блокировки базы при параллельных запросах от клиентов).
Что понадобится:
- VPS с Docker и Docker Compose (плагин
docker compose, не устаревшийdocker-compose). - Домен или поддомен, направленный на IP сервера — Joplin Server жёстко завязан на
APP_BASE_URL, и без корректного домена синхронизация будет обрываться. - Открытые порты 80/443 для HTTPS.
- Немного диска под вложения — заметки с картами хранятся вместе с базой (см. раздел про storage driver ниже).
По ресурсам ориентируйтесь на минимальный VPS: Joplin Server сам по себе лёгкий, основная нагрузка — это Postgres и объём хранимых вложений. Для 1–5 пользователей с обычными текстовыми заметками достаточно скромной конфигурации, но если вы храните в заметках много фото и PDF — берите диск с запасом, это первое, что закончится.
Docker Compose: полный файл
Структура: контейнер db с Postgres, контейнер app с Joplin Server, общий volume для данных Postgres и (опционально) volume для файлового хранилища вложений.
version: "3.8"
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: joplin
POSTGRES_PASSWORD: change_me_strong_password
POSTGRES_DB: joplin
volumes:
- joplin_db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U joplin"]
interval: 10s
timeout: 5s
retries: 5
app:
image: joplin/server:latest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:22300:22300"
environment:
APP_PORT: "22300"
APP_BASE_URL: "https://notes.example.com"
DB_CLIENT: "pg"
POSTGRES_HOST: "db"
POSTGRES_PORT: "5432"
POSTGRES_DATABASE: "joplin"
POSTGRES_USER: "joplin"
POSTGRES_PASSWORD: "change_me_strong_password"
MAILER_ENABLED: "false"
SIGNUP_ENABLED: "false"
STORAGE_DRIVER: "Type=Database"
COOKIE_SECURE: "true"
volumes:
joplin_db:
Замените notes.example.com на свой домен и придумайте нормальный пароль вместо change_me_strong_password — этот пароль указан в двух местах, следите, чтобы они совпадали. Порт 22300 намеренно опубликован только на 127.0.0.1 — наружу сервис отдаёт reverse proxy, о нём ниже.
Запуск:
docker compose up -d
docker compose logs -f app
При первом старте Joplin Server сам прогонит миграции базы — в логах должны появиться строки о применённых migrations и в конце сообщение, что сервер слушает порт 22300.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверПеременные окружения: что менять обязательно
Часть переменных можно оставить по умолчанию, но несколько штук напрямую влияют на то, заработает ли синхронизация вообще.
| Переменная | За что отвечает | Что учесть |
|---|---|---|
APP_BASE_URL | Публичный URL сервера | Должен точно совпадать с адресом, который видят клиенты, включая https:// и без слэша в конце |
DB_CLIENT | Драйвер базы | pg для Postgres, sqlite3 для SQLite — для прод-сервера берите pg |
MAILER_ENABLED | Отправка email (сброс пароля, приглашения) | Если false, восстановить пароль пользователя через форму не получится — это ручной процесс через администратора |
SIGNUP_ENABLED | Публичная самостоятельная регистрация | Для личного сервера почти всегда держите false и создавайте пользователей вручную из админки |
STORAGE_DRIVER | Где хранятся тела заметок и вложений | Type=Database — всё в Postgres, проще для бэкапа; Type=Filesystem, Path=/data — вложения на диске, база компактнее |
COOKIE_SECURE | Требовать HTTPS для cookie сессии | Держите true, если сервер уже за HTTPS-прокси (что и должно быть) |
MAX_TIME_DRIFT | Допустимая рассинхронизация времени клиента и сервера | Обычно трогать не нужно, если время на сервере и клиентах синхронизировано через NTP |
Если планируете рассылку email (приглашения пользователям, сброс пароля), добавьте блок MAILER_HOST, MAILER_PORT, MAILER_SECURITY, MAILER_AUTH_USER, MAILER_AUTH_PASSWORD, MAILER_NOREPLY_EMAIL со своим SMTP — например, тем же почтовым сервисом, что и для остальных проектов на сервере.
Про STORAGE_DRIVER: для личного использования проще оставить Type=Database — один volume, один процесс бэкапа. Если заметок с большими вложениями много и база начинает разрастаться, переход на Type=Filesystem разгружает Postgres, но тогда бэкапить нужно уже два места — базу и папку с файлами.
Reverse proxy и HTTPS через Caddy
Joplin Server сам HTTPS не отдаёт — это задача прокси. Проще всего поднять Caddy рядом (в том же docker-compose или отдельным контейнером), он сам получит сертификат Let's Encrypt по домену.
Caddyfile:
notes.example.com {
reverse_proxy 127.0.0.1:22300
}
Или добавьте Caddy как ещё один сервис в тот же compose-файл, если хотите держать всё в одном месте:
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
depends_on:
- app
и добавьте caddy_data в общий блок volumes. Если у вас на сервере уже стоит Traefik или nginx для других сайтов — используйте их и просто добавьте виртуальный хост на порт 22300, отдельный Caddy тогда не нужен. Разницу между вариантами разбирали в статье Caddy или Nginx — что выбрать для сервера.
Главная ошибка на этом шаге — APP_BASE_URL не совпадает с реальным адресом (например, забыли протокол или указали IP вместо домена). Клиент в таком случае либо не подключается, либо синхронизация зависает на первом же запросе — проверяйте это в первую очередь.
Первый запуск, админ и подключение клиентов
После docker compose up -d откройте https://notes.example.com в браузере — должна появиться форма входа. Стандартный админ-аккаунт после установки: логин admin@localhost, пароль admin. Первым делом зайдите под ним и смените и логин, и пароль — дефолтные значения известны всем, кто читал документацию Joplin Server.
Дальше в админке (/admin/users) создайте обычных пользователей — по одному на каждого человека, который будет синхронизировать заметки. У каждого пользователя своё пространство, они не видят чужие заметки.
Подключение клиента (desktop-приложение Joplin):
- Настройки → Синхронизация.
- Target sync: Joplin Server.
- URL сервера: ваш
https://notes.example.com. - Email и пароль — те, что создали в админке.
- Нажать «Синхронизировать сейчас».
Для мобильного приложения (Android/iOS) — те же поля в разделе настроек синхронизации. Если у вас уже были заметки локально или в другом облаке, при первой синхронизации Joplin аккуратно сольёт их с сервером — конфликтующие версии он не затирает молча, а создаёт конфликт-копии, которые видно в специальной папке.
Бэкап, обновление и мониторинг
Бэкап при STORAGE_DRIVER=Type=Database сводится к бэкапу одного Postgres:
docker compose exec db pg_dump -U joplin joplin > joplin_backup_$(date +%F).sql
Автоматизировать это стоит тем же способом, что и для других баз на сервере — cron-задачей с ротацией старых копий и, желательно, выгрузкой копии за пределы сервера. Общий подход к автоматизации бэкапов и переносу вне сервера разбирали в статье про BorgBackup в Docker Compose — тот же принцип применим и к дампу Postgres от Joplin.
Восстановление:
cat joplin_backup_2026-08-20.sql | docker compose exec -T db psql -U joplin joplin
Обновление до новой версии — стандартно для docker compose:
docker compose pull app
docker compose up -d app
При обновлении Joplin Server сам применит новые миграции базы при старте — это видно в логах. Перед обновлением на прод-сервере сделайте свежий дамп базы, миграции иногда необратимы без бэкапа. Для продакшен-сервера разумнее зафиксировать конкретный тег образа вместо latest, чтобы обновление происходило осознанно, а не при случайном docker compose pull — тот же принцип описан в статье Docker Compose для продакшена: частые ошибки и решения.
Из мониторинга минимум — проверять, что контейнер app жив (docker compose ps) и что диск под Postgres не заполняется под вложениями. Для базового алертинга по доступности домена достаточно внешнего HTTP-чекера, поднимать что-то тяжёлое ради одного сервиса синхронизации заметок избыточно.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли обойтись без Postgres и хранить всё в SQLite?
Технически да — установите DB_CLIENT=sqlite3, и Joplin Server создаст файл базы сам. Для одного пользователя с редкими синхронизациями это работает, но при нескольких активных клиентах SQLite чаще упирается в блокировки при параллельных запросах — Postgres надёжнее с самого начала.
Синхронизация зависает или клиент пишет ошибку соединения — с чего начать разбор?
В первую очередь сверьте APP_BASE_URL в контейнере с реальным адресом, по которому клиент стучится (протокол, домен, без завершающего слэша). Второе по частоте — сертификат HTTPS не выпустился (проверьте логи Caddy/Traefik) или порт 22300 случайно торчит наружу вместо того, чтобы идти через прокси.
Что будет с заметками, если сервер временно недоступен?
Ничего страшного — Joplin хранит полную копию заметок локально на устройстве и просто откладывает синхронизацию до следующего успешного подключения. Данные не теряются, работа с заметками не блокируется.
Нужен ли email/SMTP, если я один пользователь сервера?
Нет, MAILER_ENABLED: "false" вполне рабочий вариант — просто вы не сможете сбросить пароль через форму «забыли пароль» и придётся менять его вручную из-под администратора в веб-интерфейсе.
Чем Joplin Server отличается от хранения заметок через WebDAV или Nextcloud?
Joplin Server — специализированный протокол синхронизации именно под Joplin: умеет диффы, конфликт-резолюшн и версии заметок на уровне приложения. WebDAV и синхронизация через Nextcloud тоже работают с Joplin, но менее эффективны на больших коллекциях заметок и не дают такой же гранулярной истории изменений.
Сколько пользователей выдержит один такой сервер?
Для семьи, команды из нескольких человек или личного использования на нескольких устройствах минимальный VPS справляется без проблем — узкое место обычно не CPU, а объём вложений на диске, если в заметки заливают много изображений и файлов.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →