homelab-codex-ws/docs/joplin-server.md

178 lines
6.2 KiB
Markdown
Raw Normal View History

2026-04-15 17:46:42 +02:00
# Joplin Server
## Description
2026-04-15 20:38:09 +02:00
This page documents the current Joplin Server state on the Hetzner VPS.
2026-04-15 17:46:42 +02:00
2026-04-15 20:38:09 +02:00
Joplin Server is running on the VPS and is reachable through Nginx Proxy Manager when requests resolve to the VPS IP.
2026-04-15 17:46:42 +02:00
## Current configuration
- Compose path: `/home/dockeruser/docker/joplin-server`
- Files:
- `/home/dockeruser/docker/joplin-server/docker-compose.yml`
- `/home/dockeruser/docker/joplin-server/.env`
- `/home/dockeruser/docker/joplin-server/README.md`
2026-04-15 20:38:09 +02:00
- Current runtime state: running
- `docker compose ps` in `/home/dockeruser/docker/joplin-server` shows:
- `joplin-db`: healthy
- `joplin-server`: up, bound to `127.0.0.1:22300`
2026-04-15 17:46:42 +02:00
- Intended public URL: `https://joplin.okit.pl`
Current DNS issue:
2026-04-15 20:38:09 +02:00
- `joplin.okit.pl` currently returns `CNAME okit.pl`, but no valid A or AAAA answer.
- Let's Encrypt failed with: `no valid A records found for joplin.okit.pl; no valid AAAA records found for joplin.okit.pl`.
- DNS needs to be fixed before normal public HTTPS works.
Fixes applied on 2026-04-15:
- Recreated the Joplin compose stack so `joplin-db` used the current Postgres 18 mount layout.
- Confirmed the Joplin `.env` password is no longer the placeholder.
- Joplin app started successfully and auto-migrated the database.
- Updated Nginx Proxy Manager's `proxy_host` database row for `joplin.okit.pl` to forward to `http://127.0.0.1:22300`, with websockets and block-exploits enabled.
- Manually updated active NPM config at `/home/dockeruser/docker/npm/data/nginx/proxy_host/1.conf` to use `127.0.0.1:22300`, because this NPM instance did not regenerate the config from SQLite on restart.
- Reloaded nginx successfully.
Successful tests on 2026-04-15:
```sh
curl -sS http://127.0.0.1:22300/api/ping -H 'Host: joplin.okit.pl'
# {"status":"ok","message":"Joplin Server is running"}
curl -sS http://127.0.0.1/api/ping -H 'Host: joplin.okit.pl'
# {"status":"ok","message":"Joplin Server is running"}
curl -sS --resolve joplin.okit.pl:80:135.181.153.108 http://joplin.okit.pl/api/ping
# {"status":"ok","message":"Joplin Server is running"}
```
Laptop-side diagnostics on 2026-04-15:
- Direct test to Joplin over Tailscale:
- Command: `curl -v --connect-timeout 5 http://100.95.58.48:22300`
- Result: connection refused.
- Observed source address: `100.121.168.72`.
- TCP test to SSH over Tailscale:
- Command: `nc -vz 100.95.58.48 22`
- Result: connection succeeded.
- TCP test to Joplin over Tailscale:
- Command: `nc -vz 100.95.58.48 22300`
- Result: connection refused.
- Classical SSH test:
- Command: `ssh -o BatchMode=yes -o ConnectTimeout=5 dockeruser@100.95.58.48 true`
- Result: local SSH client refused to run because `/etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf` has bad owner or permissions.
- Classical SSH test with global config bypassed:
- Command: `ssh -F /dev/null -o BatchMode=yes -o ConnectTimeout=5 dockeruser@100.95.58.48 true`
- Result: `Permission denied (publickey,password).`
- Tailscale SSH wrapper test:
- Command: `tailscale ssh dockeruser@100.95.58.48 true`
- Result: host key verification failed because no ED25519 host key is known for `ubuntu-4gb-hel1-1.tailedf7b1.ts.net`.
- SSH tunnel was not established from the laptop during this test because SSH authentication or host-key verification was not completed.
2026-04-15 17:46:42 +02:00
## Known facts
Joplin Compose design:
- `app`
- `image: joplin/server:latest`
- `container_name: joplin-server`
- `restart: unless-stopped`
- `env_file: .env`
- Binds only to localhost:
- `127.0.0.1:22300:22300`
- Depends on `db` with condition `service_healthy`
- Network: `joplin-net`
- `db`
- `image: postgres:18`
- `container_name: joplin-db`
- `restart: unless-stopped`
- No exposed ports
- Network: `joplin-net`
- Volume:
2026-04-15 20:38:09 +02:00
- `postgres_data:/var/lib/postgresql`
2026-04-15 17:46:42 +02:00
- Healthcheck:
- `pg_isready` using `POSTGRES_USER` and `POSTGRES_DB`
- Named volume:
- `joplin_postgres_data`
- Named network:
- `joplin-net`
Joplin `.env`:
```env
2026-04-15 20:38:09 +02:00
POSTGRES_PASSWORD=<set on VPS; not placeholder>
2026-04-15 17:46:42 +02:00
POSTGRES_USER=joplin
POSTGRES_DB=joplin
APP_PORT=22300
APP_BASE_URL=https://joplin.okit.pl
DB_CLIENT=pg
POSTGRES_HOST=db
POSTGRES_PORT=5432
```
Important notes from handoff:
2026-04-15 20:38:09 +02:00
- `POSTGRES_PASSWORD` has been changed from the original placeholder.
2026-04-15 17:46:42 +02:00
- Joplin is intentionally localhost-only.
- External access must go through Nginx Proxy Manager.
- Because Nginx Proxy Manager uses host networking, Nginx Proxy Manager should forward to `127.0.0.1:22300`.
- PostgreSQL is internal-only and should not be exposed publicly.
Required Nginx Proxy Manager proxy host for Joplin:
- Domain Names: `joplin.okit.pl`
- Scheme: `http`
- Forward Hostname / IP: `127.0.0.1`
- Forward Port: `22300`
- Websockets Support: enabled
- Block Common Exploits: enabled
- SSL:
- Request Let's Encrypt certificate
- Force SSL enabled
- HTTP/2 enabled
DNS plan from handoff:
- Create A record:
- `joplin.okit.pl -> 135.181.153.108`
- Optional AAAA record:
- `joplin.okit.pl -> 2a01:4f9:c014:98f0::1`
- For normal Let's Encrypt through Nginx Proxy Manager, ports `80` and `443` must reach this VPS publicly.
- Public DNS should not point to the Tailscale IP if using standard Let's Encrypt HTTP validation.
Commands provided in handoff to start Joplin:
```sh
cd /home/dockeruser/docker/joplin-server
nano .env
# replace POSTGRES_PASSWORD
docker compose up -d
docker compose ps
docker compose logs -f app
```
Local tests on VPS after Joplin start:
```sh
curl -I http://127.0.0.1:22300
curl -I http://127.0.0.1:81
curl -I http://127.0.0.1:80
```
Public tests after DNS and Nginx Proxy Manager config:
```sh
dig joplin.okit.pl
curl -I https://joplin.okit.pl
```
## Unknown / needs clarification
2026-04-15 20:38:09 +02:00
- Whether Nginx Proxy Manager will preserve the manual generated-conf fix after future UI edits/restarts. The SQLite row is correct, but the active generated config did not update automatically during this fix.
2026-04-15 17:46:42 +02:00
- Whether `joplin.okit.pl` DNS has been created or fixed.
- Whether the optional AAAA record is intended.
- Whether Let's Encrypt certificate issuance has succeeded.
2026-04-15 20:38:09 +02:00
- Whether the laptop has a valid SSH key or password for `dockeruser@100.95.58.48`.
- Whether the Tailscale SSH host key for `ubuntu-4gb-hel1-1.tailedf7b1.ts.net` should be accepted on the laptop.