Series: Lập trình Raspberry Pi & Ứng dụng thực tế Phần 3 — Python “build app thật” Bài 17: Chạy FastAPI như service (systemd) + reverse proxy Nginx + HTTPS nội bộ
1) Mục tiêu bài học
Sau bài này bạn sẽ:
- Chạy FastAPI (uvicorn) như systemd service: auto-start, restart, logs.
- Dùng Nginx reverse proxy để truy cập bằng port 80 (hoặc 443).
- (Tuỳ chọn) Bật HTTPS nội bộ bằng self-signed cert (dùng trong LAN).
2) Chuẩn bị
- Project đã chạy được uvicorn src.api:app (Bài 13/16)
- Bạn có user chạy app (ví dụ developer)
- Port dự kiến:
- Uvicorn: 127.0.0.1:8000
- Nginx public: 80 (và 443 nếu bật TLS)
Cài Nginx:
sudo apt update
sudo apt -y install nginx
3) Systemd service cho FastAPI
Tạo file:
sudo nano /etc/systemd/system/iotlabs-api.service
Dán cấu hình (đổi đường dẫn cho đúng user/thư mục của bạn):
[Unit]
Description=IoTLabs FastAPI (Pi Dashboard/API)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=developer
WorkingDirectory=/home/developer/apps/iotlabs-py-agent
# dùng uvicorn trong venv
ExecStart=/home/developer/apps/iotlabs-py-agent/.venv/bin/uvicorn src.api:app \
--host 127.0.0.1 --port 8000
Restart=always
RestartSec=3
# log ra journald
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
Enable + start:
sudo systemctl daemon-reload
sudo systemctl enable iotlabs-api
sudo systemctl start iotlabs-api
sudo systemctl status iotlabs-api --no-pager
Xem log:
journalctl -u iotlabs-api -n 80 --no-pager
journalctl -u iotlabs-api -f
4) Nginx reverse proxy (port 80 → 8000)
Tạo config site:
sudo nano /etc/nginx/sites-available/iotlabs-api
Dán:
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
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;
}
}
Enable site:
sudo ln -s /etc/nginx/sites-available/iotlabs-api /etc/nginx/sites-enabled/iotlabs-api
sudo nginx -t
sudo systemctl restart nginx
Mở browser:
- http://<IP_CUA_PI>/
5) (Tuỳ chọn) HTTPS nội bộ bằng self-signed cert
Tạo cert (1 năm):
sudo mkdir -p /etc/nginx/certs
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/certs/iotlabs.key \
-out /etc/nginx/certs/iotlabs.crt \
-subj "/CN=iotlabs-pi.local"
Sửa config Nginx:
sudo nano /etc/nginx/sites-available/iotlabs-api
Thay bằng:
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name _;
ssl_certificate /etc/nginx/certs/iotlabs.crt;
ssl_certificate_key /etc/nginx/certs/iotlabs.key;
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;
}
}
Test & restart:
sudo nginx -t
sudo systemctl restart nginx
Truy cập:
- https://<IP_CUA_PI>/ hoặc https://iotlabs-pi.local/ (nếu mDNS ok)
Trình duyệt sẽ cảnh báo vì self-signed — bình thường trong LAN. Muốn “xịn” hơn: dùng CA nội bộ hoặc Let’s Encrypt (khi có domain public).
6) Firewall (UFW) gợi ý
Nếu bạn bật UFW:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status
7) Checklist debug nhanh
- systemctl status iotlabs-api fail:
- sai đường dẫn venv …/.venv/bin/uvicorn
- sai WorkingDirectory
- Nginx 502 Bad Gateway:
- uvicorn chưa chạy hoặc bind sai host/port
- check: curl -s http://127.0.0.1:8000/health
- Port 80 không vào được:
- UFW chưa mở
- service nginx chưa restart / config lỗi (nginx -t)


