############################################################################################################# # Welcome to settings file from # # ____ _____ ___ ____ _ ___ _ _ ____ ____ ____ _____ # # / ___|_ _|_ _| _ \| | |_ _| \ | |/ ___| | _ \| _ \| ___| # # \___ \ | | | || |_) | | | || \| | | _ _____| |_) | | | | |_ # # ___) || | | || _ <| |___ | || |\ | |_| |_____| __/| |_| | _| # # |____/ |_| |___|_| \_\_____|___|_| \_|\____| |_| |____/|_| # # # # Do not comment out any entry, it will be removed on next startup # # If you want to override with environment parameter follow parameter naming SECURITY_INITIALLOGIN_USERNAME # ############################################################################################################# security: enableLogin: true # set to 'true' to enable login loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1 loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts loginMethod: all # Accepts values like 'all' and 'normal'(only Login with Username/Password), 'oauth2'(only Login with OAuth2) or 'saml2'(only Login with SAML2) initialLogin: username: "" # initial username for the first login password: "" # initial password for the first login oauth2: enabled: false # set to 'true' to enable login (Note: enableLogin must also be 'true' for this to work) debugLogging: false # set to 'true' to log full ID token and UserInfo claims during OAuth2/OIDC login. Use this to diagnose claim issues (e.g. "Attribute value for 'email' cannot be null" with ADFS). WARNING: writes PII (sub, email, name) to logs; disable after troubleshooting. client: keycloak: issuer: "" # URL of the Keycloak realm's OpenID Connect Discovery endpoint clientId: "" # client ID for Keycloak OAuth2 clientSecret: "" # client secret for Keycloak OAuth2 scopes: openid, profile, email # scopes for Keycloak OAuth2 useAsUsername: preferred_username # field to use as the username for Keycloak OAuth2. Available options are: [email | name | given_name | family_name | preferred_name] google: clientId: "" # client ID for Google OAuth2 clientSecret: "" # client secret for Google OAuth2 scopes: email, profile # scopes for Google OAuth2 useAsUsername: email # field to use as the username for Google OAuth2. Available options are: [email | name | given_name | family_name] github: clientId: "" # client ID for GitHub OAuth2 clientSecret: "" # client secret for GitHub OAuth2 scopes: read:user # scope for GitHub OAuth2 useAsUsername: login # field to use as the username for GitHub OAuth2. Available options are: [email | login | name] issuer: "" # set to any Provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) endpoint clientId: "" # client ID from your Provider clientSecret: "" # client secret from your Provider autoCreateUser: true # set to 'true' to allow auto-creation of non-existing users blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin useAsUsername: email # default is 'email'; custom fields can be used as the username scopes: openid, profile, email # specify the scopes for which the application will request permissions provider: google # set this to your OAuth Provider's name, e.g., 'google' or 'keycloak' saml2: enabled: false # Only enabled for paid enterprise clients (enterpriseEdition.enabled must be true) provider: "" # The name of your Provider autoCreateUser: true # set to 'true' to allow auto-creation of non-existing users blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin registrationId: stirling # The name of your Service Provider (SP) app name. Should match the name in the path for your SSO & SLO URLs idpMetadataUri: https://dev-XXXXXXXX.okta.com/app/externalKey/sso/saml/metadata # The uri for your Provider's metadata idpSingleLoginUrl: https://dev-XXXXXXXX.okta.com/app/dev-XXXXXXXX_stirlingpdf_1/externalKey/sso/saml # The URL for initiating SSO. Provided by your Provider idpSingleLogoutUrl: https://dev-XXXXXXXX.okta.com/app/dev-XXXXXXXX_stirlingpdf_1/externalKey/slo/saml # The URL for initiating SLO. Provided by your Provider idpIssuer: "" # The ID of your Provider idpCert: classpath:okta.cert # The certificate your Provider will use to authenticate your app's SAML authentication requests. Provided by your Provider privateKey: classpath:saml-private-key.key # Your private key. Generated from your keypair spCert: classpath:saml-public-cert.crt # Your signing certificate. Generated from your keypair # IMPORTANT: For SAML setup, download your SP metadata from the BACKEND URL: http://localhost:8080/saml2/service-provider-metadata/{registrationId} # Do NOT use the frontend dev server URL (localhost:5173) as it will generate incorrect ACS URLs. Always use the backend URL (localhost:8080) for SAML configuration. jwt: # This feature is currently under development and not yet fully supported. Do not use in production. persistence: true # Set to 'true' to enable JWT key store enableKeyRotation: true # Set to 'true' to enable key pair rotation enableKeyCleanup: true # Set to 'true' to enable key pair cleanup tokenExpiryMinutes: 1440 # JWT access token lifetime in minutes for web clients (1 day). desktopTokenExpiryMinutes: 43200 # JWT access token lifetime in minutes for desktop clients (30 days). allowedClockSkewSeconds: 60 # Allowed JWT validation clock skew in seconds to tolerate small client/server time drift. refreshGraceMinutes: 15 # Allow refresh using an expired access token only within this many minutes after expiry. validation: # PDF signature validation settings trust: serverAsAnchor: true # Trust server certificate as anchor for PDF signatures (if configured and self-signed or CA) useSystemTrust: true # Trust Java/OS system trust store for PDF signature validation useMozillaBundle: true # Trust bundled Mozilla CA bundle (~140 CAs) for PDF signature validation useAATL: false # Trust Adobe Approved Trust List (AATL) for PDF signature validation - downloads from Adobe on startup if enabled useEUTL: false # Trust EU Trusted List (EUTL) for eIDAS qualified certificates - downloads LOTL and national TSLs on startup if enabled allowAIA: false # Allow JDK to fetch issuer certificates and revocation information from network (OCSP/CRL/AIA) aatl: url: https://trustlist.adobe.com/tl.pdf # Adobe Approved Trust List download URL eutl: lotlUrl: https://ec.europa.eu/tools/lotl/eu-lotl.xml # EU List Of Trusted Lists (LOTL) URL acceptTransitional: false # Accept certificates with 'supervisionincessation' status (transitional state) revocation: mode: none # Revocation checking mode: 'none' (disabled), 'ocsp' (OCSP only), 'crl' (CRL only), 'ocsp+crl' (OCSP with CRL fallback) hardFail: false # Fail validation if revocation status cannot be determined (true=strict, false=soft-fail) timestamp: defaultTsaUrl: http://timestamp.digicert.com # Default TSA server for RFC 3161 document timestamps customTsaUrls: [] # Admin-configured additional TSA URLs (e.g. ['https://internal-tsa.corp.com/timestamp']). Users can only select from built-in presets and these URLs. xFrameOptions: DENY # X-Frame-Options header value. Options: 'DENY' (default, prevents all framing), 'SAMEORIGIN' (allows framing from same domain), 'DISABLED' (no X-Frame-Options header sent). Note: automatically set to DISABLED when login is disabled premium: key: 00000000-0000-0000-0000-000000000000 enabled: false # Enable license key checks for pro/enterprise features proFeatures: ssoAutoLogin: false customMetadata: autoUpdateMetadata: false author: username creator: Stirling-PDF producer: Stirling-PDF googleDrive: enabled: false # Enable Google Drive file picker integration clientId: "" # Google OAuth 2.0 client ID (obtain from Google Cloud Console) apiKey: "" # Google API key for Google Picker API (obtain from Google Cloud Console) appId: "" # Google Drive app ID enterpriseFeatures: audit: enabled: true # Enable audit logging for security and compliance tracking level: 2 # Audit logging level: 0=OFF, 1=BASIC (compress/split/merge/etc and settings), 2=STANDARD (BASIC + user actions, excludes polling), 3=VERBOSE (everything including polling). retentionDays: 90 # Number of days to retain audit logs (0 or negative = infinite retention) captureFileHash: false # Capture SHA-256 hash of uploaded/processed files. Warning: adds 50-200ms per file depending on size. Only enabled independently of audit level. capturePdfAuthor: false # Capture author metadata from PDF documents. Warning: requires PDF parsing which increases processing time. Only enabled independently of audit level. captureOperationResults: false # Capture operation return values and responses in audit log. Warning: not recommended, significantly increases log volume and disk usage. Use only for debugging. databaseNotifications: backups: successful: false # set to 'true' to enable email notifications for successful database backups failed: false # set to 'true' to enable email notifications for failed database backups imports: successful: false # set to 'true' to enable email notifications for successful database imports failed: false # set to 'true' to enable email notifications for failed database imports mail: enabled: false # set to 'true' to enable sending emails enableInvites: false # set to 'true' to enable email invites for user management (requires mail.enabled and security.enableLogin) host: smtp.example.com # SMTP server hostname port: 587 # SMTP server port username: "" # SMTP server username password: "" # SMTP server password from: "" # sender email address startTlsEnable: true # enable STARTTLS (explicit TLS upgrade after connecting) when supported by the SMTP server startTlsRequired: false # require STARTTLS; connection fails if the upgrade command is not supported sslEnable: false # enable SSL/TLS wrapper for implicit TLS (typically used with port 465) sslTrust: "" # optional trusted host override, e.g. "smtp.example.com" or "*"; defaults to "*" (trust all) when empty sslCheckServerIdentity: false # enable hostname verification when using SSL/TLS telegram: enabled: false # set to 'true' to enable Telegram bot integration botToken: "" # Telegram bot token obtained from BotFather botUsername: "" # Telegram bot username (without @) pipelineInboxFolder: telegram # Name of the pipeline inbox folder for Telegram uploads customFolderSuffix: true # set to 'true' to allow users to specify custom target folders via UserID enableAllowUserIDs: true # set to 'true' to restrict access to specific Telegram user IDs allowUserIDs: [] # List of allowed Telegram user IDs (e.g. [123456789, 987654321]). Leave empty to allow all users. enableAllowChannelIDs: true # set to 'true' to restrict access to specific Telegram channel IDs allowChannelIDs: [] # List of allowed Telegram channel IDs (e.g. [-1001234567890, -1009876543210]). Leave empty to allow all channels. processingTimeoutSeconds: 180 # Maximum time in seconds to wait for processing a Telegram request pollingIntervalMillis: 2000 # Interval in milliseconds between polling for new messages feedback: channel: noValidDocument: true # set to 'false' to hide/suppress feedback messages in channels (to avoid spam) errorProcessing: true # set to 'false' to hide/suppress feedback messages in channels (to avoid spam) errorMessage: true # set to 'false' to hide/suppress error messages in channels (to avoid spam) processing: true # set to 'false' to hide/suppress processing messages in channels (to avoid spam) user: noValidDocument: true # set to 'false' to hide/suppress feedback messages to users (to avoid spam) errorProcessing: true # set to 'false' to hide/suppress feedback messages to users (to avoid spam) errorMessage: true # set to 'false' to hide/suppress error messages to users (to avoid spam) processing: true # set to 'false' to hide/suppress processing messages to users (to avoid spam) legal: termsAndConditions: https://www.stirling.com/legal/terms-of-service # URL to the terms and conditions of your application (e.g. https://example.com/terms). Empty string to disable or filename to load from local file in static folder privacyPolicy: https://www.stirling.com/legal/privacy-policy # URL to the privacy policy of your application (e.g. https://example.com/privacy). Empty string to disable or filename to load from local file in static folder accessibilityStatement: "" # URL to the accessibility statement of your application (e.g. https://example.com/accessibility). Empty string to disable or filename to load from local file in static folder cookiePolicy: "" # URL to the cookie policy of your application (e.g. https://example.com/cookie). Empty string to disable or filename to load from local file in static folder impressum: "" # URL to the impressum of your application (e.g. https://example.com/impressum). Empty string to disable or filename to load from local file in static folder system: defaultLocale: en-US # set the default language (e.g. 'de-DE', 'fr-FR', etc) googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow enableAlphaFunctionality: false # set to enable functionality which might need more testing before it fully goes live (this feature might make no changes) showUpdate: false # see when a new update is available showUpdateOnlyAdmin: false # only admins can see when a new update is available, depending on showUpdate it must be set to 'true' showSettingsWhenNoLogin: true # set to 'false' to hide settings button when login is disabled (enableLogin: false). Only applies when login is disabled. customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template HTML files tessdataDir: "" # path to the directory containing the Tessdata files. This setting is relevant for Windows systems. For Windows users, this path should be adjusted to point to the appropriate directory where the Tessdata files are stored. enableAnalytics: null # Master toggle for analytics: set to 'true' to enable all analytics, 'false' to disable all analytics, or leave as 'null' to prompt admin on first launch enableDesktopInstallSlide: true # Set to 'false' to hide the desktop app installation slide in the onboarding flow enablePosthog: null # Enable PostHog analytics (open-source product analytics): set to 'true' to enable, 'false' to disable, or 'null' to enable by default when analytics is enabled enableScarf: null # Enable Scarf tracking pixel: set to 'true' to enable, 'false' to disable, or 'null' to enable by default when analytics is enabled enableUrlToPDF: false # Set to 'true' to enable URL to PDF, INTERNAL ONLY, known security issues, should not be used externally disableSanitize: false # set to true to disable Sanitize HTML; (can lead to injections in HTML) maxDPI: 500 # Maximum allowed DPI for PDF to image conversion corsAllowedOrigins: [] # List of allowed origins for CORS (e.g. ['http://localhost:5173', 'https://app.example.com']). Leave empty to disable CORS. For local development with frontend on port 5173, add 'http://localhost:5173' backendUrl: "" # Backend base URL for SAML/OAuth/API callbacks (e.g. 'http://localhost:8080' for dev, 'https://api.example.com' for production). REQUIRED for SSO authentication to work correctly. This is where your IdP will send SAML responses and OAuth callbacks. Leave empty to default to 'http://localhost:8080' in development. frontendUrl: "" # Frontend URL for invite email links (e.g. 'https://app.example.com'). Optional - if not set, will use backendUrl. This is the URL users click in invite emails. enableMobileScanner: true # Enable mobile phone QR code upload feature. Requires frontendUrl to be configured. mobileScannerSettings: convertToPdf: true # Automatically convert uploaded images to PDF format. If false, images are kept as-is. imageResolution: full # Image resolution for mobile uploads: 'full' (original size) or 'reduced' (max 1200px on longest side). Only applies when convertToPdf is true. pageFormat: A4 # Page format for converted PDFs: 'keep' (original image dimensions), 'A4' (A4 page size), or 'letter' (US Letter page size). Only applies when convertToPdf is true. stretchToFit: false # Whether to stretch images to fill the entire page (may distort aspect ratio). If false, images are centered with preserved aspect ratio. Only applies when convertToPdf is true. serverCertificate: enabled: true # Enable server-side certificate for "Sign with Stirling-PDF" option organizationName: Stirling-PDF # Organization name for generated certificates validity: 365 # Certificate validity in days regenerateOnStartup: false # Generate new certificate on each startup html: urlSecurity: enabled: true # Enable URL security restrictions for HTML processing level: MEDIUM # Security level: MAX (whitelist only), MEDIUM (block internal networks), OFF (no restrictions) allowedDomains: [] # Whitelist of allowed domains (e.g. ['cdn.example.com', 'images.google.com']) blockedDomains: [] # Additional domains to block (e.g. ['evil.com', 'malicious.org']) internalTlds: [".local", ".internal", ".corp", ".home"] # Block domains with these TLD patterns blockPrivateNetworks: true # Block RFC 1918 private networks (10.x.x.x, 192.168.x.x, 172.16-31.x.x) blockLocalhost: true # Block localhost and loopback addresses (127.x.x.x, ::1) blockLinkLocal: true # Block link-local addresses (169.254.x.x, fe80::/10) blockCloudMetadata: true # Block cloud provider metadata endpoints (169.254.169.254) datasource: enableCustomDatabase: false # Enterprise users ONLY, set this property to 'true' if you would like to use your own custom database configuration customDatabaseUrl: "" # eg jdbc:postgresql://localhost:5432/postgres, set the url for your own custom database connection. If provided, the type, hostName, port and name are not necessary and will not be used username: postgres # set the database username password: postgres # set the database password type: postgresql # the type of the database to set (e.g. 'h2', 'postgresql') hostName: localhost # the host name to use for the database url. Set to 'localhost' when running the app locally. Set to match the name of the container name of your database container when running the app on a server (Docker configuration) port: 5432 # set the port number of the database. Ensure this matches the port the database is listening to name: postgres # set the name of your database. Should match the name of the database you create customPaths: pipeline: pipelineDir: "" # Defaults to /pipeline watchedFoldersDir: "" # Defaults to /pipeline/watchedFolders watchedFoldersDirs: [] # List of watched folder directories. Defaults to watchedFoldersDir or /pipeline/watchedFolders. finishedFoldersDir: "" # Defaults to /pipeline/finishedFolders operations: weasyprint: "" # Defaults to /opt/venv/bin/weasyprint unoconvert: "" # Defaults to /opt/venv/bin/unoconvert calibre: "" # Defaults to /usr/bin/ebook-convert ocrmypdf: "" # Defaults to /usr/bin/ocrmypdf soffice: "" # Defaults to /usr/bin/soffice fileUploadLimit: "" # Defaults to "". No limit when string is empty. Set a number, between 0 and 999, followed by one of the following strings to set a limit. "KB", "MB", "GB". tempFileManagement: baseTmpDir: "" # Defaults to java.io.tmpdir/stirling-pdf libreofficeDir: "" # Defaults to tempFileManagement.baseTmpDir/libreoffice systemTempDir: "" # Only used if cleanupSystemTemp is true prefix: stirling-pdf- # Prefix for temp file names maxAgeHours: 24 # Maximum age in hours before temp files are cleaned up cleanupIntervalMinutes: 30 # How often to run cleanup (in minutes) startupCleanup: true # Clean up old temp files on startup cleanupSystemTemp: false # Whether to clean broader system temp directory databaseBackup: cron: "0 0 0 * * ?" # Cron expression for automatic database backups "0 0 0 * * ?" daily at midnight storage: enabled: false # set to 'true' to allow users to store files on the server (requires security.enableLogin) [ALPHA] provider: local # storage provider: 'local' for filesystem storage, 'database' for DB-backed storage local: basePath: './storage' # base directory for stored files # ==================================================================================== # S3-COMPATIBLE OBJECT STORAGE - PRO / ENTERPRISE LICENSE REQUIRED # storage.provider=s3, storage.provider=database, and cluster.artifactStore=s3 all # require a valid Pro or Enterprise license. # ==================================================================================== # Used when provider=s3 (persistent user uploads) and/or cluster.artifactStore=s3 # (transient cluster artifacts). The two consumers share this block. # Vendor cheat sheet (set the highlighted flags to taste): # AWS S3 -> endpoint='' region='' pathStyleAccess=false # Cloudflare R2 -> endpoint='https://.r2.cloudflarestorage.com' region='auto' # pathStyleAccess=false; if uploads fail with 'unsupported header # x-amz-checksum-*' set requestChecksumCalculation=WHEN_REQUIRED # Supabase Storage -> endpoint='https://.supabase.co/storage/v1/s3' # region='' pathStyleAccess=true # (filenames with non-ASCII display fine - the storage key is opaque) # MinIO (in-cluster) -> endpoint='http://minio:9000' region='us-east-1' # pathStyleAccess=true allowPrivateEndpoints=true # Backblaze B2 -> endpoint='https://s3..backblazeb2.com' # If on a B2 deployment older than July-2025 and uploads return # 'Unsupported header x-amz-checksum-crc32', set # requestChecksumCalculation=WHEN_REQUIRED # DigitalOcean Spaces -> endpoint='https://.digitaloceanspaces.com' # Note: 5GB per-object cap (regardless of multipart) s3: endpoint: "" # blank = use AWS regional default; otherwise full URL incl. https:// bucket: "" # required when provider=s3 or cluster.artifactStore=s3 region: us-east-1 accessKey: "" # blank = fall back to AWS DefaultCredentialsProvider (env / profile / IMDS) secretKey: "" pathStyleAccess: false # true for MinIO and Supabase; false for AWS/R2/most CDNs allowPrivateEndpoints: false # true required when endpoint resolves to a private/loopback IP (e.g. in-cluster MinIO). SSRF guard - leave false for any internet-facing vendor. requestChecksumCalculation: WHEN_SUPPORTED # WHEN_SUPPORTED|WHEN_REQUIRED|DISABLED. Set WHEN_REQUIRED if your vendor rejects auto-added x-amz-checksum-* headers (older Backblaze B2, some R2 corner cases). responseChecksumValidation: WHEN_SUPPORTED # WHEN_SUPPORTED|WHEN_REQUIRED|DISABLED. Set WHEN_REQUIRED if you see false-positive checksum-mismatch errors on GET from a vendor that never returns checksum headers. quotas: maxStorageMbPerUser: -1 # Max storage per user in MB; -1 disables per-user cap maxStorageMbTotal: -1 # Max storage across all users in MB; -1 disables total cap maxFileMb: -1 # Max size per stored file (including history/audit) in MB; -1 disables limit sharing: enabled: false # set to 'true' to enable file sharing features [ALPHA] linkEnabled: true # set to 'false' to disable share links (requires system.frontendUrl) emailEnabled: false # set to 'true' to allow sharing by email (requires mail.enabled) linkExpirationDays: 3 # Number of days before share links expire signing: enabled: false # set to 'true' to enable group signing workflow (requires storage.enabled) [ALPHA] autoPipeline: outputFolder: "" # Output folder for processed pipeline files (leave empty for default) fileReadiness: enabled: true # Set to 'false' to skip all readiness checks and process files immediately (legacy behaviour) settleTimeMillis: 5000 # How long (ms) a file must be unmodified before it is considered fully written and stable. Default: 5000 (5 seconds) sizeCheckDelayMillis: 500 # Pause (ms) between two file-size reads used to detect active writes (Linux/macOS mid-copy detection). Default: 500 allowedExtensions: [] # Optional extension allow-list (case-insensitive, without the leading dot). Empty list = accept all extensions. Example: ["pdf", "tiff"] ui: appNameNavbar: "" # name displayed on the navigation bar logoStyle: classic # Options: 'classic' (default - classic S icon) or 'modern' (minimalist logo) languages: [] # If empty, all languages are enabled. To restrict to specific languages, use a whitelist like ["de_DE", "pl_PL", "sv_SE"]. Empty list or not restricting any languages will enable all available languages. defaultHideUnavailableTools: false # Default user preference: hide disabled tools instead of greying them out defaultHideUnavailableConversions: false # Default user preference: hide disabled conversion options instead of greying them out hideDisabledTools: googleDrive: false # Hide Google Drive button when not enabled mobileQRScanner: false # Hide mobile QR scanner button when not enabled endpoints: toRemove: [] # list endpoints to disable (e.g. ['img-to-pdf', 'remove-pages']) groupsToRemove: [] # list groups to disable (e.g. ['LibreOffice', 'DeveloperTools', 'DeveloperDocs', 'Automation']) metrics: enabled: true # 'true' to enable Info APIs (`/api/*`) endpoints, 'false' to disable # Automatically Generated Settings (Do Not Edit Directly) AutomaticallyGenerated: key: example UUID: example appVersion: 0.35.0 processExecutor: autoUnoServer: true # true: use local pool based on libreOfficeSessionLimit; false: use unoServerEndpoints unoServerEndpoints: [] # Used when autoUnoServer is false # Example manual endpoints (uncomment to use): # unoServerEndpoints: # - host: "127.0.0.1" # port: 2003 # hostLocation: "auto" # auto|local|remote (use "remote" for port-forwarded servers) # protocol: "http" # http|https # - host: "remote-server.local" # port: 8080 # hostLocation: "remote" # protocol: "https" sessionLimit: # Process executor instances limits libreOfficeSessionLimit: 1 # Each additional uno server adds ~50MB idle RAM pdfToHtmlSessionLimit: 1 qpdfSessionLimit: 4 tesseractSessionLimit: 1 pythonOpenCvSessionLimit: 8 weasyPrintSessionLimit: 16 installAppSessionLimit: 1 calibreSessionLimit: 1 imageMagickSessionLimit: 4 ghostscriptSessionLimit: 8 ocrMyPdfSessionLimit: 2 timeoutMinutes: # Process executor timeout in minutes libreOfficetimeoutMinutes: 30 pdfToHtmltimeoutMinutes: 20 pythonOpenCvtimeoutMinutes: 30 weasyPrinttimeoutMinutes: 30 installApptimeoutMinutes: 60 calibretimeoutMinutes: 30 imageMagickTimeoutMinutes: 30 tesseractTimeoutMinutes: 30 qpdfTimeoutMinutes: 30 ghostscriptTimeoutMinutes: 30 ocrMyPdfTimeoutMinutes: 30 aiEngine: enabled: false # Set to 'true' to enable the AI engine integration url: http://localhost:5001 # URL of the Python AI engine timeoutSeconds: 120 # Timeout in seconds for AI engine requests policies: # Folder automations can read from and write to the directories you allow here, so treat this as a # security boundary. Leave allowedFolderRoots empty (default) to disable folder sources/outputs # entirely; list absolute directories to permit folder access only within them. Stirling's own # config directory is always off-limits, and folder access is always disabled in SaaS mode. allowedFolderRoots: [] # e.g. ["/data/inbox", "/data/outbox"] scheduleSweepSeconds: 60 # How often (seconds) scheduled policies are checked for being due watchReconcileSeconds: 300 # How often (seconds) folder-watch re-syncs watches and re-runs as a safety net for missed events watchQuietPeriodMs: 500 # How long (ms) folder-watch coalesces a burst of file events into a single run streamTimeoutMs: 1800000 # SSE timeout (ms) for live run-progress streams runExpiryMinutes: 30 # How long (minutes) a finished run's in-memory state is kept before eviction # Model Context Protocol (MCP) server. Exposes Stirling's PDF tools (grouped by namespace) # plus the AI agents to MCP clients (Inspector, Claude Desktop, custom). OAuth-protected. # Disabled by default - enable explicitly per deployment after configuring mcp.auth. mcp: enabled: false # Master switch. 'false' (default) means no /mcp endpoint, no metadata, no beans wired. scopesEnabled: true # Enforce mcp.tools.read / mcp.tools.write scopes derived from operation category allowedOperations: [] # Tool allow-list (operation ids, e.g. ['compress-pdf']). Empty = all. When set, ONLY these are exposed over MCP. blockedOperations: [] # Tool deny-list (operation ids). Always removed from MCP even if otherwise allowed. auth: mode: oauth # 'oauth' (full OAuth2 resource server) or 'apikey' (Stirling per-user API key via X-API-KEY header; no external IdP needed - the low-friction self-host option) issuerUri: "" # OAuth2 issuer URI (e.g. http://localhost:9000). Required when mode=oauth. jwksUri: "" # JWKS URI. Blank -> derived from issuer's /.well-known/openid-configuration. resourceId: "" # RFC 8707 resource identifier of THIS MCP server (e.g. http://localhost:8080/mcp). # Required: tokens must list this id in `aud` or the request is rejected. acceptedAudiences: [] # Extra `aud` values accepted on top of resourceId. Empty = strict RFC 8707. # For IdPs that cannot mint resource audiences (Supabase OAuth server always # issues aud=authenticated) list that audience here, e.g. ['authenticated']. usernameClaim: sub # JWT claim matched against a Stirling username (e.g. 'sub', 'email', 'preferred_username') requireExistingAccount: true # Reject tokens whose subject has no enabled Stirling account (recommended) engineCapabilityRefreshMinutes: 5 # How often to refresh the AI capabilities manifest from the engine # Cluster configuration. NOT YET ENABLED - scaffolding for later work. Leave at defaults. cluster: enabled: false # Master switch. 'false' (default) wires the in-process backplane and skips all cluster checks. Single-instance installs do not need to change anything here. backplane: inprocess # Backplane implementation: 'inprocess' (single JVM only) or 'valkey' (multi-node via Valkey/Redis) artifactStore: local # Transient cluster job-artifact backend: 'local' (per-node disk; single-node only) or 's3' (shared object store; required for multi-node). Distinct from 'storage.provider' which controls persistent user uploads - when both are 's3' they share the storage.s3.* credentials block. Multi-node deployments MUST set this to 's3'. s3: keyPrefix: transient/ # Bucket key prefix used by the cluster artifact store when artifactStore=s3. Trailing slash recommended. Lets a single bucket host both persistent uploads (storage.s3.*) and transient job artifacts under separate prefixes. valkey: url: "" # Valkey/Redis URL, e.g. 'redis://valkey:6379' or 'rediss://...' for TLS. Required when enabled=true and backplane=valkey. tls: skipCertVerification: false # set to 'true' to skip TLS certificate verification on Valkey connections (dev/test only) node: id: "" # Optional explicit node id. Blank = auto-generated UUID at startup. role: both # 'web' (serves HTTP), 'worker' (runs jobs), or 'both' (default) internalAddress: "" # host:port advertised in the instance registry for peer-to-peer cluster traffic. Blank = derived at startup. scheme: http # 'http' or 'https' - scheme peers use to call this node's /internal/cluster/** endpoints heartbeatIntervalMs: 5000 # Heartbeat publish interval for the instance registry (ms) pdfEditor: fallback-font: classpath:/static/fonts/NotoSans-Regular.ttf # Override to point at a custom fallback font cache: max-bytes: -1 # Max in-memory cache size in bytes; -1 disables byte cap max-percent: 20 # Max in-memory cache as % of JVM max; used when max-bytes <= 0 font-normalization: enabled: false # IMPORTANT: Disable to preserve ToUnicode CMaps for correct font rendering. Ghostscript strips Unicode mappings from CID fonts. cff-converter: enabled: true # Wrap CFF/Type1CFF fonts as OpenType-CFF for browser compatibility method: python # Converter method: 'python' (fontTools, recommended - wraps as OTF), 'fontforge' (legacy - converts to TTF, may hang on CID fonts) python-command: /opt/venv/bin/python3 # Python interpreter path python-script: /scripts/convert_cff_to_ttf.py # Path to font wrapping script fontforge-command: fontforge # Override if FontForge is installed under a different name/path type3: library: enabled: true # Match common Type3 fonts against the built-in library of converted programs index: classpath:/type3/library/index.json # Override to point at a custom index.json (supports http:, file:, classpath:)