Onlyoffice OpenAI Compitable Settings Issue and Solutions on Omarchy Linux

ONLYOFFICE AI → FreeLLMAPI via Caddy CORS Proxy

System: Omarchy (Arch Linux) · ONLYOFFICE Desktop Editors (AUR, native) · FreeLLMAPI on 127.0.0.1:3001

Status: :white_check_mark: Working. Caddy runs as a systemd service.


1. Summary

Item Value
Symptom ONLYOFFICE AI Settings → AI Models showed “Connection error”, and the Model dropdown was empty
Root cause CORS. FreeLLMAPI sends no Access-Control-Allow-* headers. It also sends Helmet-style headers (Cross-Origin-Resource-Policy: same-origin, CSP, COOP). The AI plugin sends its requests from inside the editor’s embedded browser, which enforces CORS and blocks the response
Fix A Caddy reverse proxy on http://127.0.0.1:3002 (localhost only) that adds CORS headers and removes the blocking ones
ONLYOFFICE Base URL http://127.0.0.1:3002/v1
Other apps Unchanged. They keep using http://localhost:3001/v1 directly

2. Install Caddy

sudo pacman -S caddy
caddy version

3. Configure Caddy

Working copy at ~/Caddyfile:

cat > ~/Caddyfile <<'EOF'
http://127.0.0.1:3002 {
	bind 127.0.0.1
	log {
		output stderr
		format console
	}
	header {
		Access-Control-Allow-Origin "*"
		Access-Control-Allow-Headers "*"
		Access-Control-Allow-Methods "GET, POST, OPTIONS"
		-Cross-Origin-Resource-Policy
		-Cross-Origin-Opener-Policy
		-Content-Security-Policy
	}

	@preflight method OPTIONS
	handle @preflight {
		respond 204
	}

	reverse_proxy 127.0.0.1:3001
}
EOF

What each part does:

  • http://127.0.0.1:3002: the site address. The http:// prefix is required: without it, Caddy sees an IP address, turns on automatic HTTPS with its local CA (log lines: “enabling automatic TLS”, pki.ca.local errors), and plain http:// requests fail.
  • bind 127.0.0.1: makes Caddy actually listen only on localhost, so other devices on the LAN can’t reach it (important with * CORS). The hostname in the site address only decides which requests the site answers. Without bind, Caddy still listens on all interfaces ("addr":":3002" in the log, *:3002 in ss).
  • header { ... }: adds the CORS headers and removes FreeLLMAPI’s cross-origin-blocking headers.
  • @preflight → respond 204: answers browser preflight OPTIONS requests directly.
  • reverse_proxy: forwards everything else to FreeLLMAPI.
  • log: shows each request (method, path, status). Useful for debugging; you can remove it later.

Test in the foreground (optional)

caddy run --config ~/Caddyfile     # Ctrl+C to stop

4. Run as a system service

sudo cp ~/Caddyfile /etc/caddy/Caddyfile
sudo systemctl enable --now caddy
systemctl status caddy --no-pager

After editing the Caddyfile later:

sudo cp ~/Caddyfile /etc/caddy/Caddyfile
sudo systemctl restart caddy

Check it’s bound to localhost only:

ss -tlnp | grep 3002     # should show 127.0.0.1:3002, not *:3002

5. ONLYOFFICE AI Settings

AI Settings → AI Models → Connect new AI Model

Field Value
Provider OpenAI Compatible
API key FreeLLMAPI unified key (freellmapi-…, from the FreeLLMAPI Keys page)
Base URL http://127.0.0.1:3002/v1
Model auto
Profile name freellm

Then open the Model Assignment tab and assign freellm to each task (Chat, Summarization, Translation, Text analysis…). Tasks without a model stay greyed out.

“Import Custom Provider” is not needed. It only loads a JS adapter for APIs that don’t use the OpenAI format, and it runs in the same browser, so it hits the same CORS block.


6. Debug process (how the issue was found)

Step 1: Is the server running, and is the key valid?

curl -s http://127.0.0.1:3001/v1/models -H "Authorization: Bearer <unified-key>"
  • :white_check_mark: Returned JSON with the model list (auto, fusion, …) → server, port and key are all fine.
  • :cross_mark: 401 → wrong key. Use the unified key, not a provider key.
  • :cross_mark: Connection refused → FreeLLMAPI isn’t running, or it’s on a different port.
  • Conclusion: the problem is between the editor and the server.

Step 2: Rule out localhost vs IPv6

  • Changed the Base URL from localhost to 127.0.0.1. The editor is built on Chromium, which may try IPv6 ::1 first.
  • :cross_mark: Still “Connection error” → not an address-resolution problem.
  • Docker host networking wasn’t a factor: ONLYOFFICE is installed natively from the AUR.

Step 3: Check CORS (preflight)

curl -si -X OPTIONS http://127.0.0.1:3001/v1/models \
  -H "Origin: null" \
  -H "Access-Control-Request-Method: GET" \
  -H "Access-Control-Request-Headers: authorization" | grep -i access-control
  • :cross_mark: Empty output → no CORS headers.

Full response without grep:

curl -i -X OPTIONS http://127.0.0.1:3001/v1/models \
  -H "Origin: onlyoffice://plugin" \
  -H "Access-Control-Request-Method: GET" \
  -H "Access-Control-Request-Headers: authorization,content-type"

Findings:

  • HTTP/1.1 200 OK + Allow: GET, HEAD → a generic OPTIONS reply, not CORS handling.
  • No Access-Control-Allow-Origin → the browser drops the response.
  • Cross-Origin-Resource-Policy: same-origin, CSP, COOP (Helmet defaults) → also block cross-origin use.
  • Root cause: CORS. curl works because it doesn’t enforce CORS. The editor’s embedded browser does.

Step 4: Rule out “Import Custom Provider”

  • Same browser, same CORS block → not a fix.

Step 5: Add Caddy and check the headers

curl -si -X OPTIONS http://127.0.0.1:3002/v1/models \
  -H "Origin: onlyoffice://plugin" -H "Access-Control-Request-Method: GET" | grep -i access-control
  • :white_check_mark: Shows Access-Control-Allow-Origin: * and the other Allow-* headers.

Step 6: Watch the editor’s real requests (if it still fails)

Run caddy run --config ~/Caddyfile in the foreground (with the log block), then retest in ONLYOFFICE:

  • No log lines → the editor isn’t calling the proxy (check the Base URL/port, and that Caddy is running).
  • /v1/v1/models 404 → the client adds /v1 itself; drop /v1 from the Base URL.
  • 401 → key problem.
  • :white_check_mark: After the Caddyfile was rewritten cleanly and Caddy restarted, the dropdown filled in → fixed.

Step 7: Harden the setup and make it permanent

  • Site address http://127.0.0.1:3002 + bind 127.0.0.1, checked with ss -tlnp | grep 3002.
  • Pitfall: writing 127.0.0.1:3002 without http:// turns on automatic HTTPS and breaks the plain-HTTP Base URL. Check with journalctl -u caddy -n 20 --no-pager; there should be no TLS or pki lines. HTTP/2 skipped because it requires TLS and HTTP/3 skipped… warnings are normal for plain HTTP.
  • Installed as a systemd service (section 4).

Quick decision tree

  1. curl /v1/models fails → fix the server or key.
  2. curl works, but the editor fails → check the CORS preflight headers.
  3. No Access-Control-Allow-Origin → put a CORS proxy (Caddy) in front.
  4. Proxy has the headers but the editor still fails → watch the Caddy log for the path and status code.

7. Maintenance

systemctl status caddy --no-pager   # service state
journalctl -u caddy -f          # live logs
sudo systemctl restart caddy    # after config changes
sudo systemctl disable --now caddy   # turn off
  • If FreeLLMAPI ever adds a CORS option (e.g. CORS_ORIGIN / ALLOWED_ORIGINS in its .env), you can drop Caddy and point ONLYOFFICE back to :3001.
  • If you regenerate the FreeLLMAPI unified key, update it in ONLYOFFICE AI Settings.

:robot: ONLYOFFICE Community AI Assistant

This is an AI-generated response, not a reply from a human moderator. The suggested resources may help, but are not a confirmed fix.

This is a useful, well-documented workaround for Desktop Editors versions affected by CORS handling. The diagnosis matches ONLYOFFICE’s reports: browser preflight requests can block an otherwise working OpenAI-compatible endpoint, and a CORS-capable reverse proxy is a valid workaround:

For users on 10.0.0 or later, test without the proxy first. For older builds, keeping Caddy bound to 127.0.0.1 is important because the configuration permits any origin. Never post the unified API key in logs or screenshots.


:bust_in_silhouette: Need assistance from a human moderator?

Click the :triangular_flag: Flag option on this post and select Request Moderator Assistance to request a review by the moderation team.