Migrate Spaces to Hetzner: DigitalOcean-to-Hetzner migration covers data transfer, target architecture and cutover within the agreed scope. Arrange an initial consultation.
Migrating DigitalOcean Spaces to Hetzner Object Storage means transferring objects and separately accepting the storage features in use. This guide covers the currently visible objects using rclone. As of October 2026. Commands are templates for a test migration.
Table of contents
- Check feature boundaries before migration
- Prepare inventory and access
- Configure two rclone remotes
- Separate initial copy and final reconciliation
- Accept contents and application separately
- Switch CDN and custom domain separately
- Define rollback before cutover
- Our approach at WZ-IT
- Related guides
Check feature boundaries before migration
Hetzner is a possible DigitalOcean Spaces alternative when the features actually used fit the destination. This list describes destination boundaries; it does not claim Spaces provides every excluded feature.
| Destination feature | Planning consequence |
|---|---|
| No native custom bucket domains | Plan a separate delivery layer for a custom domain |
| No native bucket replication | Plan required copy jobs and their monitoring separately |
| No tagging | Replace application logic that relies on tags before moving |
| No S3 website feature | Replace website endpoints separately |
These boundaries appear in the supported S3 actions. Hetzner Object Storage is also not a CDN. High-volume public delivery therefore requires a separate CDN design when selecting the destination.
Decision: Postpone cutover if a required feature has no suitable replacement. The DigitalOcean-Hetzner comparison covers general provider selection; this guide focuses on the storage path.
Prepare inventory and access
Create a migration inventory: bucket, region, prefixes, object count and data volume; alongside writers, public URLs, signing, CORS, lifecycle rules and version-history requirements. Record which dataset will be authoritative and how deletions during the initial copy will be tracked.
Spaces supports bucket versioning through the API. An ordinary copy run therefore does not prove complete history migration. Plan this separately if old versions or delete markers must be retained. Spaces S3 compatibility.
Where possible, use a source read key restricted to the relevant bucket. Restricted keys are incompatible with existing PutBucketPolicy policies; assess a compatible access path without changing production policies without review. DigitalOcean offers object read permissions among its access levels. Check the actual permissions before running the transfer. Spaces access keys. Create the destination bucket as private in advance; assign destination configuration and read permissions separately. Keep secrets in protected local configuration, outside repositories and shared command histories.
Configure two rclone remotes
Create two remotes with rclone config. For Spaces select s3 and provider DigitalOcean; the endpoint contains the source region. Spaces configuration. For Hetzner follow the CLI guide, which documents provider = Other. Examples without credentials:
[spaces]
type = s3
provider = DigitalOcean
endpoint = fra1.digitaloceanspaces.com
[hetzner]
type = s3
provider = Other
endpoint = fsn1.your-objectstorage.com
region = fsn1
acl = private
Replace endpoints and the Hetzner region with the actual locations and enter each key through rclone config. Below, spaces:source-bucket and hetzner:target-bucket represent existing buckets. Start with a limited test dataset and accept its uploads, downloads and headers.
Separate initial copy and final reconciliation
Check direction using a dry run first, then run the initial copy:
rclone copy spaces:source-bucket hetzner:target-bucket --metadata --dry-run
rclone copy spaces:source-bucket hetzner:target-bucket --metadata --log-file=spaces-initial.log --log-level=INFO
copy does not remove extra destination objects. --metadata requests metadata transfer; bucket configuration remains a separate task. Dedicate a destination bucket to this migration and prevent production writes there until acceptance.
For completion we recommend this order: stop all writers, let running uploads finish, account for background jobs and automatic deletions, then run the final pass. Where modification times are unclear or shared hashes unavailable, copying everything again is the conservative choice:
rclone copy spaces:source-bucket hetzner:target-bucket --metadata --ignore-times --log-file=spaces-final.log --log-level=INFO
--ignore-times transfers files again instead of skipping them based on normal comparison. This repeats data transfer; reserve capacity and account for both providers' billing. copy options.
Then review a list of destination-only keys against the deletion record. Stale objects must not reappear as current documents. Approve deletions individually; do not apply broad synchronization with deletion permissions to an unchecked or shared destination dataset.
Accept contents and application separately
A content comparison can read both datasets in full:
rclone check spaces:source-bucket hetzner:target-bucket --download --combined=spaces-check.txt
check --download compares both remotes by streaming their contents. Include exit status and the difference report in acceptance; a completed copy alone is insufficient. Checking causes additional reads and data transfer.
We also recommend a separate checklist: headers and user metadata, private and public access, application uploads, browser access with CORS, signed URLs and caching behavior. A byte comparison does not prove these properties. The rclone S3 metadata list includes Content-Type, Content-Encoding and Cache-Control. Do not treat multipart ETags as simple MD5 checksums. Hash behavior.
Switch CDN and custom domain separately
Spaces Standard can serve public content through a CDN endpoint and a custom subdomain with a TLS certificate. Spaces Cold Storage does not support this CDN integration. An object copy does not transfer that configuration. Spaces CDN configuration.
Plan origin, public read permissions or protected origin access, TLS, cache rules and invalidation as a separate path. A CNAME pointing to the new bucket does not replace this design. Before changing DNS, test the intended hostname through the new delivery layer and update stored direct Spaces URLs. For private downloads, have the application configured for the destination generate new signed URLs and test them.
Define rollback before cutover
Our recommendation: retain the source until documented acceptance and explicitly approve the first write switch. While the destination is read-only, the return path is easier to manage. Once new uploads or deletions occur there, the source is no longer a complete rollback dataset.
To switch back, stop writers again, reconcile changes including deletions with an auditable record, then restore application and delivery configuration. Define responsibility, release criteria and retention in advance. Reverting DNS alone does not produce consistent data. These are planning rules, not a promise of uninterrupted migration.
Our approach at WZ-IT
DigitalOcean-to-Hetzner migration defines inventory, feature replacement, data transfer, tests and cutover in the quote. For Spaces, CDN dependencies and handling of version history specifically belong in that discussion. Subsequent operations are agreed separately through Managed Operations.
Related guides
- Compare DigitalOcean and Hetzner
- AWS S3 to Hetzner with rclone and MinIO Client
- Assess cloud migration
Define the storage path: Enquire about DigitalOcean migration with a bucket inventory, writers and CDN dependencies. Arrange a consultation.
Server and object storage are separate migrations: the Droplet guide covers Linux files, databases and cutover.













