> This page location: Docs > Self-Hosting > Running Your Stack
> Full index for agents: https://www.semantius.com/llms.txt

# Running Your Stack

> Everyday commands for a self-hosted Semantius platform: starting, stopping, backing up, updating, adding users, and reaching the API from scripts.

- **URL**: https://www.semantius.com/docs/self-hosted/running-your-stack

---

Once your stack is up, day-to-day work is a handful of commands plus a few addresses worth bookmarking. This page covers both. Every command here is run **from inside your variant folder**, the one holding `docker-compose.yml` and `.env`.

**This page is written for the `local-semantius-idp` variant, and applies to `local-entra-idp` as well.** Where a task happens in your identity provider rather than in semantius-idp, the section says where. On Dokploy there are no scripts to run, so use the [Dokploy](https://www.semantius.com/docs/self-hosted/dokploy.md#after-the-first-deploy) page instead. A variant is one ready-made setup of the stack; [Choose or Build Your Variant](https://www.semantius.com/docs/self-hosted/variants.md) lists them all and which pages apply to each.

Every command exists twice: a `.sh` version for macOS, Linux, and Git Bash, and a `.cmd` version for the Windows command prompt. The examples below show the `.sh` form. On Windows, swap the extension.

## The Everyday Commands

| Command        | What it does                                                     | Your data   |
| -------------- | ---------------------------------------------------------------- | ----------- |
| `./status.sh`  | Shows what is running and whether each part is healthy           | Untouched   |
| `./stop.sh`    | Stops everything, leaves it ready to resume                      | Kept        |
| `./start.sh`   | Starts it again after a stop                                     | Kept        |
| `./up.sh`      | Applies changes you made to `.env` or the other settings files   | Kept        |
| `./create.sh`  | Rebuilds everything from scratch, including a brand new database | **Deleted** |
| `./destroy.sh` | Removes the containers and the database entirely                 | **Deleted** |

The two that delete your data both ask for confirmation first when there is a database to lose.

On Windows, `start` is a built-in command, so type `.\start.cmd` rather than `start.cmd` or you will open a new window instead of starting your stack.

## Changed a Setting? Use `up`, Not `create`

This is the one distinction worth learning, because getting it backward costs you your data.

**`./up.sh` keeps your database.** Use it whenever you have edited `.env` or one of the settings files next to it. It applies the change to the running system and leaves everything you have built alone.

**`./create.sh` wipes your database and starts over.** Use it on a first install, or when you deliberately want a clean slate.

The reason they are separate commands rather than one command with a flag is that the database only sets itself up once, on the very first start. Restarting or even fully recreating the containers keeps the existing database exactly as it was. So if you change something that only applies at database creation time and then wonder why nothing happened, that is the rule you are seeing, not a bug.

## Adding People

With [semantius-idp](https://www.semantius.com/docs/self-hosted/semantius-idp.md), sign in as the administrator and go to `http://localhost:3000/idp/admin`. That is where accounts are created and managed.

With your own identity provider, people are managed there: in Entra, you assign them to the Semantius API, as the [Entra page](https://www.semantius.com/docs/self-hosted/entra-id.md#3-give-people-access) describes. Either way, what each person can see is granted in the Semantius app, under **Administration**, then **Users**.

The rest of this section is about semantius-idp's email.

By default the stack does not send email. That is deliberate: a local install with no mail service configured would otherwise offer password reset links that never arrive. The practical consequence is that **an administrator creates accounts and sets passwords directly**, and there is no self-service password reset.

To turn email on for a real deployment, add a [Resend](https://resend.com) API key to `.env` as `RESEND_API_KEY` and run `./up.sh`. Password resets, email verification, and notifications switch on together. Resend is the only email service the sign-in service supports; there are no settings for your own SMTP server.

## Reaching the API From a Script

Browsers sign in interactively, but scripts and scheduled jobs cannot. For those, semantius-idp offers personal **API keys**, through the API gateway built into it:

1. Sign in and open `http://localhost:3000/idp/account/api-keys`.
2. Create a key and copy it. You only see it once.
3. Send it with every request, as the `x-api-key` header, to the `/gateway/rest/` address:

```bash
curl -H "x-api-key: YOUR_KEY_HERE" \
  "http://localhost:3000/gateway/rest/customers?limit=5"
```

That address is the same API as `/rest/`, with the key exchange handled for you. The key belongs to your user account, so it can see exactly what you can see and nothing more. Treat it like a password: anyone holding it can act as you.

**With your own identity provider**, such as Entra, a script gets an access token from that provider and sends it as a bearer token to `/rest/`. If you want personal API keys there as well, put an API gateway of your choice, such as Kong, Tyk or AWS API Gateway, in front of `/rest/`.

## Browsing the API

`http://localhost:3000/api-docs/` lists every endpoint your model generates, with request and response shapes and a **Test Request** button on each one. With semantius-idp, when you are signed in to the app in the same browser, those test requests are authenticated automatically, so you can explore the whole API without pasting a credential anywhere. With your own identity provider, paste an access token into the docs page instead.

The documentation is generated from your live model. Change the model and the docs change with it.

## Connecting the `semantius` CLI

The [`semantius` CLI](https://www.semantius.com/docs/cli.md), the one coding agents use, works against a self-hosted stack the same way it works against a hosted one. Point it at your front door address, `localhost:3000` or whatever domain you deployed to:

```bash
semantius use localhost:3000
```

It configures itself from there: every stack publishes a small description of itself at `/.well-known/semantius.json` that tells the CLI where to sign in and where the API lives. Nothing has to be passed by hand.

This is not the [`pg_semantius` CLI](https://www.semantius.com/docs/pg-semantius/cli.md), which connects straight to the database for administration. You do not need that one to use a self-hosted stack.

You can read that document yourself to check a deployment is answering correctly:

```bash
curl http://localhost:3000/.well-known/semantius.json
```

## Connecting a Database Client

The stack publishes two database ports on purpose, for the programs that talk SQL rather than HTTP.

**Port 6432 is the pooled connection for your own applications.** It handles many short-lived connections far better than connecting to the database directly. It logs in as `semantius_authenticator`, with the `SEMANTIUS_AUTHENTICATOR_PASSWORD` value from your `.env`.

**Port 5434 is the direct connection**, for administration and for migrations with the [`pg_semantius` CLI](https://www.semantius.com/docs/pg-semantius/cli.md), and for anything that needs a session of its own. Connect as `postgres` with the `POSTGRES_PASSWORD` value from your `.env`. The database is named `semantius`.

On a public server, restrict both to the machines that need them, as [Going Live](https://www.semantius.com/docs/self-hosted/deploy.md#restrict-the-database-ports) shows.

If you just want to look at some data and do not want to install a client at all, semantius-idp's administrators have a read-only SQL console at `http://localhost:3000/idp/admin/database`. Every query there runs read-only and is recorded in the audit log, which also means an administrator who can open it can read everything stored in the database. Worth knowing before you hand out administrator accounts.

## Backing Up

Your data lives in one PostgreSQL database, so a backup is a plain `pg_dump`. Run this from the variant folder while the stack is up:

```bash
docker exec semantius-postgres pg_dump -U postgres -Fc -d semantius > semantius.dump
```

That writes a single file you can copy anywhere. It runs as the `postgres` superuser on purpose: an ordinary account would only back up the rows it is allowed to see.

**`./create.sh` and `./destroy.sh` delete the database, and there is no undo.** The data sits in a Docker volume called `semantius_pgdata`, and those two commands remove it. Take a dump before running either one on a stack you care about.

For a server, put the command on a daily schedule. Keep the copies somewhere other than that server, encrypt them if they leave your network, and decide how many days to keep. A backup you have never restored is a hope rather than a backup, so try a restore on a test machine now and then. Restoring follows the rules in [pg\_semantius: Upgrade and Backup](https://www.semantius.com/docs/pg-semantius/maintain.md#back-up): restore into an empty database, as the `postgres` user, with no extra flags.

## Choosing a Version

By default the stack runs the latest published version of every piece. It downloads that version each time you run `./create.sh` or `./up.sh`. A plain restart, a reboot or `./start.sh` does not download anything, and keeps running what is already there. That is convenient while you are trying things out, and the wrong default for a server you depend on.

To pin a database version for one run, pass the tag:

```bash
./up.sh 0.4.0-pg18
```

To make it permanent, set `SEMANTIUS_DB_VERSION` in `.env`. There are matching `SEMANTIUS_APP_VERSION` and `SEMANTIUS_IDP_VERSION` settings for the web app and the sign-in service. Pin all three before you put a stack into real use, so an update happens when you choose rather than on the next `./up.sh`.

The published versions are listed on each image's package page: [database](https://github.com/orgs/semantius/packages/container/package/postgres), [web app](https://github.com/orgs/semantius/packages/container/package/semantius-app) and [sign-in service](https://github.com/orgs/semantius/packages/container/package/semantius-idp). Database tags always end in `-pg18`, for example `0.4.0-pg18`.

**The other pieces have no setting in `.env` yet.** The API server, the connection pooler, the API docs viewer and the key fetcher run their `latest` version, and the front door runs Caddy `2-alpine`. Each `./up.sh` or `./create.sh` downloads their newest release. Once a combination works for you, pin at least the API server and the docs viewer to fixed tags too, by setting their `image:` in a [`docker-compose.override.yml`](https://www.semantius.com/docs/self-hosted/variants.md#customizing-a-variant).

## Updating to a New Version

Updating the web app and the sign-in service is one step: change `SEMANTIUS_APP_VERSION` or `SEMANTIUS_IDP_VERSION` in `.env` and run `./up.sh`. Your data is kept.

**Updating the database takes one more step.** The database sets itself up only once, when it is first created. A newer `SEMANTIUS_DB_VERSION` therefore brings newer extension files, but it does not change the schema of a database that already exists. Take a backup first, then change the tag and run `./up.sh`, then apply the update inside the database:

```bash
docker exec semantius-postgres psql -U postgres -d semantius \
  -c "ALTER EXTENSION pg_semantius UPDATE;" \
  -c "SELECT semantius.migrate();"
```

Both statements are safe to run again, because `migrate()` records what it has already applied and skips it. To see what is installed and whether anything is still pending, run `SELECT * FROM semantius.status();` the same way. [pg\_semantius: Upgrade and Backup](https://www.semantius.com/docs/pg-semantius/maintain.md) explains both in more detail, including which old versions have no upgrade path.

## Updating the Stack Files

The compose file, the front door configuration and the scripts also change over time. You pick up a newer set by pulling the repository again, from the folder you cloned:

```bash
git pull
```

Then run `./up.sh` from your variant folder. It recreates the containers from the new files and keeps your database.

Your `.env` and a `docker-compose.override.yml` survive this, because neither is part of the repository. A change made directly to a file in the variant folder does not: `git pull` stops on the conflict. Keep your changes in those two files, or in a variant of your own, as [Choose or Build Your Variant](https://www.semantius.com/docs/self-hosted/variants.md#keeping-your-changes-when-you-update) explains.

## When Sign-In Suddenly Stops Working

The sign-in system periodically replaces the keys it uses to sign your login tokens, and the API reads those keys once, when it starts. If people are signed in fine but every API call is rejected, the API is most likely holding the previous set.

```bash
./jwks-refresh.sh
```

That fetches the current keys and restarts the API, which takes about a second. Your database stays up and nobody is signed out. Most providers rotate slowly enough that running this when you hit the problem is fine. If yours rotates often, put it on a daily schedule.

## Next Steps

- **[Going Live](https://www.semantius.com/docs/self-hosted/deploy.md)**: run the stack on a real server, behind your own domain and with HTTPS.
- **[Settings Reference](https://www.semantius.com/docs/self-hosted/settings.md)**: every value in `.env`, grouped by what it does.
- **[Dokploy](https://www.semantius.com/docs/self-hosted/dokploy.md)**: deploy through Dokploy without editing config files.
- **[Microsoft Entra ID](https://www.semantius.com/docs/self-hosted/entra-id.md)**: sign people in with their Microsoft work accounts instead of the bundled provider.

---

## Related

- [Self-Hosting Quick Start](https://www.semantius.com/docs/self-hosted/quick-start.md)
- [Going Live](https://www.semantius.com/docs/self-hosted/deploy.md)
- [Docs home](https://www.semantius.com/docs.md)
- [Full index for agents](https://www.semantius.com/llms.txt)
