Skip to content

Deploy

STELLAR atlases are static-friendly: one uvicorn process serving the API on 127.0.0.1:18901, the compiled SPA shipped as static files, nginx (or any reverse proxy) terminating TLS and serving the bundle.

stellar deploy automates this

The CLI subcommand stellar deploy rsyncs the built assets to deploy.target_dir and prints the matching nginx + systemd snippets to stdout (the templates below are what it generates). See CLI → stellar deploy for the flags and exit codes; the recipes below are the manual equivalent if you'd rather do the steps yourself.


1. nginx vhost — /api proxied to uvicorn, SPA served at a subpath

Drop this in /etc/nginx/sites-available/my-atlas.conf and ln -s … /etc/nginx/sites-enabled/. Replace example.edu, my_atlas, and the target path with your own; the base_url inside stellar.yaml must match the SPA subpath (here /my_atlas/).

server {
    listen 80;
    listen [::]:80;
    server_name example.edu;

    # Redirect HTTP → HTTPS (certbot block below renders the TLS server).
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.edu;

    # Managed by certbot — see "HTTPS" below.
    ssl_certificate     /etc/letsencrypt/live/example.edu/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.edu/privkey.pem;
    include             /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam         /etc/letsencrypt/ssl-dhparams.pem;

    # ---- API: proxy to uvicorn ---------------------------------------
    location /my_atlas/api/ {
        proxy_pass         http://127.0.0.1:18901/api/;
        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;

        # SSE streaming for /copilot/ask — disable buffering and bump timeouts.
        proxy_buffering    off;
        proxy_cache        off;
        proxy_read_timeout 600s;
    }

    # ---- SPA: serve the pre-built bundle -----------------------------
    location /my_atlas/ {
        alias /var/www/html/my_atlas/;
        try_files $uri $uri/ /my_atlas/index.html;

        # Long cache for hashed assets.
        location ~* \.(?:js|css|woff2?|svg|png|jpg|webp|ico|arrow)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }

    # Reasonable defaults for the rest of the host.
    gzip on;
    gzip_types text/css application/javascript application/json image/svg+xml;
    client_max_body_size 16M;
}

Reload nginx:

sudo nginx -t && sudo systemctl reload nginx

2. systemd service unit — stellar serve

/etc/systemd/system/stellar-my_atlas.service:

[Unit]
Description=STELLAR atlas — my_atlas
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=stellar
Group=stellar
WorkingDirectory=/srv/atlases/my_atlas
EnvironmentFile=-/srv/atlases/my_atlas/.env
ExecStart=/srv/atlases/my_atlas/.venv/bin/stellar serve \
    --config /srv/atlases/my_atlas/stellar.yaml \
    --host 127.0.0.1 \
    --port 18901
Restart=on-failure
RestartSec=3
# Filesystem hardening.
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Enable + start:

sudo systemctl daemon-reload
sudo systemctl enable --now stellar-my_atlas.service
sudo systemctl status stellar-my_atlas.service
sudo journalctl -u stellar-my_atlas.service -f

The .env file (mode 600, owned by stellar:stellar) holds the secrets the copilot module needs:

ANTHROPIC_API_KEY=sk-ant-...
NCBI_API_KEY=...

3. HTTPS via certbot

One line, assuming python3-certbot-nginx is installed:

sudo certbot --nginx -d example.edu --agree-tos -m you@example.edu --redirect --non-interactive

certbot edits the nginx vhost in place to inject the ssl_certificate + ssl_certificate_key directives and the HTTP→HTTPS redirect (the template above shows the result). Auto-renewal is wired up via the certbot.timer systemd unit; check it with sudo systemctl status certbot.timer.


4. Rebuild + redeploy

A typical "I changed an h5ad" loop, manually, until stellar deploy ships:

# On the build host:
cd /srv/atlases/my_atlas
.venv/bin/stellar ingest --config stellar.yaml

# Rsync data + (optionally) the bundle to the web host:
rsync -avh --delete data/lance/    web-host:/srv/atlases/my_atlas/data/lance/
rsync -avh --delete data/duckdb/   web-host:/srv/atlases/my_atlas/data/duckdb/
rsync -avh --delete data/static/   web-host:/srv/atlases/my_atlas/data/static/
rsync -avh --delete data/parquet/  web-host:/srv/atlases/my_atlas/data/parquet/

# If you rebuilt the SPA (e.g. base_url change):
rsync -avh --delete .venv/lib/python3.12/site-packages/stellar/frontend/dist/ \
                    web-host:/var/www/html/my_atlas/

# Reload the API process on the web host:
ssh web-host 'sudo systemctl restart stellar-my_atlas.service'

Real-world examples

Public STELLAR atlases:

  • panad_atlas — hosted at https://swaruplab.bio.uci.edu/panad_atlas/.

If you deploy a public STELLAR atlas, open a PR adding it to this list.