openvibers/openvibe.ai Commits

deploy/nginx: api.openvibe.exchange, the Exchange's public API host (#313)

OP OpenVibers committed 7 days ago · 93165e7bc1 · 1 file, +97 −0

Installed on the host 2026-11-06 (by hand, like ai.openvibe.services.conf; nginx -t gated) with a proxied Cloudflare
record and the *.openvibe.exchange wildcard certificate. Only the public API reaches AI: POST /v1/chat/completions,
POST /v1/messages, GET /v1/models, GET /api/v1/exchange/*, GET /openapi.json; the bare host redirects to the docs and
anything else is a JSON 404.

Changes

ddiff --git a/deploy/nginx/api.openvibe.exchange.conf b/deploy/nginx/api.openvibe.exchange.conf
nnew file mode 100644
iindex 0000000..3d38513
---- /dev/null
++++ b/deploy/nginx/api.openvibe.exchange.conf
@@@ -0,0 +1,97 @@
++# api.openvibe.exchange: the public API host of OpenVibe.Exchange (design EXCHANGE-REMAKE-2026-11-06), served by
++# OpenVibe.AI on 127.0.0.1:4700. Only the public API: the OpenAI- and Anthropic-compatible endpoints, the model list,
++# Exchange's read API and the OpenAPI document. Everything else answers 404; the bare host sends people to the docs.
++# The certificate is the *.openvibe.exchange wildcard. The limit_req zone ovai_apps is defined in
++# ai.openvibe.services.conf (http context) and shared.
++server {
++ listen 80;
++ listen [::]:80;
++ server_name api.openvibe.exchange;
++ location /.well-known/acme-challenge/ { root /var/www/certbot; }
++ location / { return 301 https://api.openvibe.exchange$request_uri; }
++}
++server {
++ listen 443 ssl;
++ listen [::]:443 ssl;
++ http2 on;
++ server_name api.openvibe.exchange;
++ include snippets/security-txt.conf;
++ ssl_certificate /etc/letsencrypt/live/openvibe.exchange/fullchain.pem;
++ ssl_certificate_key /etc/letsencrypt/live/openvibe.exchange/privkey.pem;
++ ssl_protocols TLSv1.2 TLSv1.3;
++ access_log /var/log/nginx/api.openvibe.exchange.access.log;
++ error_log /var/log/nginx/api.openvibe.exchange.error.log;
++ client_max_body_size 12m;
++ add_header X-Content-Type-Options nosniff always;
++ add_header Referrer-Policy strict-origin-when-cross-origin always;
++ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
++
++ location = / { return 301 https://openvibe.exchange/api; }
++
++ # OpenAI-compatible Chat Completions and Anthropic-compatible Messages: POST, streamed answers.
++ location = /v1/chat/completions {
++ limit_req zone=ovai_apps burst=20 nodelay;
++ limit_req_status 429;
++ limit_except POST { deny all; }
++ proxy_pass http://127.0.0.1:4700;
++ proxy_http_version 1.1;
++ proxy_set_header Host $host;
++ proxy_set_header X-Real-IP $remote_addr;
++ proxy_set_header X-Forwarded-For $remote_addr;
++ proxy_set_header CF-Connecting-IP $remote_addr;
++ proxy_set_header X-Forwarded-Proto $scheme;
++ proxy_buffering off;
++ proxy_read_timeout 120s;
++ }
++ location = /v1/messages {
++ limit_req zone=ovai_apps burst=20 nodelay;
++ limit_req_status 429;
++ limit_except POST { deny all; }
++ proxy_pass http://127.0.0.1:4700;
++ proxy_http_version 1.1;
++ proxy_set_header Host $host;
++ proxy_set_header X-Real-IP $remote_addr;
++ proxy_set_header X-Forwarded-For $remote_addr;
++ proxy_set_header CF-Connecting-IP $remote_addr;
++ proxy_set_header X-Forwarded-Proto $scheme;
++ proxy_buffering off;
++ proxy_read_timeout 120s;
++ }
++ location = /v1/models {
++ limit_req zone=ovai_apps burst=20 nodelay;
++ limit_req_status 429;
++ limit_except GET { deny all; }
++ proxy_pass http://127.0.0.1:4700;
++ proxy_http_version 1.1;
++ proxy_set_header Host $host;
++ proxy_set_header X-Real-IP $remote_addr;
++ proxy_set_header X-Forwarded-For $remote_addr;
++ proxy_set_header CF-Connecting-IP $remote_addr;
++ proxy_set_header X-Forwarded-Proto $scheme;
++ }
++ # Exchange's public read API (catalog, a model's offers, aggregate usage) and the OpenAPI document.
++ location ^~ /api/v1/exchange/ {
++ limit_req zone=ovai_apps burst=20 nodelay;
++ limit_req_status 429;
++ limit_except GET { deny all; }
++ proxy_pass http://127.0.0.1:4700;
++ proxy_http_version 1.1;
++ proxy_set_header Host $host;
++ proxy_set_header X-Real-IP $remote_addr;
++ proxy_set_header X-Forwarded-For $remote_addr;
++ proxy_set_header CF-Connecting-IP $remote_addr;
++ proxy_set_header X-Forwarded-Proto $scheme;
++ }
++ location = /openapi.json {
++ limit_except GET { deny all; }
++ proxy_pass http://127.0.0.1:4700;
++ proxy_http_version 1.1;
++ proxy_set_header Host $host;
++ proxy_set_header X-Forwarded-Proto $scheme;
++ }
++
++ location / {
++ default_type application/json;
++ return 404 '{"error":{"message":"Not found. The API is POST /v1/chat/completions, POST /v1/messages and GET /v1/models; docs at https://openvibe.exchange/api","type":"invalid_request_error","code":"not_found"}}';
++ }
++}