seafile+network: document OnlyOffice HTTP/3 + save-callback hairpin fixes

2026-04-17 04:45:02 +00:00
parent fa836ff1fc
commit e57dfea3a7
2 changed files with 68 additions and 2 deletions

@@ -27,6 +27,12 @@ sudo netplan apply
Config: `/etc/caddy/Caddyfile`
```
{
servers {
protocols h1 h2
}
}
haos.alogins.net {
reverse_proxy http://192.168.1.141:8123 {
header_up X-Forwarded-For {remote_host}
@@ -82,6 +88,8 @@ vui4.alogins.net { reverse_proxy localhost:58959 }
sudo systemctl enable --now caddy
```
**HTTP/3 disabled globally** — the top-level `protocols h1 h2` option forces HTTP/1.1 and HTTP/2 only. OnlyOffice editor assets stall over HTTP/3 on distant connections (Caddy aborts with `writing: timeout: no recent network activity`), which breaks the Seafile → OnlyOffice flow. HTTP/2 handles the same payloads without issue.
### Hairpin NAT
The router does not support hairpin NAT — the server cannot reach its own public IP from within the LAN. Services that need to call back to a public domain from the host or from Docker containers must use local overrides.
@@ -94,13 +102,16 @@ Add to `/etc/hosts` on the host for any domain that needs to be reached locally:
127.0.0.1 vw.alogins.net
```
For Docker containers, use `extra_hosts` in the compose file:
For Docker containers, use `extra_hosts` in the compose file — routes to the host's Caddy via the Docker bridge gateway:
```yaml
extra_hosts:
- "docs.alogins.net:host-gateway"
- "office.alogins.net:host-gateway"
```
Applied in both directions of the Seafile ⇄ OnlyOffice integration: the `seafile` container reaches `office.alogins.net` to download files after a save callback, and the `seafile-onlyoffice` container reaches `docs.alogins.net` to post callbacks. Without the extra_hosts the requests try the public IP and hang ~134s before timing out.
**Port forwarding requirements:**
- Ports **80** and **443** forwarded on the router (source and target, remote IP empty)
- Port **10051** forwarded for Zabbix active agent connections

@@ -118,7 +118,62 @@ ONLYOFFICE_EDIT_FILE_EXTENSION = ('docx', 'pptx', 'xlsx')
ONLYOFFICE_JWT_SECRET = '<from Vaultwarden>'
```
**Hairpin NAT fix**: OnlyOffice server must call back to Seafile to download files and post save events. Since the public IP is unreachable from inside Docker, `onlyoffice.yml` uses `extra_hosts: docs.alogins.net:host-gateway` so callbacks route via the host's Caddy instead of the public IP.
**Hairpin NAT fix**: hairpin routing affects both directions of the integration:
- `onlyoffice.yml``docs.alogins.net:host-gateway` (OnlyOffice fetches files from Seafile and posts save callbacks).
- `seafile-server.yml``office.alogins.net:host-gateway` (Seahub downloads the saved file from OnlyOffice's cache after a save callback).
Without both, save callbacks time out (~134s), OnlyOffice retries, hits the backoff limit, and drops the edit into `forgotten/` — the file on disk stays at the old version and the editor shows "the file version has been changed" on reopen.
## Troubleshooting
### "Loading spreadsheet" hangs forever
OnlyOffice editor assets (e.g. `fonts_ie.js`) served over HTTP/3 can stall on distant/lossy connections — Caddy aborts with `writing: timeout: no recent network activity`. Fix: disable HTTP/3 globally in `/etc/caddy/Caddyfile`:
```
{
servers {
protocols h1 h2
}
}
```
Browsers cache the `Alt-Svc: h3` hint for 30 days, so after reloading Caddy fully quit the browser (or test in a private window) to drop the cached hint.
### "The file version has been changed" loop on reopen
Caused by Seahub's save callback timing out (hairpin NAT, see above). Symptoms in logs:
- `seahub.log`: `ConnectTimeoutError: Connection to office.alogins.net timed out`
- `seahub.access.log`: `POST /onlyoffice/editor-callback/ ... 500 285 ... 134.xxx` (seconds)
- `onlyoffice` container: `commandSfcCallback backoff limit exceeded``storeForgotten`
- Files accumulate in `/var/lib/onlyoffice/documentserver/App_Data/cache/files/forgotten/<doc_key>/output.xlsx`
After adding the `office.alogins.net:host-gateway` extra_host and recreating the seafile container, clear the stuck state:
```bash
# 1. Inspect or recover any forgotten edits first
docker exec seafile-onlyoffice ls /var/lib/onlyoffice/documentserver/App_Data/cache/files/forgotten/
# 2. Wipe OnlyOffice's forgotten cache
docker exec seafile-onlyoffice sh -c \
'rm -rf /var/lib/onlyoffice/documentserver/App_Data/cache/files/forgotten/*'
# 3. Wipe Seafile's cached doc_keys so fresh sessions generate new ones
PW=$(grep INIT_SEAFILE_MYSQL_ROOT_PASSWORD ~/agap_git/seafile/.env | cut -d= -f2)
docker exec seafile-mysql mysql -uroot -p"$PW" -e \
'DELETE FROM onlyoffice_onlyofficedockey;' seahub_db
```
Seafile stores the `(repo_id, file_path) → doc_key` mapping in `seahub_db.onlyoffice_onlyofficedockey`.
### OnlyOffice degraded after long uptime
After weeks without restart, `docservice` leaks AMQP heartbeats (`[AMQP] conn error Error: Heartbeat timeout` in `/var/log/onlyoffice/documentserver/docservice/out.log`) and Socket.IO sessions fail (`io.connection_error ... Transport unknown`). Restart clears it:
```bash
cd ~/agap_git/seafile && docker compose restart onlyoffice
```
## Notes