<@ULVA73B9P> how to install nginx to secure self h...
# ask-marvin
m
@Marvin how to install nginx to secure self hosted prefect server . all so need a ui with authentication password . i am using ec2 instance with ubuntu
m
thought for 311.5 seconds
Great question — you can put your self-hosted Prefect Server behind NGINX on Ubuntu, enable HTTPS, and add a password for the UI. Below is a secure, working pattern for Prefect 3.x on a single EC2 host. Important security note: - Prefect Server has no built-in auth. If you put HTTP Basic Auth in front of the API, your workers/CLI won’t be able to talk to the server. The recommended pattern is: - Protect the UI with Basic Auth on a dedicated hostname (e.g., ui.your-domain.com). - Expose the API on a separate hostname (e.g., api.your-domain.com) without Basic Auth so workers/CLI can connect. Optionally restrict the API by IP allowlist or run workers locally and point them to localhost. - The UI needs to know where the API lives; we’ll set
PREFECT_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
Copy code
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
Copy code
# 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
Copy code
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
Copy code
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:
Copy code
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
Copy code
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 ```
export PREFECT_SERVER_UI_API_URL="https://api.your-domain.com/api" export PREFECT_UI_URL="https://ui.your-domain.com" # If you’re running CLI/workers on the same machine: export PREFECT_API_URL="http://127.0.0.1:4200/api" # Start server (with UI) prefect server start --host 127.0.0.1 --port 4200 --ui
Copy code
If 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"
Copy code
- 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.