Self-Hosting A Migas Server¶
Run migas-server on your own host — bare metal or a VM — without Docker
Compose. You provide PostgreSQL and Redis; you install with
uv, create the schema with Alembic, and run the
server under systemd behind a reverse proxy.
Note
For a quick local spin-up, use the Docker Compose guide instead.
Contents¶
- Architecture & prerequisites
- Install the application
- Provision PostgreSQL
- Provision Redis
- Initialize the database schema
- Run the server
- Run under systemd
- Reverse proxy & TLS
- Set up admin access
- Upgrades
1. Architecture & prerequisites¶
migas-server is an ASGI (FastAPI) app. A self-hosted deployment has three
parts you provide:
| Component | Role | You provide |
|---|---|---|
| PostgreSQL | Persists projects, users, telemetry crumbs, and auth tokens | A reachable database + role |
| Redis (≥ 6) | Rate limiting and GitHub API caching | A reachable Redis instance |
| migas-server | The ASGI app, run with uvicorn |
This repository + Python |
It can also use MaxMind-format geolocation databases (see Configuration).
Host requirements:
- Python 3.10+ (3.13 is what the official image ships; any 3.10+ works)
uvfor dependency management- Network access from the host to your Postgres and Redis
- A reverse proxy (e.g. nginx) if you want TLS termination — recommended
2. Install the application¶
git clone https://github.com/nipreps/migas-server.git
cd migas-server
# Install runtime dependencies + Alembic (the `prod` extra pulls in `migrations`).
uv sync --extra prod
Optional extras:
--extra speedups— addsaiohttp[speedups]andredis[hiredis](C acceleration). Recommended for production.--extra prod— already includes themigrationsextra (Alembic), required for schema setup and upgrades.
uv sync creates a project virtual environment at .venv/. The migas-server
console script and alembic are available via uv run … (or by activating the
venv).
3. Provision PostgreSQL¶
Create a database and a role the server will use:
CREATE ROLE migas WITH LOGIN PASSWORD 'change-me';
CREATE DATABASE migas OWNER migas;
Point the server at it with DATABASE_URL (required for any non-local database).
See Configuration → Database for the connection
variables and an important caveat about remote hosts.
4. Provision Redis¶
Redis is required, for rate limiting and GitHub-project caching. Point the server
at it with MIGAS_REDIS_URI (or REDIS_TLS_URL for a rediss:// endpoint); see
Configuration → Redis.
5. Initialize the database schema¶
Use Alembic migrations. This is the version-tracked way to create and update the schema. From the repo root, with your database variables set (see Configuration):
uv run alembic upgrade head
Alembic reads the same variables as the server (via alembic/env.py) and loads a
.env file automatically. To point at a specific env file:
MIGAS_ENV_FILE=/etc/migas/migas.env uv run alembic upgrade head
This builds the migas schema and tables (projects, users, crumbs,
auth, geoloc). Re-running it after a git pull applies new migrations (see
§10).
Or init.sql. The repo ships
deploy/docker/init.sql, which creates the same
core tables in one shot:
psql "postgresql://migas:change-me@localhost:5432/migas" -f deploy/docker/init.sql
Warning
init.sql is intended for local development. It seeds a master project
and two publicly known test tokens. If you use it for anything real, delete
those seeded rows immediately and bootstrap your own master token
(§9). It also is not revision-aware — Alembic won't
know what state the database is in. Prefer alembic upgrade head.
6. Run the server¶
Launch the server with the migas-server console script, a thin wrapper over
uvicorn:
uv run migas-server --host 0.0.0.0 --port 8080 --proxy-headers
Flags:
| Flag | Default | Notes |
|---|---|---|
--host |
0.0.0.0 |
Bind address. Bind to 127.0.0.1 if a reverse proxy is in front. |
--port |
8000 |
Listen port. |
--proxy-headers |
off | Enable when behind a reverse proxy so client IPs/scheme are read from X-Forwarded-*. |
--workers |
1 |
Worker processes. |
--headers |
— | Extra Name:Value response headers. |
Note
Run it behind a reverse proxy (§8) rather than exposing uvicorn to the internet directly.
Check it responds. A 401 here is expected — the endpoint needs a token — and
confirms the server is up:
curl -i http://127.0.0.1:8080/api/auth/projects
7. Run under systemd¶
Create an env file at /etc/migas/migas.env with the variables from
Configuration, e.g.:
DATABASE_URL=postgresql+asyncpg://migas:change-me@localhost:5432/migas
MIGAS_REDIS_URI=redis://:password@localhost:6379
MIGAS_GEOLOC=1
MIGAS_GEOLOC_DIR=/path/to/geodb
Create a service unit at /etc/systemd/system/migas-server.service:
[Unit]
Description=migas telemetry server
After=network-online.target postgresql.service redis.service
Wants=network-online.target
[Service]
Type=simple
User=migas
Group=migas
WorkingDirectory=/opt/migas-server
EnvironmentFile=/etc/migas/migas.env
ExecStart=/usr/bin/uv run migas-server --host 127.0.0.1 --port 8080 --proxy-headers
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Adjust WorkingDirectory, User, and the path to uv (which uv) for your
host. Then:
sudo systemctl daemon-reload
sudo systemctl enable --now migas-server
sudo systemctl status migas-server
journalctl -u migas-server -f
8. Reverse proxy & TLS¶
Terminate TLS at a reverse proxy and forward to uvicorn on 127.0.0.1. Minimal
nginx config:
server {
listen 443 ssl;
server_name migas.example.org;
ssl_certificate /etc/letsencrypt/live/migas.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/migas.example.org/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
With --proxy-headers, uvicorn honors the X-Forwarded-* headers above. Only
forward them from a proxy you trust.
9. Set up admin access¶
A fresh database has no admin credential. Bootstrap the master token by running the bootstrap script from the repo root, with the server's environment:
uv run python scripts/bootstrap_admin_token.py
# or with an explicit env file:
MIGAS_ENV_FILE=/etc/migas/migas.env uv run python scripts/bootstrap_admin_token.py
Save the printed token. With it you can register projects and issue scoped tokens — see Administration for the token model and the full admin API.
10. Upgrades¶
To update a running instance:
cd /opt/migas-server
git pull
uv sync --extra prod # update dependencies
uv run alembic upgrade head # apply any new migrations
sudo systemctl restart migas-server
Always run alembic upgrade head after pulling; releases may add migrations.
Check the CHANGELOG before big version jumps.