<@ULVA73B9P> validate my prefect server installation commands and correct me if anything important b...
s
@Marvin validate my prefect server installation commands and correct me if anything important being missed pip install -U prefect mkdir -p /home/ubuntu/.prefect sudo apt update sudo apt install postgresql postgresql-contrib sudo -u postgres psql CREATE DATABASE prefect; CREATE USER prefect WITH PASSWORD 'prefectpassword'; GRANT ALL PRIVILEGES ON DATABASE prefect TO prefect; ----------------------------------------------------- [Unit] Description=Prefect Server After=network-online.target postgresql.service Wants=network-online.target [Service] Type=simple User=root WorkingDirectory=/home/ubuntu/prefect Environment="PREFECT_HOME=/home/ubuntu/.prefect" Environment="PREFECT_SERVER_API_HOST=x.x.x.x" Environment="PREFECT_SERVER_API_PORT=4200" Environment="PREFECT_SERVER_API_KEEPALIVE_TIMEOUT=60" Environment="PREFECT_SERVER_LOGGING_LEVEL=DEBUG" Environment="PREFECT_API_DATABASE_CONNECTION_URL=postgresql+asyncpg://prefect:prefectpassword@127.0.0.1:5432/prefect" Environment="PREFECT_SERVER_API_AUTH_STRING=xxx:xxxx" ExecStart=/usr/local/bin/prefect server start --host 0.0.0.0 --port 4200 --keep-alive-timeout 60 Restart=on-failure RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target ----------------------------------------------------- sudo systemctl daemon-reload sudo systemctl restart prefect-server sudo systemctl status prefect-server
m
thought for 99.5 seconds
A few important corrections: Your DB URL line has invalid angle brackets Use:
Copy code
Environment="PREFECT_API_DATABASE_CONNECTION_URL=<postgresql+asyncpg://prefect:prefectpassword@127.0.0.1:5432/prefect>"
not:
Copy code
<postgresql+asyncpg://...>
You’re missing database migrations Before first start, run:
Copy code
bash
prefect server database upgrade -y
Without this, the server may start against an uninitialized DB.
PREFECT_SERVER_API_AUTH_STRING
is valid in Prefect 3.x
That setting is supported for basic auth, in
user:password
form. Don’t set host twice unless you mean to You have both: -
Environment="PREFECT_SERVER_API_HOST=x.x.x.x"
-
ExecStart=... --host 0.0.0.0
The CLI flag wins. Usually just keep:
Copy code
bash
--host 0.0.0.0
and remove
PREFECT_SERVER_API_HOST
. Running as
root
is not recommended
Use a dedicated service user if possible. Your service file name/creation step is missing You showed the unit contents, but not where it gets written. Typically:
Copy code
bash
sudo nano /etc/systemd/system/prefect-server.service
or write it with
tee
. Here’s a corrected version of your setup. Install + DB setup
Copy code
bash
pip install -U prefect

mkdir -p /home/ubuntu/.prefect

sudo apt update
sudo apt install -y postgresql postgresql-contrib

sudo -u postgres psql
Then in psql:
Copy code
sql
CREATE DATABASE prefect;
CREATE USER prefect WITH PASSWORD 'prefectpassword';
GRANT ALL PRIVILEGES ON DATABASE prefect TO prefect;
\q
Run migrations once
Copy code
bash
prefect server database upgrade -y
Systemd unit Put this in `/etc/systemd/system/prefect-server.service`:
Copy code
ini
[Unit]
Description=Prefect Server
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu
Environment="PREFECT_HOME=/home/ubuntu/.prefect"
Environment="PREFECT_SERVER_API_PORT=4200"
Environment="PREFECT_SERVER_API_KEEPALIVE_TIMEOUT=60"
Environment="PREFECT_SERVER_LOGGING_LEVEL=DEBUG"
Environment="PREFECT_API_DATABASE_CONNECTION_URL=<postgresql+asyncpg://prefect:prefectpassword@127.0.0.1:5432/prefect>"
Environment="PREFECT_SERVER_API_AUTH_STRING=xxx:xxxx"

ExecStart=/usr/local/bin/prefect server start --host 0.0.0.0 --port 4200 --keep-alive-timeout 60

Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
Then:
Copy code
bash
sudo systemctl daemon-reload
sudo systemctl enable prefect-server
sudo systemctl restart prefect-server
sudo systemctl status prefect-server
Optional but recommended checks
Copy code
bash
journalctl -u prefect-server -f
A couple more production notes: - If
prefect
was installed in a venv,
/usr/local/bin/prefect
may be wrong; use
which prefect
- Storing DB password and auth string directly in the unit file works, but an environment file is safer - If this server is internet-facing, put it behind TLS/reverse proxy; basic auth alone is not enough Verified CLI:
Copy code
bash
prefect server start --help
Useful docs: - Prefect docs - Server CLI guide If you want, I can also rewrite this into a best-practice Ubuntu systemd setup with: - dedicated
prefect
user -
/etc/prefect/server.env
- automatic startup - reverse proxy example with Nginx
s
@Marvingive best-practice Ubuntu systemd setup and possible way to protect it beyond basic auth
m
thought for 137.8 seconds
Yes — here’s a best-practice Ubuntu + systemd setup for a self-hosted Prefect 3 server, plus better protection than basic auth. Recommended architecture - Run Prefect on
127.0.0.1:4200
only - Put Nginx in front of it for: - TLS/HTTPS - optional IP allowlisting - rate limiting - optional SSO / OAuth2 / OIDC via auth proxy - Use PostgreSQL for the DB - Run Prefect as a dedicated non-root
prefect
user - Store secrets in
/etc/prefect/server.env
with restricted permissions Important note: Prefect server itself is not where you should terminate TLS. Best practice is a reverse proxy in front of it. --- 1) Install system packages
Copy code
bash
sudo apt update
sudo apt install -y python3-venv python3-pip postgresql postgresql-contrib nginx
If you want Let’s Encrypt later:
Copy code
bash
sudo apt install -y certbot python3-certbot-nginx
--- 2) Create a dedicated service user
Copy code
bash
sudo useradd --system --create-home --home-dir /var/lib/prefect --shell /usr/sbin/nologin prefect
Create directories:
Copy code
bash
sudo mkdir -p /opt/prefect
sudo mkdir -p /etc/prefect
sudo mkdir -p /var/lib/prefect/.prefect
sudo chown -R prefect:prefect /var/lib/prefect
sudo chmod 700 /var/lib/prefect/.prefect
--- 3) Create a Python virtual environment and install Prefect
Copy code
bash
sudo python3 -m venv /opt/prefect/venv
sudo /opt/prefect/venv/bin/pip install --upgrade pip
sudo /opt/prefect/venv/bin/pip install -U prefect
Check the binary:
Copy code
bash
/opt/prefect/venv/bin/prefect version
--- 4) Configure PostgreSQL Open psql:
Copy code
bash
sudo -u postgres psql
Run:
Copy code
sql
CREATE USER prefect WITH PASSWORD 'change_this_to_a_strong_password';
CREATE DATABASE prefect OWNER prefect;
GRANT ALL PRIVILEGES ON DATABASE prefect TO prefect;
\q
--- 5) Create the Prefect environment file Create `/etc/prefect/server.env`:
Copy code
bash
sudo tee /etc/prefect/server.env > /dev/null <<'EOF'
PREFECT_HOME=/var/lib/prefect/.prefect

# Bind Prefect only to localhost; Nginx will expose it publicly
PREFECT_SERVER_API_HOST=127.0.0.1
PREFECT_SERVER_API_PORT=4200
PREFECT_SERVER_API_KEEPALIVE_TIMEOUT=60
PREFECT_SERVER_LOGGING_LEVEL=INFO

# PostgreSQL
PREFECT_API_DATABASE_CONNECTION_URL=<postgresql+asyncpg://prefect:change_this_to_a_strong_password@127.0.0.1:5432/prefect>

# Optional basic auth
PREFECT_SERVER_API_AUTH_STRING=admin:change_this_too

# Recommended security settings
PREFECT_SERVER_API_CSRF_PROTECTION_ENABLED=true

# Restrict browser origins to your actual URL
PREFECT_SERVER_API_CORS_ALLOWED_ORIGINS=["<https://prefect.example.com>"]

# Make the UI call the external URL, not localhost
PREFECT_UI_API_URL=<https://prefect.example.com/api>
EOF
Then lock it down:
Copy code
bash
sudo chown root:prefect /etc/prefect/server.env
sudo chmod 640 /etc/prefect/server.env
Notes - Use a real hostname in
PREFECT_UI_API_URL
- The database URL must use
postgresql+asyncpg://
-
PREFECT_SERVER_API_AUTH_STRING
is valid, but don’t rely on it alone for internet exposure --- 6) Run database migrations once
Copy code
bash
sudo env $(cat /etc/prefect/server.env | xargs) /opt/prefect/venv/bin/prefect server database upgrade -y
If your env file ever contains spaces/special chars, a safer pattern is:
Copy code
bash
sudo bash -c 'set -a; source /etc/prefect/server.env; set +a; /opt/prefect/venv/bin/prefect server database upgrade -y'
--- 7) Create the systemd service Create `/etc/systemd/system/prefect-server.service`: ```ini [Unit] Description=Prefect Server After=network-online.target postgresql.service Wants=network-online.target [Service] Type=simple User=prefect Group=prefect WorkingDirectory=/var/lib/prefect EnvironmentFile=/etc/prefect/server.env ExecStart=/opt/prefect/venv/bin/prefect server start --host 127.0.0.1 --port 4200 --keep-alive-timeout 60 Restart=on-failure RestartSec=10 StandardOutput=journal StandardError=journal # Basic hardening NoNewPrivileges=true PrivateTmp=true ProtectSystem=full ProtectHome=true
ReadWritePaths=/var/lib/prefect [Install] WantedBy=multi-user.target
Copy code
Then enable/start:
```bash
sudo systemctl daemon-reload
sudo systemctl enable prefect-server
sudo systemctl start prefect-server
sudo systemctl status prefect-server
Logs:
Copy code
bash
sudo journalctl -u prefect-server -f
--- 8) Configure Nginx as a reverse proxy Create `/etc/nginx/sites-available/prefect`:
Copy code
nginx
server {
    listen 80;
    server_name <http://prefect.example.com|prefect.example.com>;

    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 X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_read_timeout 90;
        proxy_connect_timeout 90;
        proxy_send_timeout 90;
    }
}
Enable it:
Copy code
bash
sudo ln -s /etc/nginx/sites-available/prefect /etc/nginx/sites-enabled/prefect
sudo nginx -t
sudo systemctl reload nginx
--- 9) Add HTTPS If DNS already points to this box:
Copy code
bash
sudo certbot --nginx -d <http://prefect.example.com|prefect.example.com>
That gives you TLS. This is the minimum for safe exposure. --- How to protect it beyond basic auth Best options, in order of strength: Option A: Restrict access at the network layer If only your team or internal workers need access, do this first: - bind Prefect to localhost - expose only through VPN, private subnet, bastion, or corporate network - optionally allowlist IPs in Nginx Example Nginx allowlist:
Copy code
nginx
location / {
    allow 203.0.113.10;
    allow 203.0.113.11;
    deny all;

    proxy_pass <http://127.0.0.1:4200;>
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}
This is much stronger than basic auth alone for many self-hosted setups. --- Option B: Put SSO/OIDC in front with an auth proxy Good choices: -
oauth2-proxy
- Nginx +
auth_request
- Cloudflare Access - Tailscale Funnel / Tailscale access controls - your cloud LB with OIDC auth This is the most common “real” upgrade beyond basic auth. Typical pattern: - user hits
<https://prefect.example.com>
- auth proxy forces login with Google, Okta, Azure AD, GitHub, etc. - only authenticated users can reach Prefect - Prefect itself remains on localhost This is usually better than exposing Prefect directly with just
PREFECT_SERVER_API_AUTH_STRING
. --- Option C: Keep basic auth, but only behind TLS + rate limiting If you must use basic auth: - enable HTTPS - add rate limiting in Nginx - use strong random passwords - rotate credentials - consider IP allowlist too Example rate limiting:
Copy code
nginx
limit_req_zone $binary_remote_addr zone=prefect_limit:10m rate=10r/s;

server {
    listen 443 ssl http2;
    server_name <http://prefect.example.com|prefect.example.com>;

    location / {
        limit_req zone=prefect_limit burst=20 nodelay;

        proxy_pass <http://127.0.0.1:4200;>
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
--- Option D: Put it behind a private ingress only If flows/workers are inside your VPC: - no public DNS - internal load balancer only - security groups/firewall rules - VPN for human access For many teams, this is the cleanest secure deployment. --- Recommended security baseline I’d suggest this baseline: 1. PostgreSQL backend 2. Dedicated
prefect
Linux user
3. Virtualenv install in
/opt/prefect/venv
4. Prefect bound to
127.0.0.1
only
5. Nginx reverse proxy with HTTPS 6. CSRF enabled 7. Restricted CORS origins 8. Either - VPN/private network access, or - SSO/OIDC auth proxy 9. Optional basic auth as an extra layer, not the only one --- Client/worker configuration Your workers/clients should point to: ```bash
export PREFECT_API_URL=https://prefect.example.com/api
Copy code
If you keep server basic auth enabled:
```bash
export PREFECT_API_AUTH_STRING=admin:change_this_too
--- Things I would change from many “quick install” examples - don’t run as
root
- don’t expose
0.0.0.0:4200
directly unless you must - don’t skip TLS - don’t keep secrets in a world-readable unit file - don’t rely only on basic auth for public internet exposure --- Useful docs: - Prefect docs - Security settings - Self-hosted Prefect If you want, I can next give you either: 1. a copy-paste complete setup for
<http://prefect.example.com|prefect.example.com>
with Nginx + Let’s Encrypt, or 2. an SSO-protected setup using
oauth2-proxy
in front of Prefect.