TLS/SSL Configuration

Tika Server supports TLS for encrypted communication, in two flavours:

  • 1-way TLS — the server presents its certificate; clients verify the server.

  • 2-way TLS (mTLS) — both sides present certificates and authenticate each other.

Should you configure TLS here at all?

For most deployments, put Tika Server behind a reverse proxy (nginx, Apache httpd, Traefik) that terminates TLS, and run Tika itself on plain HTTP on localhost or a private network. That simplifies certificate management and gives you rate limiting and authentication for free. Tika Server has no built-in token support, so JWT / API-key / OAuth2 authentication has to come from a proxy or API gateway anyway.

Configure TLS directly on Tika Server (the rest of this page) when you cannot use a proxy, need client-certificate authentication, or prefer a single-process deployment. If you only need to restrict access and not encrypt it, network controls — binding to localhost, firewall rules, a private subnet — are simpler than either.

Quick Start

TLS settings live in tlsConfig inside the server section of tika-config.json. Pass the file with -c/--config.

1-Way TLS

Server authenticates to clients; clients present no certificate.

{
  "server": {
    "host": "localhost",
    "port": 9998,
    "tlsConfig": {
      "active": true,
      "keyStoreType": "PKCS12",
      "keyStoreFile": "/path/to/server-keystore.p12",
      "keyStorePassword": "your-password",
      "clientAuthenticationWanted": false,
      "clientAuthenticationRequired": false
    }
  }
}

2-Way TLS (mTLS)

Add a truststore holding the client certificates you trust, and require client authentication.

{
  "server": {
    "host": "localhost",
    "port": 9998,
    "tlsConfig": {
      "active": true,
      "keyStoreType": "PKCS12",
      "keyStoreFile": "/path/to/server-keystore.p12",
      "keyStorePassword": "your-password",
      "trustStoreType": "PKCS12",
      "trustStoreFile": "/path/to/server-truststore.p12",
      "trustStorePassword": "your-password",
      "clientAuthenticationWanted": true,
      "clientAuthenticationRequired": true
    }
  }
}

Configuration Reference

All properties below go in server.tlsConfig.

Property Type Default Description

active

boolean

false

Enable TLS. When true, the server serves HTTPS.

keyStoreType

string

null

Keystore format: PKCS12 (recommended) or JKS.

keyStoreFile

string

null

Path to the server’s keystore, holding its private key and certificate.

keyStorePassword

string

null

Password for the keystore.

trustStoreType

string

null

Truststore format: PKCS12 (recommended) or JKS.

trustStoreFile

string

null

Path to the truststore holding trusted client certificates (2-way TLS).

trustStorePassword

string

null

Password for the truststore.

clientAuthenticationWanted

boolean

false

Request client certificates but do not require them; clients without one still connect.

clientAuthenticationRequired

boolean

false

Require a client certificate trusted by the server.

includedProtocols

list

["TLSv1.2", "TLSv1.3"]

TLS versions to enable. TLS 1.0 and 1.1 are insecure and off by default.

excludedProtocols

list

null

TLS versions to explicitly disable.

includedCipherSuites

list

null

Cipher suites to enable. Null means JVM defaults.

excludedCipherSuites

list

null

Cipher suites to disable. Entries are regular expressions.

certExpirationWarningDays

integer

30

Days before certificate expiration to log a warning. 0 disables the check.

When active is true, keyStoreType, keyStoreFile and keyStorePassword are all required. Truststore properties are all-or-nothing: set all three or none.

Restricting protocols and cipher suites

Add to server.tlsConfig — for example, TLS 1.3 only:

"includedProtocols": ["TLSv1.3"]

An explicit allowlist of cipher suites:

"includedCipherSuites": [
  "TLS_AES_256_GCM_SHA384",
  "TLS_AES_128_GCM_SHA256",
  "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
  "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]

Or a denylist of weak ones, as regular expressions:

"excludedCipherSuites": [".*CBC.*", ".*RC4.*", ".*3DES.*", ".*NULL.*"]

Certificate Expiration Warnings

At startup, Tika Server checks every certificate in the configured stores and logs:

  • ERROR — already expired, or not yet valid; TLS will fail.

  • WARN — expires within certExpirationWarningDays (default 30).

  • DEBUG — valid.

WARN  TlsConfig - Certificate 'server' in keystore expires in 15 days on Sat Feb 15 12:00:00 UTC 2026. Consider renewing soon.
ERROR TlsConfig - Certificate 'server' in keystore has EXPIRED on Mon Jan 01 12:00:00 UTC 2026. TLS connections will fail!

Set "certExpirationWarningDays": 60 to warn earlier, or 0 to disable the check entirely.

Generating Test Certificates

Self-signed certificates for testing only. In production use certificates from a trusted CA.

# Server key pair, and its certificate for clients to trust
keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -validity 365 \
  -keystore server-keystore.p12 -storetype PKCS12 -storepass changeit \
  -dname "CN=localhost,OU=Tika,O=Apache,L=Unknown,ST=Unknown,C=US"
keytool -exportcert -alias server -keystore server-keystore.p12 \
  -storetype PKCS12 -storepass changeit -file server.crt

# Client key pair (2-way TLS only), and its certificate for the server to trust
keytool -genkeypair -alias client -keyalg RSA -keysize 2048 -validity 365 \
  -keystore client-keystore.p12 -storetype PKCS12 -storepass changeit \
  -dname "CN=TikaClient,OU=Tika,O=Apache,L=Unknown,ST=Unknown,C=US"
keytool -exportcert -alias client -keystore client-keystore.p12 \
  -storetype PKCS12 -storepass changeit -file client.crt

# Truststores: the server trusts the client cert, the client trusts the server cert
keytool -importcert -alias client -file client.crt -noprompt \
  -keystore server-truststore.p12 -storetype PKCS12 -storepass changeit
keytool -importcert -alias server -file server.crt -noprompt \
  -keystore client-truststore.p12 -storetype PKCS12 -storepass changeit

Testing

# 1-way TLS: trust the server certificate
curl --cacert server.crt https://localhost:9998/tika

# 2-way TLS: also present a client certificate
curl --cacert server.crt --cert client.crt --key client-key.pem \
     https://localhost:9998/tika

# Self-signed, throwaway testing only -- skips verification entirely
curl -k https://localhost:9998/tika

From Java:

// 2-way TLS
SSLContext sslContext = SSLContexts.custom()
    .loadKeyMaterial(
        new File("client-keystore.p12"),
        "changeit".toCharArray(),
        "changeit".toCharArray())
    .loadTrustMaterial(
        new File("client-truststore.p12"),
        "changeit".toCharArray())
    .build();

HttpClient client = HttpClients.custom()
    .setSSLContext(sslContext)
    .build();

HttpResponse response = client.execute(new HttpGet("https://localhost:9998/tika"));

Containers

Mount the config file and the keystores into the container, and point -c at the config. The paths in tlsConfig are container paths, not host paths.

docker run -d --name tika-server -p 9998:9998 \
  -v $(pwd)/config:/tika/config:ro \
  -v $(pwd)/certs:/tika/certs:ro \
  apache/tika:<version> \
  -c /tika/config/tika-config.json

With /tika/config/tika-config.json holding, for example:

{
  "server": {
    "port": 9998,
    "tlsConfig": {
      "active": true,
      "keyStoreType": "PKCS12",
      "keyStoreFile": "/tika/certs/server-keystore.p12",
      "keyStorePassword": "your-password",
      "trustStoreType": "PKCS12",
      "trustStoreFile": "/tika/certs/server-truststore.p12",
      "trustStorePassword": "your-password",
      "clientAuthenticationRequired": true
    }
  }
}
The official image’s entrypoint already passes -h 0.0.0.0, so the container listens on all interfaces regardless of server.host.

Docker Compose

services:
  tika:
    image: apache/tika:latest
    ports:
      - "9998:9998"
    volumes:
      - ./config:/tika/config:ro
      - ./certs:/tika/certs:ro
    command: ["-c", "/tika/config/tika-config.json"]
    healthcheck:
      test: ["CMD", "curl", "-f", "--cacert", "/tika/certs/server.crt", "https://localhost:9998/tika"]
      interval: 30s
      timeout: 10s
      retries: 3

Kubernetes

kubectl create secret generic tika-tls-certs \
  --from-file=server-keystore.p12=./certs/server-keystore.p12 \
  --from-file=server-truststore.p12=./certs/server-truststore.p12
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tika-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tika
  template:
    metadata:
      labels:
        app: tika
    spec:
      containers:
      - name: tika
        image: apache/tika:latest
        ports:
        - containerPort: 9998
        args: ["-c", "/tika/config/tika-config.json"]
        volumeMounts:
        - name: config
          mountPath: /tika/config
          readOnly: true
        - name: certs
          mountPath: /tika/certs
          readOnly: true
      volumes:
      - name: config
        secret:
          secretName: tika-config
      - name: certs
        secret:
          secretName: tika-tls-certs

Keystore passwords

Tika reads keyStorePassword and trustStorePassword literally out of the JSON — it does not expand environment variables, ${…​} placeholders, or /run/secrets paths. Injecting the password as an env var does nothing on its own.

Treat the whole config file as the secret: store it as a Kubernetes Secret or a Docker secret and mount it read-only (as in the deployment above), rather than baking it into an image or committing it. If you need to assemble the password at run time, do it in your own entrypoint script, which writes the config file before starting the server.

Troubleshooting

Message Cause

must initialize keyStoreType / keyStoreFile / keyStorePassword

active is true but one of the three required keystore properties is missing.

keyStoreFile does not exist or is not a file

Wrong path. Absolute paths are safest; relative ones resolve against the working directory, which inside a container is not where you think it is.

Partial truststore configuration detected

Some but not all of trustStoreType, trustStoreFile, trustStorePassword are set. Set all three or none.

requiring client authentication, but no trust store has been specified

clientAuthenticationRequired is true with no truststore. The server needs one to verify client certificates.

SSL handshake failure

Expired or invalid certificate; the client does not trust the server’s certificate (1-way); the server does not trust the client’s (2-way); or no protocol/cipher suite in common.

For handshake detail, add -Djavax.net.debug=ssl:handshake to the JVM:

java -Djavax.net.debug=ssl:handshake -jar tika-server-standard-X.Y.Z.jar -c config.json

Security Best Practices

  • Use strong keystore and truststore passwords, and never commit them.

  • Stay on TLS 1.2/1.3 (the default) and restrict cipher suites to modern algorithms.

  • Prefer PKCS12 over JKS.

  • Use CA-issued certificates in production and rotate them before expiry.

  • Use 2-way TLS when clients need to be authenticated.

  • Protect keystore files with restrictive filesystem permissions.

See Also

  • Security — general security considerations

  • Robustness — process isolation and fault tolerance