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.
- faden_cli/__init__.py +16 -0
- faden_cli/__main__.py +9 -0
- faden_cli/bundle/shared/.gitignore +25 -0
- faden_cli/bundle/shared/LICENSE +187 -0
- faden_cli/bundle/shared/NOTICE +15 -0
- faden_cli/bundle/shared/OFFICIAL.md +9 -0
- faden_cli/bundle/shared/README.md +16 -0
- faden_cli/bundle/shared/agent-binaries/.gitignore +5 -0
- faden_cli/bundle/shared/alloy/config.alloy +40 -0
- faden_cli/bundle/shared/clickhouse/config.d/system-logs.xml +26 -0
- faden_cli/bundle/shared/docker-compose.gpu.yaml +34 -0
- faden_cli/bundle/shared/docker-compose.yaml +998 -0
- faden_cli/bundle/shared/grafana/dashboards/templates/vllm-runtime.json +2099 -0
- faden_cli/bundle/shared/grafana/provisioning/dashboards/dashboard.yml +10 -0
- faden_cli/bundle/shared/grafana/provisioning/dashboards/json/faden-overview.json +211 -0
- faden_cli/bundle/shared/grafana/provisioning/datasources/ds.yaml +9 -0
- faden_cli/bundle/shared/grafana/provisioning/datasources/prometheus.yaml +15 -0
- faden_cli/bundle/shared/initdb/01-init.sql +32 -0
- faden_cli/bundle/shared/loki/local-config.yaml +32 -0
- faden_cli/bundle/shared/nginx/locations.conf +245 -0
- faden_cli/bundle/shared/nginx/maintenance.html +239 -0
- faden_cli/bundle/shared/nginx/nginx-tls.conf +79 -0
- faden_cli/bundle/shared/nginx/nginx.conf +44 -0
- faden_cli/bundle/shared/nginx/rate-limits.conf +42 -0
- faden_cli/bundle/shared/nginx/security-headers.conf +22 -0
- faden_cli/bundle/shared/nginx/select-config.sh +37 -0
- faden_cli/bundle/shared/prometheus/prometheus.yml +40 -0
- faden_cli/bundle/shared/rabbitmq/definitions.json.example +37 -0
- faden_cli/bundle/shared/tls/README.md +30 -0
- faden_cli/cli.py +158 -0
- faden_cli/commands/__init__.py +1 -0
- faden_cli/commands/admin.py +161 -0
- faden_cli/commands/backup.py +159 -0
- faden_cli/commands/config.py +146 -0
- faden_cli/commands/deploy.py +949 -0
- faden_cli/commands/dev/__init__.py +1 -0
- faden_cli/commands/dev/dev_doctor.py +46 -0
- faden_cli/commands/dev/dev_down.py +241 -0
- faden_cli/commands/dev/dev_group.py +24 -0
- faden_cli/commands/dev/dev_init.py +710 -0
- faden_cli/commands/dev/dev_pull.py +297 -0
- faden_cli/commands/dev/dev_status.py +151 -0
- faden_cli/commands/dev/dev_up.py +1392 -0
- faden_cli/commands/doctor.py +225 -0
- faden_cli/commands/down.py +75 -0
- faden_cli/commands/logs_cmd.py +41 -0
- faden_cli/commands/maintenance.py +74 -0
- faden_cli/commands/module.py +113 -0
- faden_cli/commands/observe.py +95 -0
- faden_cli/commands/ports.py +91 -0
- faden_cli/commands/rebuild.py +158 -0
- faden_cli/commands/restore.py +139 -0
- faden_cli/commands/runtime_images.py +174 -0
- faden_cli/commands/status.py +71 -0
- faden_cli/commands/tls.py +722 -0
- faden_cli/commands/tune.py +37 -0
- faden_cli/commands/up.py +64 -0
- faden_cli/commands/upgrade.py +470 -0
- faden_cli/commands/version.py +78 -0
- faden_cli/core/__init__.py +1 -0
- faden_cli/core/api_client.py +77 -0
- faden_cli/core/backup.py +717 -0
- faden_cli/core/bootstrap.py +291 -0
- faden_cli/core/bundle.py +110 -0
- faden_cli/core/clickhouse.py +61 -0
- faden_cli/core/compose.py +484 -0
- faden_cli/core/console.py +106 -0
- faden_cli/core/detect.py +580 -0
- faden_cli/core/dev_modules.py +149 -0
- faden_cli/core/docker_env.py +147 -0
- faden_cli/core/edge.py +94 -0
- faden_cli/core/env_gen.py +598 -0
- faden_cli/core/git.py +219 -0
- faden_cli/core/install.py +288 -0
- faden_cli/core/installation.py +186 -0
- faden_cli/core/local_node.py +719 -0
- faden_cli/core/maintenance.py +82 -0
- faden_cli/core/private_files.py +133 -0
- faden_cli/core/registry.py +574 -0
- faden_cli/core/release_feed.py +342 -0
- faden_cli/core/rmq.py +135 -0
- faden_cli/core/runtime_images.py +309 -0
- faden_cli/core/schedule.py +278 -0
- faden_cli/core/settings.py +159 -0
- faden_cli/core/sysinfo.py +303 -0
- faden_cli/core/tls.py +790 -0
- faden_cli/core/tune.py +154 -0
- faden_cli/core/update_check.py +254 -0
- faden_cli/core/workspace.py +155 -0
- faden_cli/templates/env.j2 +33 -0
- faden_cli/tui/__init__.py +1 -0
- faden_cli/tui/widgets/__init__.py +1 -0
- faden_cli/tui/wizard/__init__.py +1 -0
- fadenstack-0.4.2.dist-info/METADATA +304 -0
- fadenstack-0.4.2.dist-info/RECORD +99 -0
- fadenstack-0.4.2.dist-info/WHEEL +4 -0
- fadenstack-0.4.2.dist-info/entry_points.txt +3 -0
- fadenstack-0.4.2.dist-info/licenses/LICENSE +187 -0
- fadenstack-0.4.2.dist-info/licenses/NOTICE +15 -0
|
@@ -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,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
|
+
}
|