Skip to content

Commit 72f7d28

Browse files
✨ New tutorial - "Setup custom domain for S3-compatible object storage via reverse proxy" (#1040)
* New tutorial * Spelling and formatting updates --------- Co-authored-by: svenja.michal <84835304+svenja11@users.noreply.github.com>
1 parent ab2034c commit 72f7d28

File tree

1 file changed

+257
-0
lines changed
  • tutorials/hetzner-object-storage-custom-domain

1 file changed

+257
-0
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
---
2+
SPDX-License-Identifier: MIT
3+
path: "/tutorials/hetzner-object-storage-custom-domain"
4+
slug: "hetzner-object-storage-custom-domain"
5+
date: "2025-01-17"
6+
title: "Setup custom domain for S3-compatible object storage via reverse proxy"
7+
short_description: "This tutorial explains how to setup custom domains for S3-compatible object storage using reverse proxy."
8+
tags: ["Custom domain", "Reverse proxy", "Object Storage"]
9+
author: "Ivan Zaitsev"
10+
author_link: "https://github.com/ivan-zaitsev"
11+
author_img: "https://avatars.githubusercontent.com/u/15122759"
12+
author_description: ""
13+
language: "en"
14+
available_languages: ["en"]
15+
header_img: "header-7"
16+
cta: "cloud"
17+
---
18+
19+
## Introduction
20+
21+
This tutorial will guide you to setup a custom domain for S3-compatible object storage using reverse proxy.
22+
The advantages of a custom domain are to enable seamless integration with existing infrastructure or services under a unified domain.
23+
24+
There are different ways to configure a custom domain, such as using a CNAME record or a reverse proxy.
25+
This tutorial focuses on configuring a custom domain using a reverse proxy.
26+
27+
**Prerequisites**
28+
29+
* A server (e.g. with [Hetzner Cloud](https://www.hetzner.com/cloud/))
30+
* An S3-compatible bucket (e.g. with [Hetzner](https://www.hetzner.com/storage/object-storage/))
31+
* A domain you want to use (e.g. `storage.example.com`).
32+
33+
## Step 1 - Create Object Storage Bucket
34+
35+
Create an S3-compatible bucket.
36+
With Hetzner, see the getting started "[Creating a Bucket](https://docs.hetzner.com/storage/object-storage/getting-started/creating-a-bucket)".
37+
Make sure it is set to public access permissions. Not much benefit to using a custom domain for private buckets.
38+
39+
Create S3 credentials to access your bucket.
40+
With Hetzner, see the getting started "[Generating S3 keys](https://docs.hetzner.com/storage/object-storage/getting-started/generating-s3-keys)".
41+
42+
## Step 2 - Create Server
43+
44+
Create a new server.
45+
With Hetzner, see the getting started "[Creating a Server](https://docs.hetzner.com/cloud/servers/getting-started/creating-a-server)".
46+
To install Docker and Docker Compose, follow the [official Docker documentation](https://docs.docker.com/engine/install/).
47+
48+
## Step 3 - Deploy Caddy
49+
50+
SSH to your server `ssh root@<server-ip>`.
51+
52+
Create a directory for your Docker Compose files and folders for the persistent storage of the Caddy container:
53+
54+
```bash
55+
sudo mkdir -p /opt/caddy/data
56+
```
57+
58+
### Step 3.1 - Create Docker deployment and configuration files
59+
60+
* Add a Docker compose file
61+
62+
```bash
63+
sudo vim /opt/caddy/compose.yaml
64+
```
65+
Add the following content:
66+
```yaml
67+
services:
68+
caddy:
69+
container_name: caddy
70+
image: caddy:latest
71+
restart: unless-stopped
72+
ports:
73+
- 80:80
74+
- 443:443
75+
volumes:
76+
- ./data/Caddyfile:/etc/caddy/Caddyfile
77+
- ./data/certs:/certs
78+
- ./data/config:/config
79+
- ./data/data:/data
80+
- ./data/sites:/srv
81+
```
82+
83+
<br>
84+
85+
* Add a Caddyfile
86+
87+
```bash
88+
sudo vim /opt/caddy/data/Caddyfile
89+
```
90+
Add the following content:
91+
92+
> Replace `storage.example.com` with your own domain.
93+
> Replace `fsn1.your-objectstorage.com` with the endpoint of your object storage bucket. If the bucket name comes after the endpoint (e.g. `https://s3-endpoint.example.org/<bucket_name>`) add your endpoint without the bucket name.
94+
95+
```text
96+
storage.example.com {
97+
98+
tls {
99+
issuer acme {
100+
dir https://acme-v02.api.letsencrypt.org/directory
101+
}
102+
}
103+
104+
reverse_proxy https://<bucket_name>.fsn1.your-objectstorage.com {
105+
#reverse_proxy https://s3-endpoint.example.org {
106+
header_up Host {http.reverse_proxy.upstream.hostport}
107+
header_up X-Forwarded-Host {host}
108+
}
109+
}
110+
```
111+
112+
### Step 3.2 - Start Caddy
113+
114+
```bash
115+
cd /opt/caddy
116+
docker compose up -d
117+
docker ps
118+
```
119+
120+
After the Docker container started, you can access your files via `storage.example.com`.
121+
122+
If your bucket name comes after the endpoint, note:
123+
124+
The request URL would be `https://storage.example.com/<bucket_name>/object.txt`.
125+
It is equivalent to `https://s3-endpoint.example.org/<bucket_name>/object.txt`.
126+
127+
### Step 3.3 - Create Kubernetes deployment and configuration files (Optional)
128+
129+
Assuming you already have configured Kubernetes, [gateway API](https://gateway-api.sigs.k8s.io/guides/#installing-gateway-api).
130+
131+
> Replace `storage.example.com` with your own domain.
132+
> Replace `fsn1.your-objectstorage.com` with the endpoint of your object storage bucket. If the bucket name comes after the endpoint (e.g. `https://s3-endpoint.example.org/<bucket_name>`) add your endpoint without the bucket name.
133+
134+
```yaml
135+
apiVersion: v1
136+
kind: Service
137+
metadata:
138+
name: caddy-storage
139+
namespace: caddy
140+
spec:
141+
type: ClusterIP
142+
selector:
143+
service: caddy-storage
144+
ports:
145+
- name: http
146+
protocol: TCP
147+
port: 80
148+
targetPort: 80
149+
150+
---
151+
152+
apiVersion: apps/v1
153+
kind: Deployment
154+
metadata:
155+
name: caddy-storage
156+
namespace: caddy
157+
spec:
158+
replicas: 1
159+
revisionHistoryLimit: 3
160+
selector:
161+
matchLabels:
162+
service: caddy-storage
163+
template:
164+
metadata:
165+
labels:
166+
service: caddy-storage
167+
spec:
168+
containers:
169+
- image: "caddy:latest"
170+
name: caddy
171+
ports:
172+
- name: http
173+
protocol: TCP
174+
containerPort: 80
175+
volumeMounts:
176+
- name: config-volume
177+
mountPath: /etc/caddy
178+
volumes:
179+
- name: config-volume
180+
configMap:
181+
name: caddy-storage-config
182+
183+
---
184+
185+
apiVersion: v1
186+
kind: ConfigMap
187+
metadata:
188+
name: caddy-storage-config
189+
namespace: caddy
190+
data:
191+
Caddyfile: |
192+
storage.example.com:80 {
193+
reverse_proxy https://<bucket_name>.fsn1.your-objectstorage.com {
194+
#reverse_proxy https://s3-endpoint.example.org {
195+
header_up Host {http.reverse_proxy.upstream.hostport}
196+
header_up X-Forwarded-Host {host}
197+
}
198+
}
199+
200+
---
201+
202+
apiVersion: gateway.networking.k8s.io/v1
203+
kind: HTTPRoute
204+
metadata:
205+
name: caddy-storage-route
206+
namespace: caddy
207+
spec:
208+
parentRefs:
209+
- name: kubernetes-gateway
210+
namespace: istio-gateway
211+
hostnames:
212+
- "storage.example.com"
213+
rules:
214+
- matches:
215+
- path:
216+
type: PathPrefix
217+
value: /
218+
backendRefs:
219+
- name: caddy-storage
220+
port: 80
221+
weight: 100
222+
```
223+
224+
## Conclusion
225+
226+
You should now be able to access the contents of your S3-compatible object storage via a custom domain.
227+
228+
##### License: MIT
229+
230+
<!--
231+
232+
Contributor's Certificate of Origin
233+
234+
By making a contribution to this project, I certify that:
235+
236+
(a) The contribution was created in whole or in part by me and I have
237+
the right to submit it under the license indicated in the file; or
238+
239+
(b) The contribution is based upon previous work that, to the best of my
240+
knowledge, is covered under an appropriate license and I have the
241+
right under that license to submit that work with modifications,
242+
whether created in whole or in part by me, under the same license
243+
(unless I am permitted to submit under a different license), as
244+
indicated in the file; or
245+
246+
(c) The contribution was provided directly to me by some other person
247+
who certified (a), (b) or (c) and I have not modified it.
248+
249+
(d) I understand and agree that this project and the contribution are
250+
public and that a record of the contribution (including all personal
251+
information I submit with it, including my sign-off) is maintained
252+
indefinitely and may be redistributed consistent with this project
253+
or the license(s) involved.
254+
255+
Signed-off-by: Ivan Zaitsev, https://github.com/ivan-zaitsev
256+
257+
-->

0 commit comments

Comments
 (0)