fadenstack 0.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. faden_cli/__init__.py +16 -0
  2. faden_cli/__main__.py +9 -0
  3. faden_cli/bundle/shared/.gitignore +25 -0
  4. faden_cli/bundle/shared/LICENSE +187 -0
  5. faden_cli/bundle/shared/NOTICE +15 -0
  6. faden_cli/bundle/shared/OFFICIAL.md +9 -0
  7. faden_cli/bundle/shared/README.md +16 -0
  8. faden_cli/bundle/shared/agent-binaries/.gitignore +5 -0
  9. faden_cli/bundle/shared/alloy/config.alloy +40 -0
  10. faden_cli/bundle/shared/clickhouse/config.d/system-logs.xml +26 -0
  11. faden_cli/bundle/shared/docker-compose.gpu.yaml +34 -0
  12. faden_cli/bundle/shared/docker-compose.yaml +998 -0
  13. faden_cli/bundle/shared/grafana/dashboards/templates/vllm-runtime.json +2099 -0
  14. faden_cli/bundle/shared/grafana/provisioning/dashboards/dashboard.yml +10 -0
  15. faden_cli/bundle/shared/grafana/provisioning/dashboards/json/faden-overview.json +211 -0
  16. faden_cli/bundle/shared/grafana/provisioning/datasources/ds.yaml +9 -0
  17. faden_cli/bundle/shared/grafana/provisioning/datasources/prometheus.yaml +15 -0
  18. faden_cli/bundle/shared/initdb/01-init.sql +32 -0
  19. faden_cli/bundle/shared/loki/local-config.yaml +32 -0
  20. faden_cli/bundle/shared/nginx/locations.conf +245 -0
  21. faden_cli/bundle/shared/nginx/maintenance.html +239 -0
  22. faden_cli/bundle/shared/nginx/nginx-tls.conf +79 -0
  23. faden_cli/bundle/shared/nginx/nginx.conf +44 -0
  24. faden_cli/bundle/shared/nginx/rate-limits.conf +42 -0
  25. faden_cli/bundle/shared/nginx/security-headers.conf +22 -0
  26. faden_cli/bundle/shared/nginx/select-config.sh +37 -0
  27. faden_cli/bundle/shared/prometheus/prometheus.yml +40 -0
  28. faden_cli/bundle/shared/rabbitmq/definitions.json.example +37 -0
  29. faden_cli/bundle/shared/tls/README.md +30 -0
  30. faden_cli/cli.py +158 -0
  31. faden_cli/commands/__init__.py +1 -0
  32. faden_cli/commands/admin.py +161 -0
  33. faden_cli/commands/backup.py +159 -0
  34. faden_cli/commands/config.py +146 -0
  35. faden_cli/commands/deploy.py +949 -0
  36. faden_cli/commands/dev/__init__.py +1 -0
  37. faden_cli/commands/dev/dev_doctor.py +46 -0
  38. faden_cli/commands/dev/dev_down.py +241 -0
  39. faden_cli/commands/dev/dev_group.py +24 -0
  40. faden_cli/commands/dev/dev_init.py +710 -0
  41. faden_cli/commands/dev/dev_pull.py +297 -0
  42. faden_cli/commands/dev/dev_status.py +151 -0
  43. faden_cli/commands/dev/dev_up.py +1392 -0
  44. faden_cli/commands/doctor.py +225 -0
  45. faden_cli/commands/down.py +75 -0
  46. faden_cli/commands/logs_cmd.py +41 -0
  47. faden_cli/commands/maintenance.py +74 -0
  48. faden_cli/commands/module.py +113 -0
  49. faden_cli/commands/observe.py +95 -0
  50. faden_cli/commands/ports.py +91 -0
  51. faden_cli/commands/rebuild.py +158 -0
  52. faden_cli/commands/restore.py +139 -0
  53. faden_cli/commands/runtime_images.py +174 -0
  54. faden_cli/commands/status.py +71 -0
  55. faden_cli/commands/tls.py +722 -0
  56. faden_cli/commands/tune.py +37 -0
  57. faden_cli/commands/up.py +64 -0
  58. faden_cli/commands/upgrade.py +470 -0
  59. faden_cli/commands/version.py +78 -0
  60. faden_cli/core/__init__.py +1 -0
  61. faden_cli/core/api_client.py +77 -0
  62. faden_cli/core/backup.py +717 -0
  63. faden_cli/core/bootstrap.py +291 -0
  64. faden_cli/core/bundle.py +110 -0
  65. faden_cli/core/clickhouse.py +61 -0
  66. faden_cli/core/compose.py +484 -0
  67. faden_cli/core/console.py +106 -0
  68. faden_cli/core/detect.py +580 -0
  69. faden_cli/core/dev_modules.py +149 -0
  70. faden_cli/core/docker_env.py +147 -0
  71. faden_cli/core/edge.py +94 -0
  72. faden_cli/core/env_gen.py +598 -0
  73. faden_cli/core/git.py +219 -0
  74. faden_cli/core/install.py +288 -0
  75. faden_cli/core/installation.py +186 -0
  76. faden_cli/core/local_node.py +719 -0
  77. faden_cli/core/maintenance.py +82 -0
  78. faden_cli/core/private_files.py +133 -0
  79. faden_cli/core/registry.py +574 -0
  80. faden_cli/core/release_feed.py +342 -0
  81. faden_cli/core/rmq.py +135 -0
  82. faden_cli/core/runtime_images.py +309 -0
  83. faden_cli/core/schedule.py +278 -0
  84. faden_cli/core/settings.py +159 -0
  85. faden_cli/core/sysinfo.py +303 -0
  86. faden_cli/core/tls.py +790 -0
  87. faden_cli/core/tune.py +154 -0
  88. faden_cli/core/update_check.py +254 -0
  89. faden_cli/core/workspace.py +155 -0
  90. faden_cli/templates/env.j2 +33 -0
  91. faden_cli/tui/__init__.py +1 -0
  92. faden_cli/tui/widgets/__init__.py +1 -0
  93. faden_cli/tui/wizard/__init__.py +1 -0
  94. fadenstack-0.4.2.dist-info/METADATA +304 -0
  95. fadenstack-0.4.2.dist-info/RECORD +99 -0
  96. fadenstack-0.4.2.dist-info/WHEEL +4 -0
  97. fadenstack-0.4.2.dist-info/entry_points.txt +3 -0
  98. fadenstack-0.4.2.dist-info/licenses/LICENSE +187 -0
  99. fadenstack-0.4.2.dist-info/licenses/NOTICE +15 -0
@@ -0,0 +1,10 @@
1
+ apiVersion: 1
2
+ providers:
3
+ - name: fadenstack Provisioned
4
+ orgId: 1
5
+ folder: Fadenstack
6
+ type: file
7
+ disableDeletion: false
8
+ editable: true
9
+ options:
10
+ path: /etc/grafana/provisioning/dashboards/json
@@ -0,0 +1,211 @@
1
+ {
2
+ "id": null,
3
+ "uid": "faden-overview",
4
+ "title": "fadenstack Overview",
5
+ "tags": ["fadenstack", "overview"],
6
+ "timezone": "browser",
7
+ "schemaVersion": 39,
8
+ "version": 1,
9
+ "refresh": "30s",
10
+ "style": "dark",
11
+ "editable": true,
12
+ "time": {
13
+ "from": "now-6h",
14
+ "to": "now"
15
+ },
16
+ "timepicker": {
17
+ "refresh_intervals": ["5s", "10s", "30s", "1m", "5m"],
18
+ "time_options": ["15m", "1h", "6h", "12h", "24h", "7d"]
19
+ },
20
+ "templating": {
21
+ "list": []
22
+ },
23
+ "annotations": {
24
+ "list": [
25
+ {
26
+ "builtIn": 1,
27
+ "datasource": {
28
+ "type": "grafana",
29
+ "uid": "-- Grafana --"
30
+ },
31
+ "enable": true,
32
+ "hide": true,
33
+ "iconColor": "rgba(0, 211, 255, 1)",
34
+ "name": "Annotations & Alerts",
35
+ "type": "dashboard"
36
+ }
37
+ ]
38
+ },
39
+ "panels": [
40
+ {
41
+ "id": 1,
42
+ "title": "Log Lines / 5m",
43
+ "type": "timeseries",
44
+ "datasource": {
45
+ "type": "loki",
46
+ "uid": "loki"
47
+ },
48
+ "gridPos": {
49
+ "h": 8,
50
+ "w": 12,
51
+ "x": 0,
52
+ "y": 0
53
+ },
54
+ "targets": [
55
+ {
56
+ "refId": "A",
57
+ "expr": "sum(count_over_time({job=\"docker\"}[5m]))",
58
+ "queryType": "range"
59
+ }
60
+ ],
61
+ "options": {
62
+ "legend": {
63
+ "displayMode": "list",
64
+ "placement": "bottom"
65
+ },
66
+ "tooltip": {
67
+ "mode": "single"
68
+ }
69
+ }
70
+ },
71
+ {
72
+ "id": 2,
73
+ "title": "Top Containers by Log Volume (5m)",
74
+ "type": "barchart",
75
+ "datasource": {
76
+ "type": "loki",
77
+ "uid": "loki"
78
+ },
79
+ "gridPos": {
80
+ "h": 8,
81
+ "w": 12,
82
+ "x": 12,
83
+ "y": 0
84
+ },
85
+ "targets": [
86
+ {
87
+ "refId": "A",
88
+ "expr": "topk(10, sum by (container) (count_over_time({container!=\"\"}[5m])))",
89
+ "queryType": "range"
90
+ }
91
+ ],
92
+ "options": {
93
+ "legend": {
94
+ "displayMode": "table",
95
+ "placement": "bottom"
96
+ }
97
+ }
98
+ },
99
+ {
100
+ "id": 3,
101
+ "title": "Error Log Rate (5m)",
102
+ "type": "timeseries",
103
+ "datasource": {
104
+ "type": "loki",
105
+ "uid": "loki"
106
+ },
107
+ "gridPos": {
108
+ "h": 8,
109
+ "w": 8,
110
+ "x": 0,
111
+ "y": 8
112
+ },
113
+ "targets": [
114
+ {
115
+ "refId": "A",
116
+ "expr": "sum(count_over_time({job=\"docker\"} |= \"error\" [5m]))",
117
+ "queryType": "range"
118
+ }
119
+ ],
120
+ "fieldConfig": {
121
+ "defaults": {
122
+ "unit": "logs"
123
+ },
124
+ "overrides": []
125
+ }
126
+ },
127
+ {
128
+ "id": 4,
129
+ "title": "Warning Log Rate (5m)",
130
+ "type": "timeseries",
131
+ "datasource": {
132
+ "type": "loki",
133
+ "uid": "loki"
134
+ },
135
+ "gridPos": {
136
+ "h": 8,
137
+ "w": 8,
138
+ "x": 8,
139
+ "y": 8
140
+ },
141
+ "targets": [
142
+ {
143
+ "refId": "A",
144
+ "expr": "sum(count_over_time({job=\"docker\"} |= \"warn\" [5m]))",
145
+ "queryType": "range"
146
+ }
147
+ ],
148
+ "fieldConfig": {
149
+ "defaults": {
150
+ "unit": "logs"
151
+ },
152
+ "overrides": []
153
+ }
154
+ },
155
+ {
156
+ "id": 5,
157
+ "title": "Recent Error Logs",
158
+ "type": "logs",
159
+ "datasource": {
160
+ "type": "loki",
161
+ "uid": "loki"
162
+ },
163
+ "gridPos": {
164
+ "h": 8,
165
+ "w": 8,
166
+ "x": 16,
167
+ "y": 8
168
+ },
169
+ "targets": [
170
+ {
171
+ "refId": "A",
172
+ "expr": "{job=\"docker\"} |= \"error\"",
173
+ "queryType": "range"
174
+ }
175
+ ],
176
+ "options": {
177
+ "showTime": true,
178
+ "wrapLogMessage": true,
179
+ "enableLogDetails": true
180
+ }
181
+ },
182
+ {
183
+ "id": 6,
184
+ "title": "Recent All Logs",
185
+ "type": "logs",
186
+ "datasource": {
187
+ "type": "loki",
188
+ "uid": "loki"
189
+ },
190
+ "gridPos": {
191
+ "h": 10,
192
+ "w": 24,
193
+ "x": 0,
194
+ "y": 16
195
+ },
196
+ "targets": [
197
+ {
198
+ "refId": "A",
199
+ "expr": "{job=\"docker\"}",
200
+ "queryType": "range"
201
+ }
202
+ ],
203
+ "options": {
204
+ "showTime": true,
205
+ "wrapLogMessage": true,
206
+ "enableLogDetails": true,
207
+ "prettifyLogMessage": false
208
+ }
209
+ }
210
+ ]
211
+ }
@@ -0,0 +1,9 @@
1
+ apiVersion: 1
2
+ datasources:
3
+ - name: Loki
4
+ uid: loki
5
+ type: loki
6
+ access: proxy
7
+ orgId: 1
8
+ url: http://loki:3100
9
+ isDefault: true
@@ -0,0 +1,15 @@
1
+ # Prometheus datasource for LLM runtime (vLLM) metrics.
2
+ #
3
+ # The uid `prometheus` is load-bearing: the generated per-runtime
4
+ # dashboards (vllm-rt-*) and the reference dashboard from
5
+ # dev/vllm-dgx-monitoring all reference
6
+ # {"type": "prometheus", "uid": "prometheus"}.
7
+ apiVersion: 1
8
+ datasources:
9
+ - name: Prometheus
10
+ uid: prometheus
11
+ type: prometheus
12
+ access: proxy
13
+ url: http://prometheus:9090
14
+ isDefault: false
15
+ editable: true
@@ -0,0 +1,32 @@
1
+ -- Run by Postgres once, when its data volume is created empty.
2
+ --
3
+ -- The databases only, and no logins: every service connects as
4
+ -- POSTGRES_USER with POSTGRES_PASSWORD, which `faden deploy` writes into
5
+ -- .env at random for each install. This script used to make two more logins
6
+ -- with fixed passwords (llm_user, faden_backend), the same on every install,
7
+ -- one of them able to read every backend table. Nothing in an install uses
8
+ -- them: `faden deploy` and `faden upgrade` switch them off on an install that
9
+ -- has them, and the development stack makes the one it needs itself
10
+ -- (`faden dev up`).
11
+
12
+ CREATE EXTENSION IF NOT EXISTS vector;
13
+
14
+ -- DB for Langfuse
15
+ CREATE DATABASE langfuse;
16
+ -- DB for your RAG service
17
+ CREATE DATABASE rag;
18
+ -- DB for Fadenstack backend
19
+ CREATE DATABASE faden_backend;
20
+ -- DB for llm gateway metadata/audit
21
+ CREATE DATABASE faden_gateway;
22
+ -- DB for MCP tool registry
23
+ CREATE DATABASE faden_mcp;
24
+ -- DB for Skills Registry
25
+ CREATE DATABASE faden_skills;
26
+
27
+ -- Optional: enable pgvector in rag DB
28
+ \connect rag
29
+ CREATE EXTENSION IF NOT EXISTS vector;
30
+
31
+ \connect faden_backend
32
+ CREATE EXTENSION IF NOT EXISTS vector;
@@ -0,0 +1,32 @@
1
+ auth_enabled: false
2
+
3
+ server:
4
+ http_listen_port: 3100
5
+
6
+ common:
7
+ path_prefix: /loki
8
+ storage:
9
+ filesystem:
10
+ chunks_directory: /loki/chunks
11
+ rules_directory: /loki/rules
12
+ replication_factor: 1
13
+ ring:
14
+ kvstore:
15
+ store: inmemory
16
+
17
+ schema_config:
18
+ configs:
19
+ - from: 2024-01-01
20
+ store: tsdb
21
+ object_store: filesystem
22
+ schema: v13
23
+ index:
24
+ prefix: index_
25
+ period: 24h
26
+
27
+ limits_config:
28
+ retention_period: 168h
29
+
30
+ # No usage reports to Grafana Labs (on by default).
31
+ analytics:
32
+ reporting_enabled: false
@@ -0,0 +1,245 @@
1
+ # Fadenstack — the routes behind the front door.
2
+ #
3
+ # Shared by the plain-HTTP server (nginx.conf) and the HTTPS server
4
+ # (nginx-tls.conf), which include this file; select-config.sh decides
5
+ # which of the two runs. Every upstream is a Docker service name and is
6
+ # re-resolved, so a restarted container needs no nginx restart.
7
+ #
8
+ # Host is passed as the client sent it ($http_host, port included): on
9
+ # ports other than 80/443 ($host drops the port) the backend built its own
10
+ # address without it, and the install line sent machines to the wrong port.
11
+ #
12
+ # X-Forwarded-For is set, not appended to: nginx is the front door, so the
13
+ # address it sees is the client's. Appended, a client could put any address
14
+ # first, and the backend and gateway -- which trust these headers
15
+ # (FORWARDED_ALLOW_IPS=*: nothing but this proxy reaches them from outside)
16
+ # -- took that one for the audit log, rate limits and a machine's address.
17
+ # X-Forwarded-Proto is always nginx's own $scheme for the same reason.
18
+ #
19
+ # Maintenance: while ./nginx/maintenance.flag exists -- put down by
20
+ # `faden upgrade` for its restart, or by `faden maintenance on` -- every
21
+ # route answers 503: pages with maintenance.html, which reloads itself once
22
+ # the platform is back, and the APIs with JSON saying so. /api/health stays
23
+ # open, so the CLI can tell when the backend is up before lifting it. A
24
+ # service that does not answer at all (502/504) gets the same page.
25
+ # X-Faden-Maintenance says which: "maintenance" while the flag is down (the
26
+ # console then reloads into the page), "unavailable" for a service down.
27
+ #
28
+ # Security headers (security-headers.conf) come from the server block; a
29
+ # location with add_header lines of its own includes them again, as nginx
30
+ # would otherwise drop them there.
31
+
32
+ # ── Maintenance ───────────────────────────────────────────────
33
+ location = /_faden/maintenance.html {
34
+ internal;
35
+ set $faden_down unavailable;
36
+ if (-f /etc/nginx/faden/maintenance.flag) {
37
+ set $faden_down maintenance;
38
+ }
39
+ alias /etc/nginx/faden/maintenance.html;
40
+ default_type text/html;
41
+ add_header Cache-Control "no-store" always;
42
+ add_header Retry-After 30 always;
43
+ add_header X-Faden-Maintenance $faden_down always;
44
+ include /etc/nginx/faden/security-headers.conf;
45
+ }
46
+
47
+ # Why the page is up (the flag's JSON: reason, since, message); 404 when it is
48
+ # not down -- the page then says a service is not answering.
49
+ location = /_faden/maintenance.json {
50
+ alias /etc/nginx/faden/maintenance.flag;
51
+ default_type application/json;
52
+ add_header Cache-Control "no-store" always;
53
+ include /etc/nginx/faden/security-headers.conf;
54
+ }
55
+
56
+ location @faden_maintenance_api {
57
+ set $faden_down unavailable;
58
+ if (-f /etc/nginx/faden/maintenance.flag) {
59
+ set $faden_down maintenance;
60
+ }
61
+ default_type application/json;
62
+ add_header Cache-Control "no-store" always;
63
+ add_header Retry-After 30 always;
64
+ add_header X-Faden-Maintenance $faden_down always;
65
+ include /etc/nginx/faden/security-headers.conf;
66
+ return 503 '{"detail":"Fadenstack is not available right now: it is being updated, under maintenance or restarting. Try again in a minute.","maintenance":"$faden_down"}';
67
+ }
68
+
69
+ location @faden_maintenance_openai {
70
+ set $faden_down unavailable;
71
+ if (-f /etc/nginx/faden/maintenance.flag) {
72
+ set $faden_down maintenance;
73
+ }
74
+ default_type application/json;
75
+ add_header Cache-Control "no-store" always;
76
+ add_header Retry-After 30 always;
77
+ add_header X-Faden-Maintenance $faden_down always;
78
+ include /etc/nginx/faden/security-headers.conf;
79
+ return 503 '{"error":{"message":"Fadenstack is not available right now: it is being updated, under maintenance or restarting. Try again in a minute.","type":"service_unavailable","code":"$faden_down"}}';
80
+ }
81
+
82
+ # Too many sign-in or account requests from one address (rate-limits.conf):
83
+ # JSON, as every other /api answer.
84
+ location @faden_too_many {
85
+ default_type application/json;
86
+ add_header Retry-After 60 always;
87
+ include /etc/nginx/faden/security-headers.conf;
88
+ return 429 '{"detail":"Too many attempts from this address. Wait a minute, then try again."}';
89
+ }
90
+
91
+ # ── Backend health (/api/health) ──────────────────────────────
92
+ # Open during maintenance: `faden upgrade` waits on it to lift the flag.
93
+ location = /api/health {
94
+ set $backend http://faden-backend:8000;
95
+ proxy_pass $backend;
96
+ proxy_set_header Host $http_host;
97
+ proxy_set_header X-Real-IP $remote_addr;
98
+ proxy_set_header X-Forwarded-For $remote_addr;
99
+ proxy_set_header X-Forwarded-Proto $scheme;
100
+ }
101
+
102
+ # ── Backend API (/api/*) ──────────────────────────────────────
103
+ # The frontend calls /api/* with httponly cookies.
104
+ location /api/ {
105
+ if (-f /etc/nginx/faden/maintenance.flag) {
106
+ return 503;
107
+ }
108
+ # Only nginx's own: what the backend answers passes as it is.
109
+ error_page 502 503 = @faden_maintenance_api;
110
+ # Sign-in, password and token requests, per address; the rest is not
111
+ # counted (rate-limits.conf).
112
+ limit_req zone=faden_signin burst=20 nodelay;
113
+ limit_req zone=faden_account burst=10 nodelay;
114
+ limit_req zone=faden_refresh burst=200 nodelay;
115
+ error_page 429 = @faden_too_many;
116
+ set $backend http://faden-backend:8000;
117
+ proxy_pass $backend;
118
+ proxy_set_header Host $http_host;
119
+ proxy_set_header X-Real-IP $remote_addr;
120
+ proxy_set_header X-Forwarded-For $remote_addr;
121
+ proxy_set_header X-Forwarded-Proto $scheme;
122
+
123
+ # SSE streaming: disable buffering
124
+ proxy_buffering off;
125
+ proxy_cache off;
126
+ proxy_read_timeout 300s;
127
+ proxy_send_timeout 300s;
128
+
129
+ # WebSocket support (if needed)
130
+ proxy_http_version 1.1;
131
+ proxy_set_header Upgrade $http_upgrade;
132
+ proxy_set_header Connection $connection_upgrade;
133
+ }
134
+
135
+ # ── OpenAI-compatible API (/v1/*) ─────────────────────────────
136
+ # External API clients (curl, SDKs) can hit /v1/* through the
137
+ # same origin instead of needing a separate port.
138
+ location /v1/ {
139
+ if (-f /etc/nginx/faden/maintenance.flag) {
140
+ return 503;
141
+ }
142
+ error_page 502 503 = @faden_maintenance_openai;
143
+ set $gateway http://faden-gateway:8000;
144
+ proxy_pass $gateway;
145
+ proxy_set_header Host $http_host;
146
+ proxy_set_header X-Real-IP $remote_addr;
147
+ proxy_set_header X-Forwarded-For $remote_addr;
148
+ proxy_set_header X-Forwarded-Proto $scheme;
149
+
150
+ # SSE streaming
151
+ proxy_buffering off;
152
+ proxy_cache off;
153
+ proxy_read_timeout 300s;
154
+
155
+ proxy_http_version 1.1;
156
+ proxy_set_header Upgrade $http_upgrade;
157
+ proxy_set_header Connection $connection_upgrade;
158
+ }
159
+
160
+ # ── Gateway static assets (Swagger UI / ReDoc JS+CSS) ───────
161
+ # The gateway serves JS/CSS from /static/docs/*. This location
162
+ # makes those assets reachable via /gateway-static/* so the
163
+ # rewritten HTML (see sub_filter below) can load them.
164
+ location /gateway-static/ {
165
+ set $gw_static http://faden-gateway:8000;
166
+ rewrite ^/gateway-static/(.*)$ /static/$1 break;
167
+ proxy_pass $gw_static;
168
+ proxy_set_header Host $http_host;
169
+ }
170
+
171
+ # ── Gateway API docs (iframe-friendly path) ──────────────────
172
+ # Proxies /gateway-docs/* → faden-gateway /api/*
173
+ location /gateway-docs/ {
174
+ set $gateway_docs http://faden-gateway:8000;
175
+ rewrite ^/gateway-docs/(.*)$ /api/$1 break;
176
+ proxy_pass $gateway_docs;
177
+ proxy_set_header Host $http_host;
178
+ proxy_set_header X-Real-IP $remote_addr;
179
+ proxy_set_header X-Forwarded-For $remote_addr;
180
+ proxy_set_header X-Forwarded-Proto $scheme;
181
+
182
+ # Rewrite absolute asset paths in Swagger/ReDoc HTML so they
183
+ # load through /gateway-static/ and /gateway-docs/ instead of
184
+ # hitting the backend (/api/) or the frontend catch-all (/static/).
185
+ proxy_set_header Accept-Encoding "";
186
+ sub_filter_once off;
187
+ sub_filter_types text/html;
188
+ sub_filter '/static/docs/' '/gateway-static/docs/';
189
+ sub_filter '/api/openapi.json' '/gateway-docs/openapi.json';
190
+ }
191
+
192
+ # ── Grafana (proxied for remote access) ────────────────────
193
+ # Only for a console session allowed to read observability data: Grafana's
194
+ # anonymous viewer can query any data source (/grafana/api/ds/query), so
195
+ # without this every log and metric was open to whoever reached this port.
196
+ # The console's embedded dashboards send the session cookie and pass.
197
+ location /grafana/ {
198
+ if (-f /etc/nginx/faden/maintenance.flag) {
199
+ return 503;
200
+ }
201
+ error_page 502 503 504 =503 /_faden/maintenance.html;
202
+ auth_request /_console_access/grafana;
203
+ set $grafana http://faden-grafana:3000;
204
+ proxy_pass $grafana;
205
+ proxy_set_header Host $http_host;
206
+ proxy_set_header X-Real-IP $remote_addr;
207
+ proxy_set_header X-Forwarded-For $remote_addr;
208
+ proxy_set_header X-Forwarded-Proto $scheme;
209
+
210
+ # WebSocket support for Grafana Live
211
+ proxy_http_version 1.1;
212
+ proxy_set_header Upgrade $http_upgrade;
213
+ proxy_set_header Connection $connection_upgrade;
214
+ }
215
+
216
+ location = /_console_access/grafana {
217
+ internal;
218
+ set $backend http://faden-backend:8000;
219
+ proxy_pass $backend/api/admin/observability/grafana-access;
220
+ proxy_pass_request_body off;
221
+ proxy_set_header Content-Length "";
222
+ proxy_set_header Host $http_host;
223
+ proxy_set_header Cookie $http_cookie;
224
+ proxy_set_header Authorization $http_authorization;
225
+ proxy_set_header X-Forwarded-Proto $scheme;
226
+ }
227
+
228
+ # ── Frontend (everything else) ────────────────────────────────
229
+ # React SSR served by react-router-serve.
230
+ location / {
231
+ if (-f /etc/nginx/faden/maintenance.flag) {
232
+ return 503;
233
+ }
234
+ error_page 502 503 504 =503 /_faden/maintenance.html;
235
+ set $frontend http://faden-frontend:3000;
236
+ proxy_pass $frontend;
237
+ proxy_set_header Host $http_host;
238
+ proxy_set_header X-Real-IP $remote_addr;
239
+ proxy_set_header X-Forwarded-For $remote_addr;
240
+ proxy_set_header X-Forwarded-Proto $scheme;
241
+
242
+ proxy_http_version 1.1;
243
+ proxy_set_header Upgrade $http_upgrade;
244
+ proxy_set_header Connection $connection_upgrade;
245
+ }