- Python Version Requirements
>=3.11.9, !=3.12.0, !=3.12.1, !=3.12.2, <3.14
You can start Casdoor on port 9999 with Docker by running
docker run --detach --name casdoor \
--volume casdoor-data:/var/lib/mysql:z,rw \
--publish 9999:8000/tcp \
casbin/casdoor-all-in-oneYou can start PMM with Docker by running
docker run --detach --restart always \
--publish 8443:443 \
--volume pmm-data:/srv \
--name pmm-server \
percona/pmm-server:2For the purpose of development, you can run Nomad with
sudo nomad agent -node="pmm-server" -dev \
-bind 0.0.0.0 \
-network-interface='{{ GetDefaultInterfaces | attr "name" }}'You can start the Celery Worker with:
celery -A app.tasks.celery worker -l infoand the Celery Beart with:
celery -A app.tasks.celery beat -S sqlalchemy --loglevel=infoFor development purposes, you can also start Celery with SEP.
- Clone the repository and enter the cloned folder:
git clone https://github.com/percona/SEP.git
cd SEP- Create and activate a virtualenv with the required packages:
make venv
source venv/bin/activateTip
Use venv/bin/activate.fish if you're on a Fish shell.
- Create SEP's databases with
make migrate:
make migrate- Add your Redirect URL to the Casdoor application
In Casdoor's web interface, navigate to Identity > Applications > app-built-in (should be in this link) and scroll to Redirect URLs.
The Redirect URL you should add depends on how SEP is running (see Usage).
For example, if you're running SEP in your localhost with HTTP in port 8000, you shoul
add the URLs http://localhost:8000/oauth/callback and http://127.0.0.1:8000/oauth/callback.
- Create a .env file in the project root folder to store your secrets. See the secrets section of the README for more details.
SEP will read settings in the following order of priority:
- Environment variables
- .env file
- Secret files
- Settings file
By default, the .env file is expected to be .env and the settings file settings.yaml.
You can change that by using the environment variables ENV_FILE and SETTINGS_FILE.
Secret files are read from the directory named by SECRETS_DIR, which is unset by
default; when unset, no secret files are read. See the
secrets section for how to name them.
The settings.yaml has base settings that you can (but don't need to) change.
Some settings are app-specific and you might not need them for running another app. These are some, but not all, the possible settings you can have, per app:
| Name | App | Required | Default | settings.yaml (development) |
|---|---|---|---|---|
| BASE_URL | all | no | Built from the user's request | N/A |
| ALLOWED_HOSTS | all | yes | N/A | ["localhost", "127.0.0.1"] |
| ALLOW_CONCURRENT_SESSIONS | all | no | False | False |
| SSL_CAFILE | all | no | null | null |
| AUTH__PROVIDER__CASDOOR__ENDPOINT | all | yes | N/A | http://localhost:9999 |
| AUTH__PROVIDER__CASDOOR__FRONT_ENDPOINT | all | no | The same as AUTH__PROVIDER__CASDOOR__ENDPOINT |
//:9999 |
| AUTH__PROVIDER__CASDOOR__CERTIFICATE_PATH | all | no | null | null |
| AUTH__PROVIDER__CASDOOR__ORGANIZATION_NAME | all | no | built-in | N/A |
| AUTH__PROVIDER__CASDOOR__APPLICATION_NAME | all | no | app-built-in | sep-app |
| AUTH__PROVIDER__CASDOOR__ALLOWED_ISSUERS | all | no | [<ENDPOINT>] |
[http://localhost:9999, http://127.0.0.1:9999] |
| CELERY__BROKER_URL | all | no | N/A | filesystem:// |
| CELERY__BEAT_DBURI | all | no | N/A | sqlite:///schedule.db |
| LOGGING | all | no | WARNING | N/A |
| BACKEND_CORS_ORIGINS | all | no | [] | [http://localhost:8000, http://127.0.0.1:8000] |
| TASKS__NOMAD__ENDPOINT | tasks | yes | N/A | http://127.0.0.1:4646 |
| TASKS__NOMAD__SECURE | tasks | no | False | N/A |
| TASKS__NOMAD__VERIFY_SSL | tasks | no | False | True |
| TASKS__NOMAD__TIMEOUT | tasks | no | 10 | 10 |
| TASKS__NOMAD__MINIFY_PAYLOAD | tasks | no | True | True |
| TASKS__NOMAD__LOG_SOCKET_READ_TIMEOUT | tasks | no | 10 | 10 |
| TASKS__SYNC_LOCK_TTL | tasks | no | 300 | 300 |
| TASKS__ANONYMIZER__DEFAULT_ENTITIES | tasks | no | seven high-confidence entities (see below) | [] (anonymization disabled) |
| TASKS__EXECUTE_MODE | tasks | no | background | N/A |
| TASKS__DATABASE__ENGINE | tasks | no | sqlite | N/A |
| TASKS__DATABASE__NAME | tasks | no | tasks.db | N/A |
| TASKS__DATABASE__USER | tasks | no | N/A | N/A |
| TASKS__DATABASE__PASSWORD | tasks | no | N/A | N/A |
| TASKS__DATABASE__HOST | tasks | no | "" | "" |
| TASKS__DATABASE__PORT | tasks | no | N/A | N/A |
| SEP__INVENTORY_ENDPOINT | sep | yes | N/A | http://localhost:8000/api/inventory |
| SEP__TASKS_ENDPOINT | sep | yes | N/A | http://localhost:8000/api/tasks |
| SEP__OAUTH__REDIRECT_URI | sep | yes | N/A | /oauth/callback |
| SEP__OAUTH__POST_LOGIN_URI | sep | no | / | N/A |
| SEP__OAUTH__AUTH_LINK | sep | no | CasdoorOptions.SYNC_SDK.get_auth_link(REDIRECT_URI) | N/A |
| SEP__PROXY_HEADERS | sep | no | False | False |
| SEP__SYNC_REFRESH_TIME | sep | no | 5 | 5 |
| SEP__SESSION__COOKIE_NAME | sep | no | authToken | casdoorToken |
| SEP__SESSION__SECURE | sep | no | False | False |
| SEP__SESSION__HTTP_ONLY | sep | no | True | True |
| SEP__SESSION__SAME_SITE | sep | no | lax | lax |
| SEP__SESSION__MAX_AGE | sep | no | 3600 | 3600 |
| SEP__TEMPLATES_DIR | sep | no | templates | templates |
| SEP__STATIC_DIR | sep | no | static | N/A |
| SEP__SECURITY_HEADERS__CONTENT_SECURITY_POLICY_EXCLUDE_PATHS | sep | no | [] | [/api/docs, /api/inventory/docs, /api/tasks/docs] |
| ALERTING__SOURCE_SUFFIX | all | no | "" | ":dev" |
The active authentication provider is configured under AUTH__PROVIDER__<NAME>__*,
and exactly one provider may be configured. Casdoor is the built-in default,
shipped as the AUTH.PROVIDER.casdoor entry in settings.yaml
(AUTH__PROVIDER__CASDOOR__*). To use a different provider, replace that
casdoor entry in settings.yaml with your provider's entry — configuring a
second provider (e.g. adding AUTH__PROVIDER__CUSTOM__* on top of the shipped
casdoor block) is rejected at startup, since only one provider may be active.
An out-of-tree provider uses the CUSTOM name with AUTH__PROVIDER__CUSTOM__PROVIDER_CLASS
(a dotted import path to a BaseAuthProvider subclass) plus that class's own
fields. The legacy top-level CASDOOR__* variables are deprecated but still
honored (a startup warning is logged); migrate to AUTH__PROVIDER__CASDOOR__*.
Path settings (AUTH__PROVIDER__CASDOOR__CERTIFICATE_PATH, TEMPLATES_DIR, STATIC_DIR,
etc.) may have relative or absolute values. Relative paths will be resolved from the
project root folder.
SEP provides configurable session management through the SEP__SESSION section:
SEP:
SESSION:
COOKIE_NAME: casdoorToken
SECURE: False
HTTP_ONLY: True
SAME_SITE: lax
MAX_AGE: 3600COOKIE_NAME: Name of the session cookieSECURE: Whether the cookie should only be sent over HTTPSHTTP_ONLY: Whether the cookie should be accessible only via HTTP(S)SAME_SITE: SameSite attribute for the cookie (lax, strict, none)MAX_AGE: Maximum age of the session in seconds
SEP uses double-submit cookie CSRF protection. The same token can be reused for
multiple POST requests (e.g. from a React SPA), so you do not need to refetch
a token after each request. Send the token in the X-CSRF-TOKEN header or in
the form body as csrf-token. The token expires with the session (see
Session Management).
CSRF token lifetime is tied to the session MAX_AGE. Use the same
SEP__SESSION section to control how long the token stays valid:
SEP:
SESSION:
COOKIE_NAME: casdoorToken
MAX_AGE: 604800 # 7 days (seconds); CSRF token expires after the same periodSEP supports configurable security headers through the SEP__SECURITY_HEADERS section:
SEP:
SECURITY_HEADERS:
CONTENT_SECURITY_POLICY_EXCLUDE_PATHS:
- /api/docs
- /api/inventory/docs
- /api/tasks/docsThis allows you to exclude specific paths from Content Security Policy restrictions.
The anonymizer plugin can be configured through the TASKS__ANONYMIZER section:
TASKS:
ANONYMIZER:
DEFAULT_ENTITIES:
- CREDIT_CARD
- EMAIL_ADDRESS
- IBAN_CODE
- IP_ADDRESS
- PHONE_NUMBER
- US_SSN
- US_ITINThe DEFAULT_ENTITIES setting specifies which Personally Identifiable Information (PII) entities should be anonymized by default when a task does not set an explicit anonymize_mask. The shipped default: profile uses the seven high-confidence entities above (checksum-validated or strong-regex recognizers). The development: profile sets DEFAULT_ENTITIES to an empty list so local task logs stay readable and no Presidio/spaCy engine is constructed.
Profile overlays merge onto default:: a non-empty list prepends to the inherited list, and an empty list clears it. To narrow the set relative to default:, edit the default: block or use a runtime settings override (do not rely on a shorter non-empty profile list alone). Operators can restore any of the fourteen PIIEntity members through settings.yaml or a runtime settings override without a code change. Use "*" to select every supported entity.
SEP provides several sync-related configuration options:
SEP__SYNC_REFRESH_TIME: Browser refresh interval during sync operations (in seconds)TASKS__SYNC_LOCK_TTL: TaskHistory sync lock timeout (in seconds)
Additional Nomad configuration options are available:
TASKS__NOMAD__MINIFY_PAYLOAD: Whether to minify payloads before dispatchTASKS__NOMAD__LOG_SOCKET_READ_TIMEOUT: Socket read timeout for logs (in seconds)
Caution
*Do not store secrets in settings.yaml, as the file is shared in the git repository. See the secrets section of the README for more details.
SEP works with modular plugins. Plugins are FastAPI routers that will be added to the application
according to defined settings. Each plugin must have their own module in app.sep.plugins
with a router inside. The following plugins are configured by default:
PLUGINS:
- NAME: Schema Change
MODULE_NAME: alters
URI_PATH: /alters
CSS_CLASS: alters
- NAME: Inventory
MODULE_NAME: inventory
URI_PATH: /inventory
CSS_CLASS: inventory
- NAME: Archive
MODULE_NAME: archives
URI_PATH: /archives
CSS_CLASS: archive
- NAME: MySQL Backups
MODULE_NAME: mysql_backups
URI_PATH: /mysql_backups
CSS_CLASS: mysql_backups
- NAME: Checksums
MODULE_NAME: checksums
URI_PATH: /checksums
CSS_CLASS: checksums
- NAME: MongoDB Backups
MODULE_NAME: backup_mongo
URI_PATH: /backup_mongo
CSS_CLASS: backup_mongoEach plugin configuration includes:
NAME: Display name for the pluginMODULE_NAME: Python module name inapp.sep.pluginsURI_PATH: URL path where the plugin will be accessibleCSS_CLASS: CSS class for styling the plugin in the UI
SEP needs some keys and secrets to interact with Casdoor. They are:
AUTH__PROVIDER__CASDOOR__CLIENT_IDAUTH__PROVIDER__CASDOOR__CLIENT_SECRET
You can create a basic .env file template by running the following command in the project root folder:
echo -e "AUTH__PROVIDER__CASDOOR__CLIENT_ID=YOUR_CASDOOR_CLIENT_ID\nAUTH__PROVIDER__CASDOOR__CLIENT_SECRET=YOUR_CASDOOR_CLIENT_SECRET\n" > .envAny setting can instead be supplied as a file inside the directory SECRETS_DIR names,
which keeps the value out of the process environment. Name the file after the canonical
__-nested variable the setting already uses — SECRET_KEY,
SEP__DATABASE__PASSWORD, AUTH__PROVIDER__GRAFANA__SERVICE_ACCOUNT_TOKEN — and put
the value in its contents. /run/secrets is the conventional mount point:
mkdir -p /run/secrets
openssl rand -hex 32 > /run/secrets/SECRET_KEY
SECRETS_DIR=/run/secrets uvicorn app.main:appSurrounding whitespace is stripped, so a trailing newline is fine. A file only applies when nothing higher in the priority list supplies the same setting: an environment variable and a .env entry both still win over a file. A configured directory that does not exist logs a warning and is otherwise ignored, and a directory holding no matching file changes nothing.
- In a browser, open Casdoor's web interface and login (the default credentials are
admin:123). If you followed the Docker tutorial, it should be in http://localhost:9999.
- Navigate to Identity > Applications > app-built-in. If you followed the Docker tutorial, it should be in http://localhost:9999/applications/built-in/app-built-in
- Copy the app's Client ID and Client Secret and replace the respective
YOUR_CASDOOR_CLIENT_IDandYOUR_CASDOOR_CLIENT_SECRETin the .env file you created.
You can categorize settings by environments in settings.yaml:
default:
# defaults settings shared by all environments
development:
# development settings
production_docker:
# production settings for Docker deploymentTo switch environment, use the environment variable FASTAPI_ENV or add FASTAPI_ENV
to your .env file.
SEP supports multiple database engines for different components. Each component (SEP, Inventory, Tasks) can have its own database configuration:
SEP:
DATABASE:
ENGINE: sqlite # Database engine: sqlite, mysql, postgresql
USER: null
PASSWORD: null
HOST: "" # Database host (empty string for SQLite to avoid URL construction issues)
PORT: null
NAME: sep.db
INVENTORY:
DATABASE:
ENGINE: sqlite
USER: null
PASSWORD: null
HOST: ""
PORT: null
NAME: inventory.db
TASKS:
DATABASE:
ENGINE: sqlite
USER: null
PASSWORD: null
HOST: ""
PORT: null
NAME: tasks.dbSEP:
DATABASE:
ENGINE: mysql
USER: sep_user
PASSWORD: your_secure_password
HOST: localhost
PORT: 3306
NAME: sep_databaseSEP:
DATABASE:
ENGINE: postgresql
USER: sep_user
PASSWORD: your_secure_password
HOST: localhost
PORT: 5432
NAME: sep_databaseSupported database engines:
sqlite: SQLite database (default for development)mysql: MySQL/MariaDB databasepostgresql: PostgreSQL database
Note
For SQLite databases, set HOST to an empty string to avoid URL construction issues.
SEP features Inventory syncing with external services and APIs. You can choose the syncers you want to enable in the SEP.SYNCERS section of the configuration:
SEP:
# ...
SYNCERS:
- SYNCER: PMMSyncerSome syncers require additional configuration. PMM connection/auth config lives in the
top-level PMM section (not under the syncer entry) — PMMSyncer reads it directly:
PMM:
ENDPOINT: https://127.0.0.1:8443
VERIFY_SSL: falseThe PMM API key is a secret and should be set via an env var rather than settings.yaml:
PMM__API_KEY=<Your PMM API key>
Other syncers may take extra keyword arguments, defined globally through the
SEP.SYNCER_EXTRA_KWARGS config (SEP__SYNCER_EXTRA_KWARGS for env settings).
Sync Nodes and Services with PMM. Requires the PMM setting with ENDPOINT, API_KEY,
and optionally VERIFY_SSL, SSL_CAFILE, SSL_KEYFILE, and SSL_CERTFILE.
Sync MySQL/MariaDB inventory (schemas and tables). Optional configuration under each MySQLSyncer entry in SEP.SYNCERS:
IGNORE_SCHEMAS: List of schema names to skip during sync (defaults typically includesys,performance_schema,mysql,information_schema).DEFAULT_EXECUTOR_HOST: Nomad node name to use when the MySQL service host does not match any Nomad node. Set this when syncing RDS, DBaaS, or other remote MySQL instances: the sync payload runs on a Nomad client, so you must choose which client can reach the database. The value must match a node name (key) returned by/api/tasks/hosts/—not the node IP or address—otherwise task execution will fail. If unset, the first available Nomad host is used when there is no match.
Credentials are read on the Nomad client from ~/.my.cnf and ~/.mylogin.cnf. For each host the payload connects to, it looks up a login path by matching the RDS host: it tries a login path named like the host (e.g. host:port or host_port with colon replaced by underscore), then falls back to client. So for multiple RDS instances with different credentials, create a login path per host in ~/.mylogin.cnf (e.g. mysql_config_editor set --login-path=rds-a.region.rds.amazonaws.com:3306 --user=... --password --host=rds-a.region.rds.amazonaws.com --port=3306); the payload will use the matching path automatically.
Example for RDS/DBaaS:
SEP:
SYNCERS:
- SYNCER: MySQLSyncer
IGNORE_SCHEMAS:
- sys
- performance_schema
- mysql
- information_schema
DEFAULT_EXECUTOR_HOST: "ip-10-0-1-5.region.compute.internal" # Nomad node name from /api/tasks/hosts/ that can reach RDSTopology is a standalone, experimental Topology app that is shipped disabled
by default. Enable it like any other plugin by activating its module in
SEP.APPS:
SEP:
APPS:
- MODULE_NAME: topology
ENABLED: trueWhen enabled, the app draws an interactive React Flow graph of every MySQL
service the inventory knows about: replication chains (primary → replica with
GTID/IO/SQL state), dual-primary pairs, and Percona XtraDB Cluster groups. It
sources the MySQL host list from the Inventory service at request time.
Topology data is collected live, on demand - there is no persisted snapshot
in the database - by dispatching
sharded run-python tasks (capped at 8 shards) to executor hosts via the
Tasks API. Each shard runs the
topology.py payload, which
fans out per-host queries with a ThreadPoolExecutor and emits NDJSON events
to stdout. The API polls the dispatched tasks (GET /result), merges their
stdout into the graph, and the client polls that endpoint until every shard is
finished. Results are cached client-side with TanStack Query, so re-opening the
app is free until the user clicks Refresh.
Topology runtime limits live in
api_routes.py as module constants:
maximum shards is 8. Changing that value currently requires a code deploy; move
it into inventory_settings first if it needs per-deployment tuning.
The payload reuses the same credential rules as MySQLSyncer -
~/.my.cnf and ~/.mylogin.cnf on the executor, with per-host login paths
matched by host:port (or host_port) and a client fallback - so no
additional configuration is required if you already have MySQLSyncer running
against the same hosts.
SEP supports SSL/TLS configuration for secure communications. SSL settings can be configured at different levels:
SSL_CAFILE: /path/to/ca-certificate.pem # Global CA certificate fileSEP:
SSL_KEYFILE: /path/to/sep-key.pem
SSL_CERTFILE: /path/to/sep-cert.pem
INVENTORY:
SSL_KEYFILE: /path/to/inventory-key.pem
SSL_CERTFILE: /path/to/inventory-cert.pem
TASKS:
SSL_KEYFILE: /path/to/tasks-key.pem
SSL_CERTFILE: /path/to/tasks-cert.pemTASKS:
NOMAD:
SSL_CAFILE: /path/to/nomad-ca.pem
SSL_CERTFILE: /path/to/nomad-cert.pem
SSL_KEYFILE: /path/to/nomad-key.pemSSL certificate files should be in PEM format. Relative paths will be resolved from the project root folder.
- In a browser, open PMM's web interface and login (the default credentials are
admin:admin). If you followed the Docker tutorial, it should be in https://localhost.
- Navigate to Configuration > API keys. If you followed the Docker tutorial, it should be in https://localhost/graph/org/apikeys.
- Click the New API key button to create a new API key. Make sure the Role is set to Admin.
- Copy the generated API Key and replace the respective
YOUR_PMM_API_KEYin your .env file.
- Enter the project folder:
cd SEP- Activate your virtualenv:
source venv/bin/activate- Start SEP:
LOGGING=debug python3 -m app.mainSEP will be available in http://localhost:8000.
For development environments, you can start the Celery Worker and the Celery Beat with SEP by using the --start-celery flag:
LOGGING=debug python3 -m app.main --start-celeryYou can also run sep with Docker Compose by following these steps:
- Enter the project folder:
cd SEP- Generate the SSL certificates with the
generate_certs.shscript:
./generate_certs.sh- Generate Casdoor's init data with the
generate_casdoor_init_data.shscript:
./generate_casdoor_init_data.shYou can use the -p/--password argument to specify a password for the initial user:
./generate_casdoor_init_data.sh -p passwordIf no password is specified, a random one will be generated.
By now, your data folder should look something like this:
data
├── nomad.hcl
├── certs
│ ├── nomad
│ │ ├── global-client-nomad.pem
│ │ ├── global-server-nomad-key.pem
│ │ ├── global-client-nomad-key.pem
│ │ ├── global-client-nomad.p12
│ │ └── global-server-nomad.pem
│ ├── sep-ca-key.pem
│ ├── sep
│ │ ├── localhost-cert-key.pem
│ │ ├── inventory_api-cert-key.pem
│ │ ├── tasks_api-cert.pem
│ │ ├── localhost-cert.pem
│ │ ├── inventory_api-cert.pem
│ │ └── tasks_api-cert-key.pem
│ ├── casdoor
│ │ ├── sep_token_jwt_key.pem
│ │ ├── README.md
│ │ ├── sep_token_jwt_key.key
│ └── sep-ca.pem
├── mime.types
├── casdoor_init_data.json
├── http-tests
│ ├── inventory.http
│ ├── nomad.http
│ ├── task_history.http
│ └── tasks.http
└── nginx.conf
- Add your PMM API key to the
.env.dockerfile
By now, a .env.docker file should have been created in your current directory.
Open it and replace REPLACE_WITH_YOUR_PMM_API_KEY with your actual PMM API key.
- Start Nomad with the new generated config:
nomad agent -config /path/to/SEP/data/nomad.hclReplace /path/to/SEP with the path in which the project folder is stored in your computer.
Important
Make sure you're not running other Nomad instances.
- Build the Docker Compose services:
docker compose build- Start the Docker Compose services:
docker compose upSEP will be available in https://localhost.
You can stop SEP with CTRL-C and later start it again with docker compose up.
See our CONTRIBUTING guide.
See our INSTALLER guide for deployment instructions.







