Skip to content

Configuration

Philter Workspace reads its configuration from application.properties (or matching environment variables). The defaults shipped in the file are intended for the bundled docker-compose.yaml deployment; override any property by editing the file, by setting an environment variable named the same way (e.g. SERVER_PORT), or by pointing Philter Workspace at an additional properties file with the --spring.config.additional-location=... command-line argument.

HTTP server

server.port

The port Philter Workspace listens on. Defaults to 8080.

server.forward-headers-strategy=native

Tells Philter Workspace to use the X-Forwarded-For and X-Forwarded-Proto headers added by a TLS-terminating reverse proxy (nginx, AWS ALB, etc.), so it knows the client's address and that the request arrived over HTTPS. Without this, the session cookie would be marked "insecure" because Philter Workspace would think the connection was plain HTTP.

Philter Workspace believes these headers only on requests from an address matching server.tomcat.remoteip.internal-proxies, set with the environment variable PHILTER_WORKSPACE_TRUSTED_PROXIES_REGEX. The default matches every private-network and loopback address, so any client on a private network that reaches Philter Workspace directly can set its own address. Set PHILTER_WORKSPACE_TRUSTED_PROXIES_REGEX to a regular expression matching only your reverse proxy's address. If you terminate TLS in Philter Workspace itself, set the strategy to none.

server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.secure=true
server.servlet.session.cookie.same-site=strict
  • http-only=true — JavaScript cannot read the session cookie, which blunts cookie theft via cross-site scripting.
  • secure=true — the browser only sends the cookie over HTTPS. Works correctly even when Philter Workspace receives plain HTTP from a reverse proxy because forward-headers-strategy=native (above) makes Philter Workspace believe the request arrived over HTTPS.
  • same-site=strict — the browser will not send the cookie on any cross-site request, which closes the cross-site request forgery vector that a missing SameSite attribute would otherwise leave open.

Upload limits

spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=110MB

These are the hard ceilings enforced before a request reaches Philter Workspace's business logic. The runtime per-request upload limit lives under Admin → General; that limit is the one operators normally adjust. The ceiling here only kicks in if an admin raises the runtime limit above 100 MB.

Database

philter-workspace.store

Which database Philter Workspace uses: mongodb (the default) or sqlite. The SQLite settings (philter-workspace.sqlite.path, philter-workspace.sqlite.pool-size, philter-workspace.sqlite.busy-timeout-ms, philter-workspace.sqlite.synchronous) are described in Database. The settings below apply to MongoDB.

spring.data.mongodb.uri

The connection URI to MongoDB. Default: mongodb://localhost:27017/philter-workspace.

spring.data.mongodb.auto-index-creation=true

Auto-create the indexes Philter Workspace needs (unique-name constraints on users and batches, "one in-flight import per batch", etc.) the first time each collection is used. Leave this true unless you create the indexes through another mechanism — without them, duplicate-key checks won't be enforced and the import dispatcher won't behave correctly.

Sessions and Valkey

spring.session.store-type=redis
spring.session.timeout=30m
spring.data.redis.host=localhost
spring.data.redis.port=6379

Session state lives in Valkey (a Redis protocol-compatible server) so user sessions are shared across application replicas. The bundled docker-compose.yaml overrides spring.data.redis.host via environment variable so the app talks to the Valkey container.

When Valkey is not reachable on local non-Docker runs, comment out spring.session.store-type to fall back to in-memory sessions. That is fine for single-instance development, but sessions are lost on restart and won't work in a multi-replica deployment.

spring.session.timeout controls how long an idle session stays valid before the user is logged out.

Sign-in

People sign in through the user management API of Philter 4.x (see Supported Philter versions), at Philter Workspace's Philter, PHILTER_WORKSPACE_PHILTER_URL (see Philter integration). See Sign-in through Philter.

Property Environment variable Purpose
philter-workspace.sign-in.check-interval-seconds PHILTER_WORKSPACE_SIGN_IN_CHECK_INTERVAL_SECONDS How often Philter Workspace checks a person's session key with Philter while they use it, in seconds (default 60). 0 checks every request. A session Philter has ended, or whose role has changed, ends at the next check. The check is what keeps Philter's idle timeout for the key moving, so keep the interval well under Philter's SESSION_KEY_IDLE_TIMEOUT_MINUTES (30 by default), or people are signed out while they work. A negative value stops Philter Workspace at startup.
philter-workspace.api-keys.cache-seconds PHILTER_WORKSPACE_API_KEYS_CACHE_SECONDS How long Philter Workspace keeps Philter's answer for a Philter API key used on its API, in seconds (default 30). A revoked key, a deactivation, or a role change applies within this time. 0 asks Philter on every request. A negative value stops Philter Workspace at startup.

PHILTER_WORKSPACE_SIGN_IN_MODE is no longer read: Philter Workspace refuses to start with local, which was removed (see Upgrading from local sign-in). These settings are read only at startup, so an administrator signed in to Philter Workspace cannot change how people sign in. Calls to Philter use the philter-workspace.philter.tls.* settings in TLS and client certificates; with Philter's Docker image, which serves HTTPS with a self-signed certificate, set philter-workspace.philter.tls.trust-store to a trust store holding that certificate.

The Philter must run with PASSWORD_SIGN_IN_ENABLED=true. Otherwise every sign-in fails with "Sign-in is unavailable" and Philter Workspace logs a warning naming the setting. List Philter Workspace's address in Philter's TRUSTED_PROXIES, so Philter rate limits and records each person's own address rather than Philter Workspace's.

Philter Workspace sends Philter the address it believes the person has. With the default PHILTER_WORKSPACE_TRUSTED_PROXIES_REGEX (see server.forward-headers-strategy=native), a client on a private network that reaches Philter Workspace directly can set that address, and so choose the address Philter rate limits. Narrow the setting to your reverse proxy. Philter's lockout per username does not depend on the address.

Threading

spring.threads.virtual.enabled=true

Run request handling on lightweight threads so Philter Workspace handles many simultaneous reviewers more efficiently. Recommended; turn off only if you hit a compatibility issue.

Demo data

philter-workspace.demo-data.enabled=true
philter-workspace.demo-data.directory=/app/sample-files

When enabled and Philter Workspace starts up against an empty database, a small set of sample documents is loaded and run through redaction so the UI has something to demonstrate. This runs exactly once on a fresh install — once any document exists, the loader does nothing.

The default directory is the path mounted by docker-compose.yaml. When that directory does not exist (running locally outside Docker), the loader falls back to ./sample-files and ../sample-files relative to the working directory.

Set philter-workspace.demo-data.enabled=false for production deployments.

Monitoring and metrics

management.endpoints.web.exposure.include=health,prometheus
management.endpoints.web.discovery.enabled=false
management.endpoint.health.show-details=never
management.endpoint.health.show-components=never
management.health.redis.enabled=${MANAGEMENT_HEALTH_REDIS_ENABLED:false}

Philter Workspace serves /api/health, /actuator/health, and /actuator/prometheus, all unauthenticated and GET-only. See REST API → Health and metrics for the response shapes and what they disclose.

The exposure list is a security control, not a convenience. Both exposed endpoints are reachable without a credential, so adding env, configprops, beans, loggers, or heapdump to it would hand configuration or memory contents to anything that can reach the port. Everything not on the list returns 404, and the /actuator links page is switched off as well.

show-details and show-components are pinned off so an unauthenticated caller gets the aggregate status and never learns which dependency is down or what address it sits at.

MongoDB, Valkey, disk space, and (when full text search is enabled) OpenSearch contribute to the aggregate. Nothing needs to be configured for them. Note that an unreachable MongoDB delays the health response by the driver's server-selection timeout; see REST API → Health and metrics.

Valkey counts because Philter Workspace stores sessions in it and cannot serve a page without it, so an unreachable Valkey is a genuine outage rather than a degradation. MANAGEMENT_HEALTH_REDIS_ENABLED=false drops it from health if your deployment has some other reason to leave it out.

Philter integration

Philter Workspace works with one Philter, which signs people in, holds the policies, and redacts. See Configure Philter.

Property Environment variable Purpose
philter-workspace.philter.url PHILTER_WORKSPACE_PHILTER_URL Required: Philter's http or https URL, for example http://philter:8080. A URL holding a user name or password stops Philter Workspace at startup.
philter-workspace.philter.api-key PHILTER_WORKSPACE_PHILTER_API_KEY Required: the API key Philter Workspace uses for background work such as ingest, for a Philter user who is not an administrator. See Philter API key for Philter Workspace. Set it through the environment or a secrets mechanism, not application.properties.

Both are read only at startup, and Philter Workspace does not start without them. It logs the URL it uses, never the key. Admin → Philter shows the URL and tests the connection, but cannot change either setting.

TLS and client certificates

When PHILTER_WORKSPACE_PHILTER_URL starts with https://, Philter Workspace verifies Philter's certificate, including that it names the URL's host. Two optional settings apply:

Property Purpose
philter-workspace.philter.tls.trust-store A PKCS12 or JKS trust store holding the certificate authority (or self-signed certificate) to trust for Philter, in place of the JVM's default trust store.
philter-workspace.philter.tls.trust-store-password The trust store's password, if it has one.
philter-workspace.philter.tls.key-store A PKCS12 or JKS keystore holding a client certificate and its private key, presented to Philter for mutual TLS.
philter-workspace.philter.tls.key-store-password The keystore's password, which must also be the private key's password. Leave it empty only for a keystore without one; a missing or wrong password stops Philter Workspace at startup.

Set the passwords through environment variables (for example PHILTER_WORKSPACE_PHILTER_TLS_KEY_STORE_PASSWORD) or a secrets mechanism rather than in application.properties. Mount the store files read-only.

Philter Workspace reads the stores when it starts and refuses to start if a file is missing, can't be opened with its password, or holds no usable key or certificate. The error names the file, never the password. Build a trust store with keytool -importcert; a PKCS12 trust store made with openssl pkcs12 reads as empty in Java.

Mutual TLS is enforced on the Philter side, by Philter or by a TLS proxy in front of it that requires client certificates. To have Philter require them itself, see Client certificates (mutual TLS) in Philter's settings. A client certificate does not replace Philter Workspace's Philter API key: Philter still requires the key on every request.

Data-source allow-list

philter-workspace.data-sources.allowed-hosts=

Optional comma-separated list of host patterns that Philter Workspace accepts as the target of an outbound data-source connection (OpenSearch / Elasticsearch test endpoints, ingest workers, Ollama, JDBC URLs). Philter's URL is an environment setting rather than an admin one, so it is not checked against this list. Patterns may be exact hostnames (opensearch.example.com) or use a leading wildcard (*.search.example.com).

When unset, public hosts are allowed and private/internal addresses (loopback, link-local, private network ranges) are blocked. When set, every outbound host must match a pattern. The same check applies at data-source create time and again at the moment Philter Workspace actually makes the outbound call, so changing the list takes effect on the next request — no restart needed.