Madushan Pathirana
09/09/2025, 2:54 PMMarvin
09/09/2025, 2:54 PMMarvin
09/09/2025, 3:00 PMPREFECT_SERVER_UI_API_URL to the API URL.
Links for reference:
- Prefect 3: Self-hosted Server
- Prefect 3: Security settings
Assumptions
- Ubuntu on EC2 with a security group allowing 80 (HTTP) and 443 (HTTPS).
- You have DNS records for:
- ui.your-domain.com → your EC2 public IP
- api.your-domain.com → your EC2 public IP
- You’ll run Prefect Server bound to 127.0.0.1:4200 and use RDS for Postgres.
1) Install NGINX and Certbot
sudo apt-get update
sudo apt-get install -y nginx apache2-utils
# Certbot (Let's Encrypt)
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
2) Create a Basic Auth file for the UI
# Create /etc/nginx/.htpasswd and add a user
sudo htpasswd -c /etc/nginx/.htpasswd admin
# (you’ll be prompted to set a password)
3) NGINX config (two virtual hosts: one for UI with Basic Auth, one for API without)
Create file: /etc/nginx/sites-available/prefect-ui
server {
listen 80;
server_name <http://ui.your-domain.com|ui.your-domain.com>;
# Increase if needed for file uploads
client_max_body_size 50m;
location / {
# Basic auth for UI only
auth_basic "Prefect UI";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass <http://127.0.0.1:4200;>
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# WebSocket/SSE headers (safe to include)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Create file: /etc/nginx/sites-available/prefect-api
server {
listen 80;
server_name <http://api.your-domain.com|api.your-domain.com>;
client_max_body_size 50m;
# NO Basic Auth on API so workers/CLI can connect
# Optional: Add IP allowlist to lock down API access further
# Example: allow your office IP only
# allow 203.0.113.10;
# deny all;
location / {
proxy_pass <http://127.0.0.1:4200;>
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Enable and test:
sudo ln -s /etc/nginx/sites-available/prefect-ui /etc/nginx/sites-enabled/prefect-ui
sudo ln -s /etc/nginx/sites-available/prefect-api /etc/nginx/sites-enabled/prefect-api
sudo nginx -t
sudo systemctl reload nginx
4) Get HTTPS certificates
sudo certbot --nginx -d <http://ui.your-domain.com|ui.your-domain.com> -d <http://api.your-domain.com|api.your-domain.com>
# Follow prompts; this will add SSL server blocks and reload NGINX
5) Start Prefect Server bound to localhost
- Prefect Server typically runs on 127.0.0.1:4200. We’ll:
- Tell the UI which public API URL to use: PREFECT_SERVER_UI_API_URL=<https://api.your-domain.com/api>
- Optionally set PREFECT_UI_URL=<https://ui.your-domain.com> for nice links in CLI output
- Point your workers/CLI (on the same box) to localhost so they don’t go through Basic Auth: PREFECT_API_URL=<http://127.0.0.1:4200/api>
Example: run server manually
```Marvin
09/09/2025, 3:00 PMIf you want it as a systemd service, I can provide a unit file template.
6) Point your workers/CLI at the API
- On this EC2 host (same machine), before starting workers or running CLI:
export PREFECT_API_URL="http://127.0.0.1:4200/api"
- If you run workers from another machine, use the public API instead:
export PREFECT_API_URL="https://api.your-domain.com/api"
```
Note: Don’t protect the API endpoint with Basic Auth unless you have a way for workers/CLI to send Authorization headers (Prefect does not add them automatically). Use IP allowlists or private networking instead if you need to restrict access.
7) Verify
- Open https://ui.your-domain.com — you should be prompted for the Basic Auth credentials you created.
- The UI should load and talk to the API at https://api.your-domain.com/api.
- Workers should be able to connect to the API (localhost or public) without authentication prompts.
Optional: Secure the API more
- If all workers run on the same EC2 host (your case), you can:
- Keep workers/CLI pointed at http://127.0.0.1:4200/api
- Restrict the public API by IP allowlist in NGINX, or even avoid exposing api.your-domain.com at all. In that case, the UI won’t work from the public internet (you could access via VPN or SSH tunnel when needed).
Would you like me to:
- Generate a systemd unit file for Prefect Server with your RDS Postgres connection?
- Provide an NGINX config that uses a single hostname (UI + API together), accepting the trade-offs?
If you share your actual domain names and whether you want the API publicly reachable, I’ll tailor the exact config.Bring your towel and join one of the fastest growing data communities. Welcome to our second-generation open source orchestration platform, a completely rethought approach to dataflow automation.
Powered by