Aster Web Data / Operate
Configure and deploy
How to write the configuration file for a production deployment, keep secrets out of it, and stop the server cleanly behind a load balancer.
One YAML file describes a whole deployment: the services, the databases they read, authentication, limits and telemetry. The file holds no secrets, so it can live in version control beside your model, and an unknown key stops start-up, so a misspelt key fails the deploy instead of being silently ignored.
The configuration file
The server reads the file named by --config. Relative paths in it resolve against the directory that holds the file. This file runs one service on PostgreSQL behind a load balancer:
listen: 0.0.0.0:8080
services:
crm:
root: /crm
public_url: https://api.example.com/crm
namespace: Crm
datasources: [model/crm]
max_page_size: 100
databases:
main:
kind: postgres
url_env: CRM_DATABASE_URL
tls: verify-full
ca_file: certs/db-ca.pem
required: true
pool:
max: 20
auth:
kind: jwt
jwt:
jwks_file: keys/jwks.json
audience: [crm-api]
issuer: [https://login.example.com/]
limits:
residual_rows: 50000
request_deadline_ms: 60000
observability:
service_name: crm-api
traces_exporter: otlp
metrics_exporter: prometheus
logs_exporter: none
otlp_endpoint: http://otel-collector.example.com:4317
health:
port: 9090
host: 127.0.0.1
shutdown:
grace_seconds: 30
ready_delay_seconds: 5
The Configuration reference lists every key with its default.
Secrets
Secrets stay out of the configuration file. A database connection is named by an environment variable or a file, never written inline:
databases.<name>.url_envnames the variable that holds the connection URL, andurl_filenames a file that holds it.- Without a URL, the parts form takes
host,port,user,databaseand a password frompassword_envorpassword_file. - The JWT secret, for an HMAC key, comes from the variable
auth.jwt.secret_envnames.
Aster reads the URL again on every attempt to open the database, so a changed value is used from the next attempt.
A few settings can also come from the server's own environment variables, such as ASTER_LOG for the log filter and the OTEL_* variables for telemetry. Environment variables lists them and which way each one overrides the file.
TLS
PostgreSQL and MariaDB connections take a tls mode:
| Mode | Behaviour |
|---|---|
disable |
no TLS |
prefer |
TLS when the server offers it, without checking the certificate. This is the default. |
require |
TLS, without checking the certificate |
verify-ca |
TLS, and the certificate must chain to a trusted authority |
verify-full |
verify-ca, and the host name must match the certificate |
With verify-ca or verify-full, ca_file names a PEM file of the authority. Without it, the Mozilla root certificates are used.
A plaintext or unverified connection logs a warning. To make it an error, set tls_strict: true on a database. To apply that to every PostgreSQL and MariaDB database, set startup.require_tls: true, or ASTER_WEBDATA_REQUIRE_TLS=1.
Use verify-full for connections that cross a network you do not control, because the prefer default accepts a server that presents any certificate. SQL Server, Oracle and Db2 accept fewer modes; their pages (SQL Server, Oracle, Db2) list them.
Several services
One process serves one or more services. Each service has a root path, such as /crm, and its own data sources, security, rules and limits. Roots are unique, and no root is a path prefix of another, so /a and /a/b cannot both be served. A lone service can use /.
Services can share the databases. Each database is declared once under databases. A service's data sources are on its database unless a data source names its own. The same set name may map different tables in two services, and two services may map one table. Two things are refused at start-up: one table that two services describe differently (its columns, types or keys), and one table that two services both seed.
For how a request reads data that lives in more than one database, see Several databases and Reads across databases.
What a reload applies
Change the model describes how a SIGHUP reload runs and what happens when it fails. A reload applies the services, their models, rules, scripts, operations, views, virtual sources and limits, the databases and their connections, authentication, CORS and the explain header.
These keys need a restart, because the process holds them for its whole life:
| Key | Why |
|---|---|
listen (and --listen) |
the listening socket is bound once |
health (enabled, host, port) |
the health listener is bound once |
log |
logging is set up once |
observability |
the telemetry pipeline is set up once |
shutdown.grace_seconds |
the drain period is fixed at start |
databases.<name>.setup, services.<name>.seed |
setup and seeding run once, when the database is first opened |
If you change one of these and send SIGHUP, the reload applies everything else and logs a warning naming the key.
Shutdown behind a load balancer
On the first SIGTERM or SIGINT, the server:
- Sets readiness to false at once.
/readyzanswers 503 from this point. - Keeps serving for
shutdown.ready_delay_seconds(default 0), so the load balancer can take the instance out of rotation. - Stops accepting connections. Requests in flight run until they finish or
shutdown.grace_seconds(default 30) ends. After that they are cut. - Flushes the telemetry pipeline, for up to 5 seconds.
- Exits.
A second signal exits at once. Set ready_delay_seconds to 5 behind a load balancer, which gives it time to see the failing readiness check. Keep grace_seconds below the time your orchestrator waits before it kills the process, so the server exits cleanly rather than being killed mid-drain.
The server logs one drain summary line when the grace ends. It reports how many requests were in flight when the grace began, how many completed and how many were cut.
Health and outages covers the readiness checks and what happens when a database goes down, and Observability the telemetry the observability section turns on.
Preview builds
A preview build expires one month after it is built. The expiry is part of the build: aster-webdata-server --version prints it, and so does the first line the server logs when it starts.
This is a preview build and will expire on 2026-11-28 13:53 UTC. Run 'aster-webdata-server update' to get the latest build.
A build past its expiry prints the expiry and the update command, exits with status 1 and does not bind its port. A running server stops at the expiry the way it stops on SIGTERM: it stops accepting, lets requests in flight finish up to shutdown.grace_seconds, and exits, after a log line that says why. In the last seven days the server logs a warning each day. Container images are preview builds too; pull a newer image rather than updating inside the container.
To get the latest build:
aster-webdata-server update --check # installed version and expiry, latest version and expiry
aster-webdata-server update
update downloads the build for your platform from downloads.getaster.now, checks its signature against the public key built into the server, runs the new binary's --version, and replaces the binary in one step. The old binary stays beside it as aster-webdata-server.previous, so you can put it back. Nothing is changed if the download, the signature or the checks fail. update never restarts the service: restart it when you are ready. See the command line for what it refuses.
A preview build also looks at the update feed once when it starts and then daily. It is one GET of a small JSON file, sent with a User-Agent that names the version and nothing else, and it logs a line when a newer build exists. It installs nothing. To turn it off, set the key or the variable:
disable_update_check: true
ASTER_WEBDATA_UPDATE_CHECK=0 aster-webdata-server --config server.yaml