Guides: storage & data
How to route a bucket to a different backendHow to route a bucket to a different backend
On this page
This guide shows you how to serve a bucket from a specific storage backend, and how to map the bucket name that clients use onto a different real bucket upstream. Routing is pure configuration, so you can do it in the admin UI or in the YAML file. For how multi-backend routing works internally, see the multi-backend architecture.
The example registers three backends: hetzner-fsn1 (S3-compatible storage at Hetzner, the default), local-disk (a directory on the proxy host) and aws-dr (AWS). It then routes downloads to local-disk, and it keeps releases on hetzner-fsn1 under the real bucket name acme-prod-releases-fsn1.
1. Declare the backends#
In the admin UI:
-
In the sidebar, open Storage → Backends (
/_/admin/storage/backends). -
Click New backend at the top right of the page.


-
In the New backend form, type
hetzner-fsn1in Name and select S3 in Type. Fill in Endpoint (https://fsn1.your-objectstorage.com), Region (fsn1), Access key ID and Secret access key. Select Force path-style URLs, because Hetzner is not AWS, and select Set as default backend. -
Click Create backend.


Before it saves an S3 backend, the page tests the connection with the keys that you typed. If the test fails, the page does not create the backend and shows the error. The server then probes the new backend again, and it refuses a backend that fails its probe. A backend that passes is saved at once and written to the config file, so the Backends page has no Review & apply step.
Repeat steps 2 to 4 for the other two backends:
- For
local-disk, select Filesystem in Type and type/var/lib/dgp-localin Data directory. The admin UI andPOST /_/api/admin/backendsrefuse a filesystem backend whose path is not absolute. A relative path resolves against the working directory of the proxy process, and that directory is different under systemd, Docker and a shell. - For
aws-dr, select S3, leave Endpoint empty, typeeu-west-1in Region, and leave Force path-style URLs off, because AWS itself needsfalse. Every non-AWS provider (Hetzner, MinIO, Backblaze, Wasabi) needs it on.
The form needs both an access key and a secret key for an S3 backend. Two options work only in YAML (see below): on AWS you can omit both keys and let the SDK pick up instance credentials, and you can keep a secret out of the file with a ${env:...} reference.
2. Route the bucket#
In the admin UI:
-
In the sidebar, open Storage → Buckets (
/_/admin/storage/buckets). Each bucket is a row that shows its backend, its public access and its quota. -
Click the
downloadsrow to open it.

-
In Backend, select
local-disk. The option Default means that the bucket followsdefault_backend. If the bucket already had an explicit backend, a dialog reminds you that routing does not move objects; click Re-route anyway to continue.

-
Click Review & apply in the bar at the bottom of the page.


-
Check the diff in the dialog, and then click Apply and Persist.


If the bucket does not exist yet, click Settings for a future bucket at the top right of the page. A new settings row opens. Type the bucket name in it, and continue with step 3. Any bucket without an explicit backend goes to default_backend.
A bucket with its own encryption block (see How to encrypt one bucket on a shared backend) always keeps an explicit backend, because the block belongs to the storage that holds the bucket. The Backend list does not let you choose Default for such a bucket; set its Encryption group to Inherit first. A re-route moves no objects, and the objects on the old backend stay under their old keys. To move a bucket with its own key, run a migrate job: the bucket's block moves with it.
3. Alias an upstream bucket name#
If the real bucket on the backend has a different name from the one that clients should see, give the bucket an alias. In the admin UI:
-
On Storage → Buckets, click the
releasesrow to open it. -
Click Advanced inside the row.
-
Type
acme-prod-releases-fsn1in Real name on backend.

-
Click Review & apply, and then click Apply and Persist, as in the previous section.
Clients send requests to s3://releases/firmware/widget-3000/fw-1.4.3.tar, and the proxy translates them to s3://acme-prod-releases-fsn1/firmware/widget-3000/fw-1.4.3.tar on Hetzner.
Aliasing is useful when:
- You're moving buckets between backends without updating clients.
- The upstream name carries a prefix you don't want to expose (
acme-prod-releases-fsn1vsreleases). - You want two logical namespaces in one physical bucket (two aliases that point at the same real bucket). Avoid this unless you also scope access by prefix with IAM.
When two bucket names point at one real bucket on one backend, ListBuckets lists both names. The proxy treats the two names as one storage in two places. A replication rule from one name into the other is refused when the destination prefix contains the source prefix (Replication reference). A migrate job of either name is refused with 409, because the job would not block or copy the writes through the other name (How to move a bucket to another backend).
The same change in YAML#
The steps above write this configuration into the storage section of deltaglider_proxy.yaml (why the UI and the file hold the same configuration):
# validate
storage:
default_backend: hetzner-fsn1
backends:
- name: hetzner-fsn1
type: s3
endpoint: https://fsn1.your-objectstorage.com
region: fsn1
force_path_style: true
- name: local-disk
type: filesystem
path: /var/lib/dgp-local
- name: aws-dr
type: s3
region: eu-west-1
buckets:
downloads:
backend: local-disk # local filesystem
releases: # name clients use
backend: hetzner-fsn1
alias: acme-prod-releases-fsn1 # real bucket on the backend
# every other bucket goes to default_backend
Each S3 backend takes its credentials in access_key_id and secret_access_key. Keep the secret out of the file with a ${env:...} reference:
# fragment
access_key_id: "${env:HETZNER_S3_KEY}"
secret_access_key: "${env:HETZNER_S3_SECRET}"
On AWS you can omit both and let the SDK pick up instance credentials. The complete field list is in the configuration reference.
After you edit the file, restart the proxy, or apply the file to the running proxy with POST /_/api/admin/config/apply or with deltaglider_proxy config apply deltaglider_proxy.yaml --server https://s3.acme.example.
Buckets that the proxy creates at startup#
The proxy creates each bucket declared under storage.buckets at startup, on the backend that its route points at, so the first write works without a CreateBucket step. On a filesystem backend, the proxy creates the bucket's directory. On an S3 backend, the proxy first sends a HeadBucket, and it sends a CreateBucket only when the backend does not have the bucket. When the backend's key may not create buckets, the proxy logs a warning and starts anyway. In that case, create the bucket yourself, for example through the proxy with aws s3 mb s3://downloads --endpoint-url https://s3.acme.example. Set DGP_BOOT_CREATE_DECLARED_BUCKETS=false to turn the startup creation off for every backend. A route that you add at runtime (with an apply, from the UI or from the file) does not create the bucket until the next start. If a client creates a bucket that has no storage.buckets entry at all, it lands on default_backend.
What routing does not do#
Routing never moves data. When you point an existing bucket at a new backend, the proxy looks for its objects on the new backend. Objects that are already stored on the old backend become invisible until you move them. To relocate data, use the built-in migrate job instead: How to move a bucket to another backend. On the Buckets page, the Migrate data… link next to Backend starts it.
Verify#
-
Check that the proxy applied the config:
curl -b cookies https://s3.acme.example/_/api/admin/config/section/storage?format=yaml -
Check that a SigV4 client sees the bucket:
aws --endpoint-url https://s3.acme.example s3 ls -
Check that a round-trip works through the alias:
aws --endpoint-url https://s3.acme.example s3 cp test.txt s3://releases/test.txt aws --endpoint-url https://s3.acme.example s3 cp s3://releases/test.txt - -
Check that the object landed on the right backend. For a filesystem backend, check the path directly. For S3, list the real (aliased) bucket on the provider:
ls /var/lib/dgp-local/downloads/ # filesystem backend aws s3 ls s3://acme-prod-releases-fsn1/ --profile hetzner # S3 backend, raw
If an object goes to the wrong backend, see Troubleshooting.
Related#
- How to move a bucket to another backend: relocate the data.
- How to migrate an existing S3 bucket into the proxy: adopt a pre-existing upstream bucket.
- Configuration reference: every
storage.backendsandstorage.bucketsfield. - The multi-backend architecture: how virtual-bucket routing works.
- Two ways to configure DeltaGlider: how the admin UI and the YAML file relate.