roundcube¶
A free and open source webmail solution with a desktop-like user interface
Homepage: https://github.com/encircle360-oss/helm-charts/tree/main/charts/roundcube
Introduction¶
This chart bootstraps a Roundcube deployment on a Kubernetes cluster using the Helm package manager.
Roundcube is a browser-based multilingual IMAP client with an application-like user interface. It provides full functionality expected from an email client, including MIME support, address book, folder management, message searching and spell checking.
Prerequisites¶
- Kubernetes 1.27+
- Helm 3.14.0+
- PV provisioner support in the underlying infrastructure (if using SQLite)
- Access to an IMAP/SMTP mail server
Installing the Chart¶
To install the chart with the release name my-roundcube
:
helm repo add encircle360-oss https://encircle360-oss.github.io/helm-charts/
helm repo update
helm install my-roundcube encircle360-oss/roundcube
Uninstalling the Chart¶
To uninstall/delete the my-roundcube
deployment:
Configuration¶
Basic Configuration¶
The following table lists the most important configurable parameters:
Parameter | Description | Default |
---|---|---|
roundcube.defaultHost | Default IMAP server address | ssl://mail.example.com |
roundcube.defaultPort | Default IMAP server port | 993 |
roundcube.smtpServer | SMTP server address | tls://mail.example.com |
roundcube.smtpPort | SMTP server port | 587 |
Database Configuration¶
This chart supports three database backends:
SQLite (Default)¶
MySQL/MariaDB¶
database:
type: mysql
external:
host: mysql.example.com
port: 3306
name: roundcube
user: roundcube
password: secretpassword
PostgreSQL¶
database:
type: pgsql
external:
host: postgresql.example.com
port: 5432
name: roundcube
user: roundcube
password: secretpassword
Ingress Configuration¶
To expose Roundcube via Ingress:
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: webmail.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: roundcube-tls
hosts:
- webmail.example.com
Session Storage with Redis¶
For better performance in multi-replica deployments:
redis:
enabled: true
host: redis-master.default.svc.cluster.local
port: 6379
password: redispassword
Installing Additional Plugins via Composer¶
Roundcube supports installing additional plugins via composer. You can specify plugins using the composerPlugins
list:
roundcube:
plugins:
- archive
- zipdownload
composerPlugins:
- johndoh/contextmenu
- sblaisot/automatic_addressbook
- texxasrulez/persistent_login
This will: - Install the specified plugins via composer during container startup - Automatically make them available in Roundcube - Work with any plugin available on Packagist
Popular composer plugins include: - johndoh/contextmenu
- Context menu for message list - sblaisot/automatic_addressbook
- Automatically add recipients to address book - texxasrulez/persistent_login
- Stay logged in across sessions - weird-birds/thunderbird_labels
- Thunderbird-style labels
Custom Configuration¶
You can provide custom Roundcube configuration:
roundcube:
customConfig: |
<?php
$config['spell_engine'] = 'aspell';
$config['enable_spellcheck'] = true;
// Additional custom configuration
Plugin-Specific Configuration¶
Many Roundcube plugins require their own config.inc.php
file in the plugin directory. You can provide plugin-specific configurations using the pluginConfigs
map:
roundcube:
plugins:
- identity_from_directory
- persistent_login
pluginConfigs:
identity_from_directory: |
<?php
$config['identity_from_directory_ldap_host'] = ['ldap://localhost:389'];
$config['identity_from_directory_ldap_base_dn'] = 'dc=example,dc=com';
$config['identity_from_directory_ldap_bind_dn'] = 'cn=admin,dc=example,dc=com';
$config['identity_from_directory_ldap_bind_pass'] = 'secret';
persistent_login: |
<?php
$config['login_lifetime'] = 30;
$config['login_secure_cookie'] = true;
$config['login_token_expiration'] = 3600;
This will: - Create a separate ConfigMap for each plugin configuration - Mount each config directly to /var/www/html/plugins/<plugin-name>/config.inc.php
- No init containers or lifecycle hooks required - Configs are immediately available when the container starts
Plugin-Specific Configuration with Secrets¶
For sensitive plugin configuration values (passwords, API tokens, OAuth secrets), use the secretEnvVars
feature for a fully declarative approach:
Option 1: Using secretEnvVars (Recommended - Fully Declarative)
roundcube:
plugins:
- identity_from_directory
pluginConfigs:
identity_from_directory: |
<?php
$config['identity_from_directory_ldap_host'] = ['ldap://localhost:389'];
$config['identity_from_directory_ldap_base_dn'] = 'dc=example,dc=com';
$config['identity_from_directory_ldap_bind_dn'] = 'cn=admin,dc=example,dc=com';
$config['identity_from_directory_ldap_bind_pass'] = getenv('LDAP_BIND_PASSWORD');
secretEnvVars:
LDAP_BIND_PASSWORD: "my-secret-password"
API_KEY: "my-api-key"
OAUTH_CLIENT_SECRET: "oauth-secret"
This will: - Automatically create a Kubernetes Secret - Inject environment variables into the container - Work with SOPS/sealed-secrets by encrypting your values.yaml
or separate secrets.yaml
- No external Secret creation or Helmfile hooks needed
Security with SOPS:
# Encrypt your values file with SOPS
sops -e values.yaml > values.enc.yaml
# Deploy with encrypted values
helm secrets upgrade my-release ./roundcube -f values.enc.yaml
Option 2: Using External Secrets (For existing secret management solutions)
roundcube:
pluginConfigs:
identity_from_directory: |
<?php
$config['identity_from_directory_ldap_bind_pass'] = getenv('LDAP_BIND_PASSWORD');
extraEnvVars:
- name: LDAP_BIND_PASSWORD
valueFrom:
secretKeyRef:
name: my-existing-secret
key: password
You must create the Secret separately (manually or via external-secrets operator):
apiVersion: v1
kind: Secret
metadata:
name: my-existing-secret
type: Opaque
stringData:
password: my-secret-password
Security Benefits: - secretEnvVars
: Fully declarative, works with SOPS/sealed-secrets, no external tools needed - extraEnvVars
: Supports external secret management (External Secrets Operator, Vault, etc.) - Secrets separated from configuration - Secrets never stored in ConfigMaps - Environment variables accessible via getenv()
in PHP
Multi-Domain Support¶
Roundcube can serve multiple domains with completely different configurations:
roundcube:
multiDomain:
enabled: true
domains:
- name: "mail.example.com"
config: |
$config['default_host'] = 'ssl://imap.example.com:993';
$config['smtp_server'] = 'tls://smtp.example.com:587';
$config['managesieve_host'] = 'imap.example.com';
$config['managesieve_port'] = 4190;
$config['plugins'] = array('managesieve', 'password', 'archive');
- name: "mail.company.org"
config: |
$config['default_host'] = 'ssl://mail.company.org:993';
$config['smtp_server'] = 'ssl://mail.company.org:465';
$config['smtp_conn_options'] = array(
'ssl' => array('verify_peer' => false)
);
$config['password_algorithm'] = 'sha256-crypt';
$config['password_db_dsn'] = 'mysql://user:pass@localhost/users';
$config['plugins'] = array('password', 'vacation', 'forward');
ingress:
enabled: true
hosts:
- host: mail.example.com
paths:
- path: /
- host: mail.company.org
paths:
- path: /
With this configuration: - Each domain can have completely different settings - Full control over IMAP, SMTP, ManageSieve, OAuth, plugins, etc. - Users accessing different domains get their specific configuration - Fallback to default settings if domain is not configured
Maintainers¶
Name | Url | |
---|---|---|
encircle360-oss | oss@encircle360.com |
Source Code¶
Values¶
Key | Type | Default | Description |
---|---|---|---|
affinity | object | {} | |
autoscaling.enabled | bool | false | |
autoscaling.maxReplicas | int | 10 | |
autoscaling.minReplicas | int | 1 | |
autoscaling.targetCPUUtilizationPercentage | int | 80 | |
autoscaling.targetMemoryUtilizationPercentage | int | 80 | |
database.external.existingSecret | string | "" | |
database.external.existingSecretPasswordKey | string | "password" | |
database.external.existingSecretUserKey | string | "username" | |
database.external.host | string | "" | |
database.external.name | string | "roundcube" | |
database.external.password | string | "" | |
database.external.port | int | 3306 | |
database.external.user | string | "roundcube" | |
database.type | string | "sqlite" | |
fullnameOverride | string | "" | |
image.pullPolicy | string | "IfNotPresent" | |
image.repository | string | "roundcube/roundcubemail" | |
image.tag | string | "" | |
imagePullSecrets | list | [] | |
ingress.annotations | object | {} | |
ingress.className | string | "" | |
ingress.enabled | bool | false | |
ingress.hosts[0].host | string | "webmail.example.com" | |
ingress.hosts[0].paths[0].path | string | "/" | |
ingress.hosts[0].paths[0].pathType | string | "Prefix" | |
ingress.tls | list | [] | |
initContainers | list | [] | |
livenessProbe.enabled | bool | true | |
livenessProbe.failureThreshold | int | 3 | |
livenessProbe.initialDelaySeconds | int | 30 | |
livenessProbe.periodSeconds | int | 10 | |
livenessProbe.successThreshold | int | 1 | |
livenessProbe.timeoutSeconds | int | 5 | |
memcached.enabled | bool | false | |
memcached.host | string | "" | |
memcached.port | int | 11211 | |
nameOverride | string | "" | |
nodeSelector | object | {} | |
persistence.accessMode | string | "ReadWriteOnce" | |
persistence.enabled | bool | true | |
persistence.existingClaim | string | "" | |
persistence.logsPath | string | "/var/roundcube/logs" | |
persistence.size | string | "5Gi" | |
persistence.sqlitePath | string | "/var/roundcube/db" | |
persistence.storageClass | string | "" | |
persistence.tempPath | string | "/tmp/roundcube" | |
podAnnotations | object | {} | |
podSecurityContext.fsGroup | int | 33 | |
podSecurityContext.runAsNonRoot | bool | true | |
podSecurityContext.runAsUser | int | 33 | |
readinessProbe.enabled | bool | true | |
readinessProbe.failureThreshold | int | 3 | |
readinessProbe.initialDelaySeconds | int | 5 | |
readinessProbe.periodSeconds | int | 10 | |
readinessProbe.successThreshold | int | 1 | |
readinessProbe.timeoutSeconds | int | 5 | |
redis.enabled | bool | false | |
redis.existingSecret | string | "" | |
redis.existingSecretPasswordKey | string | "password" | |
redis.host | string | "" | |
redis.password | string | "" | |
redis.port | int | 6379 | |
replicaCount | int | 1 | |
resources.limits.memory | string | "512Mi" | |
resources.requests.cpu | string | "100m" | |
resources.requests.memory | string | "256Mi" | |
roundcube.composerPlugins | list | [] | |
roundcube.customConfig | string | "" | |
roundcube.defaultHost | string | "ssl://mail.example.com" | |
roundcube.defaultPort | int | 993 | |
roundcube.desKey | string | "" | |
roundcube.extraEnvVars | list | [] | |
roundcube.extraVolumeMounts | list | [] | |
roundcube.extraVolumes | list | [] | |
roundcube.multiDomain.domains | list | [] | |
roundcube.multiDomain.enabled | bool | false | |
roundcube.pluginConfigs | object | {} | |
roundcube.plugins[0] | string | "archive" | |
roundcube.plugins[1] | string | "zipdownload" | |
roundcube.plugins[2] | string | "managesieve" | |
roundcube.productName | string | "Roundcube Webmail" | |
roundcube.secretEnvVars | object | {} | |
roundcube.skin | string | "elastic" | |
roundcube.smtpPass | string | "%p" | |
roundcube.smtpPort | int | 587 | |
roundcube.smtpServer | string | "tls://mail.example.com" | |
roundcube.smtpUser | string | "%u" | |
roundcube.supportUrl | string | "" | |
roundcube.uploadMaxFilesize | string | "25M" | |
securityContext.allowPrivilegeEscalation | bool | false | |
securityContext.capabilities.drop[0] | string | "ALL" | |
securityContext.readOnlyRootFilesystem | bool | false | |
service.annotations | object | {} | |
service.port | int | 80 | |
service.targetPort | int | 80 | |
service.type | string | "ClusterIP" | |
serviceAccount.annotations | object | {} | |
serviceAccount.create | bool | true | |
serviceAccount.name | string | "" | |
sidecarContainers | list | [] | |
startupProbe.enabled | bool | false | |
startupProbe.failureThreshold | int | 30 | |
startupProbe.initialDelaySeconds | int | 0 | |
startupProbe.periodSeconds | int | 10 | |
startupProbe.successThreshold | int | 1 | |
startupProbe.timeoutSeconds | int | 5 | |
tolerations | list | [] |
Examples¶
Minimal Configuration with SQLite¶
roundcube:
defaultHost: "ssl://imap.gmail.com"
defaultPort: 993
smtpServer: "tls://smtp.gmail.com"
smtpPort: 587
database:
type: sqlite
persistence:
enabled: true
Production Configuration with External Database¶
replicaCount: 3
roundcube:
defaultHost: "ssl://mail.company.com"
smtpServer: "tls://mail.company.com"
database:
type: mysql
external:
host: mysql.company.local
name: roundcube_prod
user: roundcube
existingSecret: roundcube-db-secret
redis:
enabled: true
host: redis.company.local
ingress:
enabled: true
className: nginx
hosts:
- host: webmail.company.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: webmail-tls
hosts:
- webmail.company.com
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
Troubleshooting¶
Logs¶
View Roundcube logs:
Database Connection Issues¶
If you're experiencing database connection issues:
- Verify database credentials
- Check network connectivity to database host
- Ensure database exists and user has proper permissions
Session Issues¶
If users are getting logged out frequently:
- Enable Redis for session storage
- Ensure all replicas can access the same session store
- Check session timeout settings
Support & Professional Services¶
Community Support¶
For issues and questions about this Helm chart: - Open an issue in GitHub Issues - Start a discussion in GitHub Discussions
For Roundcube specific issues: - Visit the Roundcube GitHub repository - Check the Roundcube documentation
Professional Support¶
For professional support, consulting, custom development, or enterprise solutions, contact hello@encircle360.com
Disclaimer¶
This Helm chart is provided "AS IS" without warranty of any kind. encircle360 GmbH and the contributors: - Make no warranties about the completeness, reliability, or accuracy of this chart - Are not liable for any damages arising from the use of this chart - Recommend thorough testing in non-production environments before production use
Use this chart at your own risk. For production deployments with SLA requirements, consider our professional support services.
License¶
This chart is licensed under the Apache License 2.0. See LICENSE for details.