Provider Migrations

This document describes the steps for migrating openDesk from one cloud service provider to another. For the sake of simplicity this document assumes that the Kubernetes-Cluster is an off-the-shelf cluster of said CSP, hence no K8S-Migration occurs. We also assume that in-cluster persistence services are used (e.g. S3, PostgreSQL,…). CSP-Services may behave differently but follow similar patterns.

Warning

Provider migrations are complex operations. Plan the migration during a maintenance window and communicate expected downtime to users.

Note

The describes approach is generic. However, the data-flow is heavily based on a central S3-Bucket. High capacity migrations ( e.g. many TB ) may require a performance focused solution.

Guidelines & Suggestions

The following values have proven effective in practice. Adjust based on your infrastructure and requirements.

SettingSuggested ValueRationale
DNS TTL~300sShort enough for quick transition, long enough for DNS provider compatibility and debugging
Source retention7-14 daysSufficient window to detect post-migration issues
K8up snapshot retention≥14 daysAllows point-in-time recovery after migration
Maintenance window prepAnnounce 1-2 weeks aheadUsers can plan accordingly
Port-forward stabilityUse bastion/jump hostAvoids unstable local connections during long operations

Timeline & Overview

What to Migrate

1. Configuration Files

FilePurpose
databases.yaml.gotmplDatabase connection settings
objectstores.yaml.gotmplS3/object storage config
cache.yaml.gotmplCache service config
secrets.yaml.gotmplAll secrets and passwords
smtp.yaml.gotmplSMTP/mail relay config

2. Database Credentials

Important

All database credentials are derived from the master password using the Master Password algorithm. As long as the same master password is used in the target deployment, all derived credentials will match automatically.

Database credentials in openDesk work as follows:

  1. Technical usernames (e.g., keycloak_user) are defined in databases.yaml.gotmpl
  2. Database passwords are derived from MASTER_PASSWORD via the Master Password algorithm in secrets.yaml.gotmpl
  3. To migrate: Use the same MASTER_PASSWORD in target deployment, then migrate only the actual data
Note

If you must change the master password, you would need to regenerate all derived passwords manually - this is not covered in this migration guide.

3. Kubernetes Secrets

Migrate all Kubernetes Secrets from the source namespace to ensure credentials, API keys, and certificates are available in the target cluster.

Alternatively, use the K8up PreBackupPod approach:

  • The PreBackupPod secrets-pre-backup-pod exports all secrets as JSON
  • This can be restored using K8up Restore CR

4. Object Storage (S3 Buckets)

BucketComponentContent
nextcloudFilesUser files, versioning, trash
openprojectProjectsProject attachments
openxchangeGroupwareEmail attachments, drive files
elementmediaChatUploaded images, files
openxchangeDovecot Pro EEUser mail

5. LDAP Data

Export OpenLDAP directory from the ums-ldap-server-primary service.

Secret Service: ums-ldap-server-admin (password key)

Base DN: Get from pod environment (LDAP_BASE_DN), default: dc=swp-ldap,dc=internal

6. DNS Records

Record TypePurpose
A/CNAMEMain ingress, subdomains
MXMail delivery
TXT: SPFAuthorized mail servers
TXT: DKIMEmail signing keys
TXT: DMARCEmail authentication policy
SRVService discovery

Migration Steps

Step 1: Reduce DNS TTLs (days before)

Consider setting DNS TTL to ~300 seconds for faster propagation and easier rollback.

Many openDesks are managed by delegated DNS-Zones. Zone-TTLs are often quite high. Depending on what exactly is migrated ( zone or record ) the shortened TTL may be the zone or the records.

Step 2: Build New Infrastructure

  1. Use existing configuration files to deploy openDesk on new provider. openDesk is domain-centric, hence a Test-Deployment on a different domain may be used to verify the deployment generally works but needs to be re-deployed with the correct domain for a later migration.
  2. Verify base deployment works.

Most openDesk setups require LetsEncrypt for certificate handling. Transfer the LE Secrets. Alternatively the DNS-Challenge may issue valid certificates to an offline-cluster.

Step 3: Maintenance Window - Disable Ingress

Consider disabling all ingresses to prevent new write traffic during migration.

Note

The nginx.ingress.kubernetes.io/server-snippet annotation breaks Collabora ingresses because they already use a server-snippet. If you need to abort the migration, the Collabora ingress must be redeployed. Consider scaling down write-heavy services instead.

Important

Ensure all ingresses are disabled before starting data export to prevent data inconsistencies between source and target.

Note

Run migration commands from an infrastructure-near system (e.g., a jump host or bastion) rather than your local machine to ensure stable connections.

Step 4: Export All Data

Export all databases, LDAP, object storage, and Kubernetes Secrets to the migration S3 bucket.

Key export commands:

  • PostgreSQL: pg_dump via port-forward
  • MariaDB: mysqldump via port-forward
  • LDAP: ldapsearch via port-forward
  • Object Storage: aws s3 sync
  • Secrets: kubectl get secrets -o json

Step 5: Import All Data

Restore all databases, LDAP, object storage, and Kubernetes Secrets to the target cluster.

Key import commands:

  • PostgreSQL: pg_restore via port-forward
  • MariaDB: mysql via port-forward
  • LDAP: slapadd (stop StatefulSet first)
  • Object Storage: aws s3 sync
  • Secrets: kubectl apply -f

Step 6: Nameserver Cutover

The nameserver switch approach allows you to prepare DNS changes before the migration window, significantly reducing downtime.

DNS Records to Migrate

RecordSourceTargetNotes
A/CNAMEOld provider’s DNS zoneNew provider’s DNS zoneMain ingress IP or alias
MXOld provider’s DNS zoneNew provider’s DNS zoneMail delivery target
SPFOld provider’s DNS zoneNew provider’s DNS zoneTXT record with v=spf1 ...
DKIMOpenDKIM/Keycloak podNew DNS zoneTXT record with v=DKIM1...
DMARCOld provider’s DNS zoneNew provider’s DNS zoneTXT record with _dmarc. prefix

Copy SPF Record

  1. From: Query current DNS at old provider
    dig TXT yourdomain.com +short
    # or
    nslookup -type=TXT yourdomain.com
  2. To: Add identical TXT record at new DNS provider
  3. Verify: dig TXT yourdomain.com +short after propagation

Copy DKIM Record

  1. From: Extract public key from OpenDKIM pod or Keycloak
    # Option A: From OpenDKIM pod
    kubectl exec -n ${SOURCE_NS} opendkim-0 -c main -- cat /etc/opendkim/keys/${DOMAIN}/mail.txt
     
    # Option B: From Keycloak realm settings (if DKIM is managed there)
    # Check realm settings in Keycloak admin UI under Email -> DKIM
  2. To: Add as TXT record at new DNS provider
    • Selector: match what your current _domainkey.yourdomain.com shows (often default or mail)
    • Content: The full v=DKIM1; p=... string
  3. Verify: dig TXT default._domainkey.yourdomain.com +short

Copy DMARC Record

  1. From: Query current DNS
    dig TXT _dmarc.yourdomain.com +short
  2. To: Add identical TXT record at new DNS provider with prefix _dmarc
  3. Verify: dig TXT _dmarc.yourdomain.com +short

Execution Order

  1. Before migration window (preparation): Copy all records to new DNS provider but keep old nameservers active
  2. During migration window: Switch authoritative nameservers to new provider
  3. Wait for TTL propagation (typically 5-30 minutes)
Important

MX, SPF, DKIM, and DMARC are critical for email deliverability. Verify each record matches exactly after migration.

Step 7: Post-Migration Restart

Consider restarting applications in a logical order (databases first, then services) to ensure proper initialization.

Step 8: Verification

Consider testing using DNS-resolved hostname or test accounts.

Step 9: Open to Users

  1. Allow access to new environment
  2. Monitor for issues
  3. Consider keeping source cluster running for 7-14 days (rollback option)

Verification Checklist

Authentication & Identity

TestDescription
SSO LoginLogin via Keycloak
LDAP SyncCheck user/group sync
2FATest two-factor authentication
Password ResetTest self-service

Mail System

TestDescription
Mail Inbound/OutboundSend/receive email
IMAP/SMTPMail client access
Calendar SharingShare calendar

Applications

TestDescription
NextcloudLogin, upload/download files
OX App SuiteWebmail, calendar, contacts
OpenProjectView/create work packages
XWikiCreate/edit pages
ElementSend messages
JitsiVideo meeting

Federation & Integrations

TestDescription
Matrix FederationExternal Matrix room
CalDAV SubscriptionExternal calendar
FilepickerOX to Nextcloud
OpenProject-NextcloudLink files

Data Integrity & DNS

TestDescription
User FilesVerify Nextcloud files
Email HistoryCheck old emails
Calendar EventsVerify past events
Project DataCheck projects
DNS RecordsA, MX, SPF, DKIM, DMARC
CertificatesCheck TLS validity

Migration-Specific Tests

TestDescription
Secrets RestoreVerify all Kubernetes Secrets migrated correctly
Database ConnectionsConfirm applications connect to databases
S3 AccessVerify object storage access for all components
LDAP UsersTest login with existing users
Backup IntegrityRun K8up Check job to verify backup repository
Note

Consider running automated restore tests in a separate environment before production migration to validate backup integrity.

RTO Calculation

Cloud Interconnect (1 Gbps) migration times with safety factor (1.4×) and overhead (~45 min):

Data SizeTransfer TimeWith Overhead
10 GB~2 minutes~50 minutes
100 GB~20 minutes~1.5 hours
1000 GB~3 hours~4.5 hours

Formula used: ((Data_Size_GB × 8) / 1000) × 2 × 1.4 + 0.75 (hours)

Rollback

If migration fails:

  1. Keep DNS pointing to source
  2. Keep source cluster running
  3. Investigate and retry
  4. Use K8up Restore jobs to re-sync any partial data transfers
Note

Consider retaining source infrastructure for 7-14 days after successful migration. Suggest keeping K8up snapshots available for at least 14 days to enable point-in-time recovery if issues are discovered post-migration.