The following provides an example of deploying SignServer to a Kubernetes cluster, integrating it with an external MariaDB database, and worker configuration for a production-ready setup.
Prerequisites
Before you begin, ensure the following are in place. See Prerequisites for full version requirements.
-
Kubernetes
v1.32+withkubectlconfigured -
Helm
v3+ -
A Certificate Authority, EJBCA or another CA, for infrastructure certificates (TLS, admin client auth) and signer certificates.
-
An external database for any non-ephemeral deployment (MariaDB, MySQL, PostgreSQL, Oracle, or SQL Server)
-
An HSM for production key storage. See HSM Integration for supported options.
To access the Admin Web, you need a client certificate installed in your browser. If you do not have one yet, follow Issue Client Authentication Certificate using EJBCA to get started.
If you want to verify your cluster setup before deploying, follow the Quick Test Deployment guide.
Step 1 - Fetch the Helm Chart
Pull the SignServer Community chart and unpack it locally so you can inspect and customize the default values:
helm pull oci://repo.keyfactor.com/charts/signserver-ce --untar
For SignServer Enterprise, use the Enterprise chart instead:
helm pull oci://repo.keyfactor.com/charts/signserver --untar
Step 2 - Create a Custom Values File
For any deployment beyond the ephemeral test, create a custom values file to configure SignServer for your environment:
helm show values signserver-ce > signserver.yaml
Edit signserver.yaml to add the configuration described in the sections below, then deploy with:
helm install signserver signserver-ce \
--namespace signserver \
--create-namespace \
--values signserver.yaml
Step 3 - Configure an External Database
All production deployments should use an external database. SignServer supports MariaDB/MySQL, PostgreSQL, Oracle, and SQL Server.
Disable the ephemeral H2 database and set the connection details in your values file:
MariaDB Example:
signserver:
useEphemeralH2Database: false
env:
DATABASE_JDBC_URL: jdbc:mariadb://mariadb-server:3306/signserverdb?characterEncoding=UTF-8
DATABASE_USER: signserver
DATABASE_PASSWORD: foo123
PostgreSQL Example using a Kubernetes Secret for Credentials:
signserver:
useEphemeralH2Database: false
env:
DATABASE_JDBC_URL: jdbc:postgresql://postgresql-server:5432/signserverdb
envRaw:
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: signserver-db-credentials
key: database_password
- name: DATABASE_USER
valueFrom:
secretKeyRef:
name: signserver-db-credentials
key: database_user
Using Kubernetes secrets for credentials is recommended over plaintext values in production. Bitnami Helm charts can deploy a database into your cluster if needed: PostgreSQL · MariaDB.
For more information, see Connect SignServer to External Database.
Step 4 - Configure a Reverse Proxy (Optional)
Options for using a reverse proxy include:
-
Built-in NGINX Reverse Proxy
-
External Reverse Proxy with AJP
-
External Reverse Proxy with HTTP Back-end Ports
-
TLS Termination
For configuration information, see Configure a Reverse Proxy in SignServer.
This example continues with the built-in NGINX reverse proxy.
Step 5 - Prepare Deployment Parameters
To deploy SignServer, first prepare the deployment parameters by creating a YAML configuration file, and then use the Helm Chart with your values file to install SignServer to a Kubernetes cluster.
Kubernetes has announced the retirement of Ingress NGINX. The ingress parameters remain available for backward compatibility, but are not recommended for new deployments. NGINX Reverse Proxy is the recommended replacement. See Configure a Reverse Proxy in SignServer.
Create an signserver.yaml configuration file with the following content. If using the built-in NGINX reverse proxy, make sure to create the Kubernetes secrets first. See Option A: Built in NGINX Reverse Proxy.
signserver:
useEphemeralH2Database: false
env:
DATABASE_JDBC_URL: "jdbc:mariadb://mariadb:3306/signserver?characterEncoding=utf8"
DATABASE_USER: signserver
envRaw:
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-passwords
key: mariadb-password
services:
proxyHttp:
enabled: true
type: ClusterIP
bindIP: 0.0.0.0
httpPort: 8081
httpsPort: 8082
nginx:
image: nginx:1.27.1
enabled: true
initializeWithSelfSignedTls: false
host: "signserverhost"
externalConfiguration:
# Server TLS credential for cluster internal communication
mountInternalNginxCert: true
secretInternalNginxCert: "managementca-secret"
service:
type: LoadBalancer
bindIP: 0.0.0.0
httpPort: 80
httpsPort: 443
# only relevant if multiple replicas
loadBalancerAccess:
enableStickySessionClientIp: false
# create a load balancer service for each Pod with separate IP address
enableReplicaSpecificAccess: false
additionalHosts:
#imagePullSecrets:
# - name: keyfactor-registry
For a description of the supported parameters, see SignServer Helm Deployment Parameters.
Customize Default Deploy Properties (Optional)
To customize the default deploy properties in your SignServer deployment, override the default properties by mounting in your own signserver_deploy.properties file version from a ConfigMap.
Note: Before version 7.8.0 the container bundles its own signserver_deploy.properties file containing some mandatory properties. To set one or more properties one would need to make sure to also include those mandatory properties. Since 7.8.0 it is enough to mount in a properties file with only the wanted properties.
-
(Required only for SignServer version before 7.8.0:)
Obtain the default properties file from/opt/keyfactor/signserver-custom/conf/signserver_deploy.propertieswithin the container and modify as needed. -
Create a ConfigMap with your custom properties file.
kubectl create configmap custom-signserver-deploy-properties --from-file=/path/to/signserver_deploy.properties -
Update your
values.yamlto mount the ConfigMap.Add the following configuration to mount the custom deploy properties file into the SignServer container:
YAMLsignserver: volumes: - name: signserver-deploy-properties configMap: name: custom-signserver-deploy-properties volumeMounts: - name: signserver-deploy-properties mountPath: /opt/keyfactor/signserver-custom/conf/signserver_deploy.properties subPath: signserver_deploy.properties
Configure OIDC (Optional)
OpenID Connect (OIDC) authentication for SignServer can be configured in two ways: by mounting an oidc.properties file from a ConfigMap, or by setting OIDC environment variables through Helm values. The two approaches can be combined. Environment variables take precedence over values in the mapped oidc.properties file and overwrite them when both are present.
For OIDC parameters, see SignServer Helm Deployment Parameters.
Option A - Configure OIDC Using a Properties File
-
Create or modify the
oidc.propertiesfile with the desired OIDC settings. -
Create a ConfigMap with the properties file.
kubectl create configmap signserver-oidc-properties --from-file=oidc.properties=/path/to/oidc.properties -
Update your
values.yamlto mount the ConfigMap.Add the following configuration to mount the OIDC properties file into the SignServer container:
YAMLsignserver: volumes: - name: signserver-oidc-properties configMap: name: signserver-oidc-properties volumeMounts: - name: signserver-oidc-properties mountPath: /opt/keyfactor/signserver/conf/oidc.properties subPath: oidc.properties
Notes:
-
The file is mounted as
oidc.propertiesin the container. -
You can add this mount alongside other configuration mounts.
-
Keep sensitive OIDC values in Kubernetes secrets where possible, and reference them from the properties file or environment variables as appropriate.
Option B - Configure OIDC Using Environment Variables
OIDC environment variables can be used to configure OpenID Connect authentication for SignServer through Helm values. These variables can be set in signserver.env, while sensitive values such as the client secret should preferably be provided through envRaw using a Kubernetes secret.
OIDC environment variables can be used alongside a mapped oidc.properties file. Values defined through Helm environment variables take precedence over values in the mapped oidc.properties file and overwrite them when both are present.
Step 6 - Deploy
Once your signserver.yaml is configured, use the Helm Chart with your values file to install SignServer to a Kubernetes cluster.
Community Edition:
helm install signserver-ce -f signserver.yaml \
oci://repo.keyfactor.com/charts/signserver-ce --version x.y.z
Enterprise Edition:
helm install signserver -f signserver.yaml \
oci://repo.keyfactor.com/charts/signserver --version x.y.z
Wait for the installation to finish. You can use the following command to monitor the pod creation process:
kubectl get pods -w -l app.kubernetes.io/instance=signserver
Proceed once all pods are ready (1/1).
NAME READY STATUS RESTARTS AGE
signserver... 0/1 Pending 0 0s
signserver... 0/1 ContainerCreating 0 0s
signserver... 0/1 Running 0 20s
signserver... 1/1 Running 0 40s
Step 7 - Access the Admin Web
Finalize the installation by importing the administrator certificate into your browser before navigating to the Admin Web.
The process of importing a certificate may vary depending on the web browser you are using. The following example outlines how to import a certificate into Mozilla Firefox.
To import the downloaded super administrator P12 keystore in Firefox:
-
Open Settings → Privacy & Security → View Certificates.
-
On the Your Certificates tab, click Import.
-
Browse to your
.p12file, click OK, and enter the certificate password.
Navigate to https://signserver.example.com/signserver/adminweb/ and select the administrator certificate when prompted.
Step 8 - Configure Workers
Before configuring the SignServer Workers, import the keystore files containing signer keys and certificates the Workers will use.
Import Signer Keystores
Keystore files can be mounted into the SignServer container from a Kubernetes secret:
kubectl create secret generic signer-keystores-secret \
--from-file=signer_keystore.p12=signer_keystore.p12
Configure the chart to mount keystore files from the secret. The keystoresMountPath is the location to place the files in the container:
signserver:
importKeystores: true
keystoresSecret: signer-keystores-secret
keystoresMountPath: /mnt/external
Configure Workers Using Properties Files
Workers can be fully configured from a properties file at startup, without manual Admin Web configuration. This is the recommended approach for repeatable, automated deployments.
The following example configures a Crypto Worker backed by a PKCS#12 keystore and a Plain Signer that uses the key signKey0001 from this keystore:
WORKER1.NAME=SignerCryptoToken
WORKER1.TYPE=CRYPTO_WORKER
WORKER1.IMPLEMENTATION_CLASS=org.signserver.server.signers.CryptoWorker
WORKER1.CRYPTOTOKEN_IMPLEMENTATION_CLASS=org.signserver.server.cryptotokens.KeystoreCryptoToken
WORKER1.KEYSTORETYPE=PKCS12
WORKER1.KEYSTOREPATH=/mnt/external/signer_keystore.p12
WORKER1.KEYSTOREPASSWORD=foo123
WORKER1.DEFAULTKEY=testKey
WORKER2.NAME=PlainSigner
WORKER2.TYPE=PROCESSABLE
WORKER2.IMPLEMENTATION_CLASS=org.signserver.module.cmssigner.PlainSigner
WORKER2.CRYPTOTOKEN=SignerCryptoToken
WORKER2.DEFAULTKEY=signKey0001
WORKER2.DISABLEKEYUSAGECOUNTER=true
WORKER2.AUTHTYPE=NOAUTH
Sample properties files for different Worker types are available in the SignServer GitHub repository.
Use explicit Worker IDs. The sample properties files use the prefix WORKERGENID1 to always create a new Worker. In order to handle container restarts, exact Worker ID should be used like in the example above, to avoid overwriting the properties of an existing Worker.
Create a secret from one or more text files with Worker properties:
kubectl create secret generic workers-secret \
--from-file=workers.properties=workers.properties
Configure the chart to import Worker properties at start-up:
signserver:
importWorkerProperties: true
workerPropertiesSecret: workers-secret
Next Steps
-
Set up HSM-backed key storage: HSM Integration
-
Review all available configuration parameters: SignServer Helm Deployment Parameters
-
Upgrade an existing deployment: Upgrade SignServer Helm Deployment