diff --git a/codex_context b/codex_context new file mode 100644 index 0000000..485ceab --- /dev/null +++ b/codex_context @@ -0,0 +1 @@ +Load SESSION_STATE below as full context. Treat it as authoritative memory. Continue work accordingly. diff --git a/docs/hetzner-vps.md b/docs/hetzner-vps.md index 89f0c19..a7e2a2b 100644 --- a/docs/hetzner-vps.md +++ b/docs/hetzner-vps.md @@ -50,6 +50,16 @@ Running containers: - Nginx Proxy Manager responded `200 OK` at `http://100.95.58.48:81`. - Nginx Proxy Manager responded `200 OK` at `http://135.181.153.108:81`. - Nginx config test passes. +- Laptop-side diagnostics on 2026-04-15 verified: + - `tailscale status` shows `ubuntu-4gb-hel1-1` at `100.95.58.48` as active. + - `tailscale ping 100.95.58.48` returns pong responses through DERP relay `hel`. + - `tailscale ping 100.95.58.48` reports direct connection not established. + - `ping -c 4 100.95.58.48` returns 4 received, 0% packet loss. + - `ping -c 4 135.181.153.108` returns 4 received, 0% packet loss. + - `curl -v --connect-timeout 5 http://100.95.58.48:81` connects and returns `HTTP/1.1 200 OK`. + - `curl -I --connect-timeout 5 http://100.95.58.48:81` returns `HTTP/1.1 200 OK`. + - `curl -v --connect-timeout 5 http://135.181.153.108:81` connects and returns `HTTP/1.1 200 OK`. + - `curl -I --connect-timeout 5 http://135.181.153.108:81` returns `HTTP/1.1 200 OK`. - From a laptop/browser, the reported Nginx Proxy Manager admin UI URLs are: - `http://100.95.58.48:81` over Tailscale - `http://135.181.153.108:81` publicly if firewall allows it @@ -74,6 +84,7 @@ Nginx Proxy Manager Compose file: - Firewall rules. - Whether port `81` is intentionally reachable on public IPv4. - Whether ports `80` and `443` are publicly reachable from the internet. +- Why Tailscale direct connection is not established and traffic uses DERP relay `hel`. - Whether any services other than `npm` are running outside Docker. - Backup configuration. - Monitoring and alerting configuration. diff --git a/docs/joplin-server.md b/docs/joplin-server.md index 95477a4..cb14499 100644 --- a/docs/joplin-server.md +++ b/docs/joplin-server.md @@ -2,9 +2,9 @@ ## Description -This page documents the current Joplin Server state received from the Hetzner VPS Codex handoff. +This page documents the current Joplin Server state on the Hetzner VPS. -Joplin Server has been created on disk but is not running yet. +Joplin Server is running on the VPS and is reachable through Nginx Proxy Manager when requests resolve to the VPS IP. ## Current configuration @@ -13,14 +13,62 @@ Joplin Server has been created on disk but is not running yet. - `/home/dockeruser/docker/joplin-server/docker-compose.yml` - `/home/dockeruser/docker/joplin-server/.env` - `/home/dockeruser/docker/joplin-server/README.md` -- Current runtime state: not running -- `docker compose ps` in `/home/dockeruser/docker/joplin-server` shows no running services. +- 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` - Intended public URL: `https://joplin.okit.pl` Current DNS issue: -- `joplin.okit.pl` did not resolve from user test. -- DNS needs to be created or fixed before public HTTPS works. +- `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. ## Known facts @@ -42,7 +90,7 @@ Joplin Compose design: - No exposed ports - Network: `joplin-net` - Volume: - - `postgres_data:/var/lib/postgresql/data` + - `postgres_data:/var/lib/postgresql` - Healthcheck: - `pg_isready` using `POSTGRES_USER` and `POSTGRES_DB` - Named volume: @@ -53,7 +101,7 @@ Joplin Compose design: Joplin `.env`: ```env -POSTGRES_PASSWORD=CHANGE_ME_STRONG_PASSWORD +POSTGRES_PASSWORD= POSTGRES_USER=joplin POSTGRES_DB=joplin APP_PORT=22300 @@ -65,7 +113,7 @@ POSTGRES_PORT=5432 Important notes from handoff: -- `POSTGRES_PASSWORD` must be changed before first production start. +- `POSTGRES_PASSWORD` has been changed from the original placeholder. - 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`. @@ -121,12 +169,9 @@ curl -I https://joplin.okit.pl ## Unknown / needs clarification -- Whether `POSTGRES_PASSWORD` has been changed from `CHANGE_ME_STRONG_PASSWORD`. -- Whether `docker compose up -d` has been run for Joplin. -- Whether `joplin_postgres_data` has been created. -- Whether `joplin-net` has been created. +- 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. - Whether `joplin.okit.pl` DNS has been created or fixed. - Whether the optional AAAA record is intended. -- Whether the Nginx Proxy Manager proxy host for `joplin.okit.pl` has been created. - Whether Let's Encrypt certificate issuance has succeeded. -- Whether ports `80` and `443` reach the Hetzner VPS publicly. +- 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.