9.1 KiB
ChronoSeal Deployment Guide
ChronoSeal is intended to run as a small Unix daemon behind TLS, with static browser assets served either by the daemon or by the same protected origin. This guide covers native, service, and container deployment.
Deployment Model
Typical production topology:
Internet
|
v
TLS reverse proxy
|
v
chronoseal daemon on 127.0.0.1:3000
|
v
sqlite-in-disk or valkey storage
For local evaluation, the daemon can bind directly to 0.0.0.0:3000 or 127.0.0.1:3000.
Requirements
| Tool | Minimum | Purpose |
|---|---|---|
| Rust | 1.87 stable | Build server and shared crates |
wasm32-unknown-unknown target |
current stable | Compile WASM runtime |
wasm-pack |
0.13 | Generate browser WASM package |
| systemd | 248+ | Native service management |
| Docker | 24.x | Optional container image |
| Docker Compose | 2.x | Optional local orchestration |
Install Rust from rustup, then install the WASM tooling:
rustup target add wasm32-unknown-unknown
cargo install wasm-pack
Build
Use the repository build script:
bash scripts/build.sh
The script:
- Builds
wasm/withwasm-pack build --target web --release. - Replaces
frontend/pkgwith the generated package. - Builds the release daemon binary.
Manual equivalent:
wasm-pack build wasm --target web --release
rm -rf frontend/pkg
mv wasm/pkg frontend/pkg
cargo build -p chronoseal-server --bin chronoseal --release
Release binary:
target/release/chronoseal
Native Install
The installer builds, installs, enables, and starts the service:
sudo bash scripts/install.sh
Installer actions:
- create the
chronosealsystem user if missing - build WASM and server artifacts
- install
target/release/chronosealto/usr/local/bin/chronoseal - copy
frontend/to/opt/chronoseal/frontend - install
chronoseal.serviceto/etc/systemd/system/chronoseal.service - reload systemd
- enable and start the service
Verify:
sudo systemctl status chronoseal
chronoseal status --format json
chronoseal health
sudo journalctl -u chronoseal -f
Running Without Install
For local development:
bash scripts/build.sh
cargo run -p chronoseal-server --bin chronoseal -- run \
--bind 127.0.0.1:3000 \
--frontend-dir frontend
Probe the daemon:
curl http://127.0.0.1:3000/health
curl http://127.0.0.1:3000/stats
curl http://127.0.0.1:3000/metrics
Configuration
ChronoSeal resolves configuration in this order:
- CLI flags
CHRONOSEAL_*environment variables- TOML config file
- built-in defaults
Default config discovery:
CHRONOSEAL_CONFIG, if it points to an existing file/etc/chronoseal/config.toml$XDG_CONFIG_HOME/chronoseal/config.toml~/.config/chronoseal/config.toml
Validate effective configuration:
chronoseal config check --format yaml
Example:
bind = "127.0.0.1:3000"
db_type = "sqlite-in-disk"
pid_file = "/run/chronoseal.pid"
db_path = "/var/lib/chronoseal/chronoseal.sqlite"
frontend_dir = "/usr/share/chronoseal/frontend"
log_file = "/var/log/chronoseal/chronoseal.jsonl"
heartbeat_min_interval_ms = 12000
heartbeat_max_interval_ms = 25000
expiration_minutes = 30
rate_limit_count = 5
rate_limit_window_secs = 10
max_timestamp_drift_ms = 30000
min_mouse_total_dist = 10.0
max_mouse_avg_speed = 2.0
min_pause_count = 1
require_mouse_activity = true
gene_size = 512
mutation_rounds = 4
Storage Backends
| Backend | db_type |
Use case |
|---|---|---|
| SQLite memory | sqlite-in-memory |
ephemeral local or stateless deployment |
| SQLite disk | sqlite-in-disk |
persisted session continuity across restarts |
| Valkey | valkey |
external session storage |
For disk persistence:
sudo mkdir -p /var/lib/chronoseal
sudo chown -R chronoseal:chronoseal /var/lib/chronoseal
For Valkey / Redis:
ChronoSeal expects a running Valkey or Redis instance when db_type is set to valkey.
1. Installing Valkey or Redis
To install Valkey (the recommended open-source option) or Redis on Linux:
- Valkey (Debian/Ubuntu):
sudo apt-get install -y valkey-server - Redis (Debian/Ubuntu):
sudo apt-get install -y redis-server
2. Local Setup and Startup
By default, ChronoSeal searches for Valkey/Redis on 127.0.0.1:6666.
You can start a local instance manually:
# Start Valkey on port 6666
valkey-server --port 6666 --bind 127.0.0.1
# Or start Redis on port 6666
redis-server --port 6666 --bind 127.0.0.1
Or run it via Docker:
# Run Valkey container mapping host port 6666 to container port 6379
docker run -d --name chronoseal-valkey -p 6666:6379 valkey/valkey:latest
3. Service Configuration
Configure the environment variables to point ChronoSeal to your instance:
export CHRONOSEAL_DB_TYPE=valkey
export CHRONOSEAL_VALKEY_ADDR=127.0.0.1:6666
Providing Credentials & SSL/TLS
If your Valkey/Redis server requires authentication or secure TLS/SSL, include them directly in the CHRONOSEAL_VALKEY_ADDR connection URL:
- Password Only:
export CHRONOSEAL_VALKEY_ADDR=redis://:your_password@127.0.0.1:6666 - Username & Password:
export CHRONOSEAL_VALKEY_ADDR=redis://your_username:your_password@127.0.0.1:6666 - Secure Connection (SSL/TLS): Use the
rediss://scheme prefix:export CHRONOSEAL_VALKEY_ADDR=rediss://your_username:your_password@secure-valkey-host.example.com:6379
If Valkey connection setup fails, the current implementation logs a warning and falls back to in-memory SQLite.
systemd
The supplied service file is intended as the baseline unit. Keep the daemon under a dedicated user and restrict filesystem access to the paths it needs.
Useful commands:
sudo systemctl daemon-reload
sudo systemctl enable --now chronoseal
sudo systemctl restart chronoseal
sudo systemctl status chronoseal
sudo journalctl -u chronoseal -f
Recommended hardening properties include:
NoNewPrivileges=truePrivateTmp=trueProtectSystem=strictProtectHome=trueProtectKernelTunables=trueProtectKernelModules=trueProtectControlGroups=trueMemoryDenyWriteExecute=trueRestrictRealtime=trueRestrictSUIDSGID=trueSystemCallArchitectures=native
Any hardening must still allow access to:
- the binary
- frontend assets
- PID file directory
- optional log file directory
- SQLite database directory, if using
sqlite-in-disk
Reverse Proxy and TLS
ChronoSeal should be served over HTTPS in production. Terminate TLS at a reverse proxy or load balancer and proxy to the local daemon.
Minimal nginx example:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
proxy_read_timeout 35s;
proxy_send_timeout 10s;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
Keep /init, /hb, and frontend assets on the same origin when possible. If you split origins, configure CORS and cookie/application policy deliberately.
Docker
Build and run:
bash scripts/build.sh
docker compose up -d --build
The Compose file exposes port 3000.
curl http://127.0.0.1:3000/health
The Dockerfile copies frontend/ from the working tree. Build frontend/pkg before building the image when the browser WASM runtime is required inside the container.
Observability
CLI:
chronoseal status --format json
chronoseal health
chronoseal stats --format json
chronoseal metrics
HTTP:
curl http://127.0.0.1:3000/health
curl http://127.0.0.1:3000/stats
curl http://127.0.0.1:3000/metrics
Prometheus metrics:
chronoseal_sessionschronoseal_expired_sessionschronoseal_max_chain_length
Logging
Use info-level logs for production:
CHRONOSEAL_LOG=info chronoseal run
or with systemd:
sudo systemctl edit chronoseal
Avoid debug logging in production because internal identifiers may be written to logs.
Production Checklist
- Build
frontend/pkgbefore packaging. - Serve ChronoSeal traffic over HTTPS.
- Bind the daemon to localhost behind a reverse proxy unless direct exposure is required.
- Use a dedicated service user.
- Keep debug logs disabled.
- Choose storage intentionally:
sqlite-in-memory,sqlite-in-disk, orvalkey. - Protect SQLite and log directories with correct ownership.
- Monitor
/health,/stats, and/metrics. - Verify
chronoseal config checkafter environment or config changes.
v1.0.2 Deployment Notes
- Containers run as a dedicated non-root user.
- Reverse proxies should forward X-Forwarded-For or X-Real-IP.
- Security headers are enabled by default.