-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathfastAPI
More file actions
457 lines (277 loc) · 11.6 KB
/
fastAPI
File metadata and controls
457 lines (277 loc) · 11.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
Final deployment method — oropendola_fastapi (step-by-step)
Target domain: api.oropendola.ai
Server: Hetzner CPX22 (Ubuntu 22.04)
Stack: Python 3.11 venv → Uvicorn → systemd → Nginx (reverse proxy) → Let’s Encrypt → Cloudflare (Full Strict).
User on server: deployuser
PREP: Preparation (do this before touching firewall)
Create Hetzner VM: CPX22, Ubuntu 22.04. Add your SSH public key during create.
From your workstation note your public IP (for UFW): curl ifconfig.me → save as YOUR_HOME_IP.
Ensure you have Cloudflare admin for oropendola.ai.
STEP 0 — SSH in and create deploy user
# connect as root
ssh root@SERVER_IP
# create user and copy your authorized key
adduser deployuser
usermod -aG sudo deployuser
mkdir -p /home/deployuser/.ssh
cp /root/.ssh/authorized_keys /home/deployuser/.ssh/
chown -R deployuser:deployuser /home/deployuser/.ssh
chmod 700 /home/deployuser/.ssh
chmod 600 /home/deployuser/.ssh/authorized_keys
Test login as deployuser from your workstation:
ssh deployuser@SERVER_IP
Do not disable root SSH until deployuser is confirmed.
STEP 1 — Install base packages (run as root or via sudo)
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3.11 python3.11-venv python3-pip nginx ufw fail2ban git curl wget certbot python3-certbot-nginx
sudo timedatectl set-timezone Etc/UTC
STEP 2 — Safe baseline firewall (do this now to avoid lockout)
# Keep SSH open to your IP before enabling UFW
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from YOUR_HOME_IP to any port 22 proto tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
Important: Do not add Cloudflare-only rules yet. We add them later in a safe scripted step.
STEP 3 — App files & virtualenv (as deployuser)
sudo su - deployuser
mkdir -p ~/apps/oropendola_fastapi
cd ~/apps/oropendola_fastapi
python3.11 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install fastapi uvicorn[standard] httpx
Create app file /home/deployuser/apps/oropendola_fastapi/main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"app": "oropendola_fastapi"}
@app.get("/health")
def health():
return {"status": "ok"}
Quick test:
source ~/apps/oropendola_fastapi/venv/bin/activate
uvicorn main:app --host 127.0.0.1 --port 8000
# curl http://127.0.0.1:8000/health -> should return {"status":"ok"}
# ctrl-c to stop
STEP 4 — systemd service for autostart & restart
Create /etc/systemd/system/fastapi.service (run as root):
[Unit]
Description=FastAPI (uvicorn) for api.oropendola.ai
After=network.target
[Service]
User=deployuser
Group=www-data
WorkingDirectory=/home/deployuser/apps/oropendola_fastapi
Environment="PATH=/home/deployuser/apps/oropendola_fastapi/venv/bin"
ExecStart=/home/deployuser/apps/oropendola_fastapi/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --workers 1
Restart=always
RestartSec=3
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now fastapi
sudo systemctl status fastapi
# logs: sudo journalctl -u fastapi -f
Verify local reachability:
curl -I http://127.0.0.1:8000/health
STEP 5 — Nginx reverse proxy (HTTP -> proxy to Uvicorn)
Create /etc/nginx/sites-available/api.oropendola.ai:
server {
listen 80;
server_name api.oropendola.ai;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name api.oropendola.ai;
ssl_certificate /etc/letsencrypt/live/api.oropendola.ai/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.oropendola.ai/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Allow streaming/SSE
proxy_buffering off;
proxy_request_buffering off;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
location = /health {
proxy_pass http://127.0.0.1:8000/health;
}
}
Enable site:
sudo ln -s /etc/nginx/sites-available/api.oropendola.ai /etc/nginx/sites-enabled/
sudo nginx -t
# If test fails because cert missing, remove symlink, run certbot (next step), then re-add symlink.
STEP 6 — Get TLS certificate (Let’s Encrypt)
If Cloudflare is proxying (orange cloud), temporarily set it to DNS only (gray cloud) so Certbot can validate, or use DNS challenge. Easiest: set DNS to gray cloud for api while issuing cert.
Run:
sudo certbot --nginx -d api.oropendola.ai --redirect
# choose redirect -> yes
Verify cert:
sudo certbot certificates
curl -I https://api.oropendola.ai/health
When cert is present and Nginx OK, you may re-enable Cloudflare proxy (orange cloud) and set Cloudflare SSL to Full (strict).
STEP 7 — Cloudflare configuration (production)
In Cloudflare for oropendola.ai:
DNS: A record api → SERVER_IP, proxied (orange cloud) after cert issuance.
SSL/TLS: Mode Full (strict).
Firewall rule (WAF Skip for API):
Expression: (http.host eq "api.oropendola.ai")
Action: Skip
Skip components: All managed rules, All rate limiting rules, All custom rules, Super Bot Fight Mode (select the options).
Place rule: First.
(Optional) Authenticated Origin Pulls: enable and add Cloudflare origin CA cert and Nginx config if you want Cloudflare-only access.
(Optional) Rate limiting: configure Cloudflare rate limits for heavy abuse (but skip it for API if you plan to enforce in-app).
STEP 8 — Lock origin to Cloudflare IPs (safe scripted approach)
Important: Keep SSH open for your IP before running. Run as root.
Create /root/add_cloudflare_ufw.sh:
#!/bin/bash
set -e
# Replace YOUR_HOME_IP below with your workstation IP to keep SSH accessible.
YOUR_HOME_IP="YOUR_HOME_IP"
# Allow SSH from your IP
ufw allow from $YOUR_HOME_IP to any port 22 proto tcp
# Fetch CF ranges
CF4=$(curl -s https://www.cloudflare.com/ips-v4)
CF6=$(curl -s https://www.cloudflare.com/ips-v6)
# Add rules for HTTP/HTTPS from Cloudflare
for ip in $CF4; do
ufw allow from $ip to any port 80 proto tcp comment 'cloudflare-http'
ufw allow from $ip to any port 443 proto tcp comment 'cloudflare-https'
done
for ip in $CF6; do
ufw allow from $ip to any port 80 proto tcp comment 'cloudflare-http'
ufw allow from $ip to any port 443 proto tcp comment 'cloudflare-https'
done
# Now deny non-CF traffic to 80/443 (optional; do only if CF rules confirmed)
ufw deny 80/tcp
ufw deny 443/tcp
ufw reload
ufw status numbered
Make executable and run:
sudo chmod +x /root/add_cloudflare_ufw.sh
sudo /root/add_cloudflare_ufw.sh
If you lose SSH, use the Hetzner web console to regain access and revert UFW (sudo ufw disable) — see Troubleshooting below.
STEP 9 — Health checks, logs, and verification
From your workstation:
curl -I https://api.oropendola.ai/health
curl https://api.oropendola.ai/health
Server-side:
sudo journalctl -u fastapi -f # watch uvicorn logs
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log
If you get HTTP/2 200 and JSON from / and /health, deployment succeeded.
STEP 10 — Monitoring & alerting (quick)
Uptime monitor: Register https://api.oropendola.ai/health on UptimeRobot or Hetzner monitoring.
Resource metrics: Install Prometheus node exporter or use Hetzner Monitoring.
Alerting: Create alerts for CPU>70%, Memory>80%, Disk>75% and downtime.
STEP 11 — Backups & snapshots
Enable automated nightly snapshots in Hetzner (or cron rsync to remote storage).
Back up:
/home/deployuser/apps/oropendola_fastapi (app code and venv)
/etc/nginx/sites-available/api.oropendola.ai
/etc/systemd/system/fastapi.service
/etc/letsencrypt/ (or ensure cert repo)
Use rsync or borg to copy to a separate object store (S3/R2).
STEP 12 — CI/CD (basic GitHub Actions example)
Add .github/workflows/deploy.yml (simple push -> deploy via SSH):
name: Deploy to Hetzner
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Copy files to server
uses: appleboy/scp-action@master
with:
host: ${{ secrets.SERVER_IP }}
username: deployuser
key: ${{ secrets.DEPLOY_KEY }}
source: "./*"
target: "/home/deployuser/apps/oropendola_fastapi"
- name: Restart service
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_IP }}
username: deployuser
key: ${{ secrets.DEPLOY_KEY }}
script: |
source /home/deployuser/apps/oropendola_fastapi/venv/bin/activate
pip install -r /home/deployuser/apps/oropendola_fastapi/requirements.txt || true
sudo systemctl restart fastapi
Store DEPLOY_KEY (private key with access only to deployuser) and SERVER_IP in GitHub Secrets.
STEP 13 — Basic security & rate limiting inside FastAPI (sample)
Install aiolimiter or use Redis-based token bucket. Minimal per-process limiter example:
pip install aiolimiter
Add to main.py:
from fastapi import FastAPI, Request, HTTPException
from aiolimiter import AsyncLimiter
app = FastAPI()
# allow 5 requests per second per process — use Redis for real multi-process limits
limiter = AsyncLimiter(5, 1)
@app.middleware("http")
async def rate_limit(request: Request, call_next):
try:
async with limiter:
return await call_next(request)
except Exception:
raise HTTPException(status_code=429, detail="Too Many Requests")
For production use Redis-based solution (I can provide code).
STEP 14 — Hardening checklist (short)
Disable unused services.
Fail2ban running.
Regular security updates (unattended-upgrades).
Use strong SSH (keys only).
Rotate API keys and secrets (store in environment variables, not in repo).
Restrict /docs and admin endpoints behind Cloudflare Access or auth.
Use JWT or API keys for your endpoints.
TROUBLESHOOTING & ROLLBACK quick commands
Show FastAPI logs:
sudo journalctl -u fastapi -n 200
Restart FastAPI:
sudo systemctl restart fastapi
Check Nginx config:
sudo nginx -t
sudo systemctl restart nginx
Disable UFW (use Hetzner console if SSH locked):
sudo ufw disable
Revert Cloudflare DNS to gray cloud (DNS only) if issuing certs fails.
Remove Cloudflare-only UFW rules quickly:
# remove CF rules by number after listing:
sudo ufw status numbered
sudo ufw delete <num>
Appendix: Useful commands (copy/paste)
View status:
sudo systemctl status fastapi nginx
curl -I https://api.oropendola.ai/health
Restart stack:
sudo systemctl restart fastapi
sudo systemctl restart nginx
Update system:
sudo apt update && sudo apt upgrade -y
Backup app:
rsync -avz /home/deployuser/apps/oropendola_fastapi backup@backup.example:/backups/oropendola_fastapi-$(date +%F)
Final notes — cost & scaling
CPX22 is a good start. Monitor CPU/RAM. Move to CPX32 or dedicated vCPU when users/requests grow.
For heavy LLM inference or on-prem models, use GPU instances (separate hosts) or a cloud provider with GPU support.
Implement per-user quotas in DB + router to avoid 'unlimited plan' abuse.
If you want, I will now:
Produce the exact files (systemd unit, Nginx config, UFW script, Certbot steps) for direct copy/paste into the server, or
Provide the Redis-based rate limiter code and db schema for subscription/quota enforcement, or
Build a ready-to-run Git repository zip containing the app + deploy script.
Tell me which one to output now and I’ll deliver the files.