Web S3 Docker
A Terraform module, creating a self-hosted static web hosting solution in the Hetzner cloud, offering S3 object storage and a Docker registry.
- Public and private S3 buckets
- Custom domains for public S3 Buckets
- Public and private Docker Registry
Prerequisites
The module will create DNS entries for the various service endpoints. This requires a valid DNS zone that is managed via the Hetzner Cloud API.
Usage Example
resource "tls_private_key" "ssh_key" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "hcloud_ssh_key" "ssh_key1" {
name = "ssh-key1"
public_key = tls_private_key.ssh_key.public_key_openssh
}
module "web-s3-docker" {
source = "https://github.com/pellepelster/solidblocks/releases/download/v0.4.9/terraform-hcloud-blcks-web-s3-docker-v0.4.9.zip"
name = "server1"
dns_zone = "blcks-test.de"
ssh_keys = [hcloud_ssh_key.ssh_key1.id]
s3_buckets = [
{
name = "bucket1",
web_access_public_enable = true,
web_access_domains = ["blcks-test.de", "www.blcks-test.de"]
},
{
name = "bucket2",
owner_key_id = "cbeebb7f1fa4de50025a5c95",
owner_secret_key = "f775d527e821ab035b5a874e6326f20c135b2d2fc903112fe768a17681f54043"
},
]
}Configuration
Name and DNS
The name and dns_zone will be used as base domain for all created endpoints using the pattern <name>.<dns_zone>.
S3 Buckets
The variable s3_buckets can be used to auto-create S3 buckets during provisioning.
Minimal Bucket configuration
module "web_s3_docker" {
# ...
s3_buckets = [{ name = "bucket1" }]
}will create a single S3 bucket named bucket1 with autogenerated access keys for the bucket owner, a read-write rw
as well as a read-only ro user. The keys can be retrieved using the module output s3_buckets.
Example output for s3_buckets
[
{
"name": "bucket1",
"owner_key_id": "GKxxxxxxxxxxxxxxxxxxxxxxxx",
"owner_secret_key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"ro_key_id": "GKxxxxxxxxxxxxxxxxxxxxxxxx",
"ro_secret_key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"rw_key_id": "GKxxxxxxxxxxxxxxxxxxxxxxxx",
"rw_secret_key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
//...
}
]Together with the base S3 api address from the output s3_host the bucket can be used with S3 tools like s3cmd like
this
export S3_HOST=$(terraform output -raw s3_host)
export ACCESS_KEY=$(terraform output -raw s3_host | jq '.[0].owner_key_id')
export SECRET_KEY=$(terraform output -raw s3_host | jq '.[0].owner_secret_key')
s3cmd --host-bucket ${S3_HOST} --host ${S3_HOST} --access_key ${ACCESS_KEY} --secret_key ${SECRET_KEY} ls s3://bucket1Custom access keys
You can override the access key ids as well as the secrets by providing your own. To do this simply provide them in the bucket config
module "web_s3_docker" {
//...
s3_buckets = [
{
name = "bucket2",
owner_key_id = "cbeebb7f1fa4de50025a5c95",
owner_secret_key = "f775d527e821ab035b5a874e6326f20c135b2d2fc903112fe768a17681f54043"
},
]
}[owner|rw|ro]_key_id has to be 24 characters long, and [owner|rw|ro]_secret_key 64. You can either provide both,
just one or none, the missing parts will be automatically generated. The module takes care to add the GK prefix which
is needed by the underlying S3 server.
Static web hosting
By setting the bucket configuration web_access_public_enable to true, static web hosting can be enabled for the
Bucket, making all its content available on the internet. The list web_access_domains enables access to this bucket
using custom domains.
Tip
DNS entries for all domains that are within the dns_zone are auto-created. If the provided web_access_domains is not
part of the dns_zone the A respectively AAAA DNS entries need to be created manually, the IPv4 and IPv6 addresses
are available through the module output ipv4_address and ipv6_address.
The created web endpoints again can be retrieved via the s3_buckets output.
Example output for a bucket with web_access_public_enable
[
{
"name": "bucket1",
//...
"web_access_public_enable": true,
"web_access_addresses": [
"https://bucket1.s3-web.web-s3-docker.blcks-test.de",
"https://blcks-test.de",
"https://www.blcks-test.de"
]
}
]Tip
When uploading content to be served it is important to use the correct mime-types, when using s3cmd to upload content this can be achieved like this
s3cmd sync --no-mime-magic --guess-mime-type ./contnt/* s3://<bucket_name>
Docker
By setting docker_enable to true the service will also expose a docker registry. The creation of credentials follows
the pattern of the S3 bucket access key creation. If no user is specified a read-write as well as a read-only user will
be autogenerated. Those can be retrieved via the outputs docker_rw_users respectively docker_ro_users.
Example output for docker_rw_users
[
{
"username": "61008df60fd0abac80a5cba645056a80",
"password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
]using the private docker endpoint that can be retrieved from docker_host_private, docker images can be pushed like
this
export DOCKER_HOST_PRIVATE=$(terraform output -raw docker_host_private)
export DOCKER_USERNAME=$(terraform output -raw docker_rw_users | jq '.[0].username')
export DOCKER_PASSWORD=$(terraform output -raw docker_rw_users | jq '.[0].password')
echo ${DOCKER_PASSWORD} | docker login ${DOCKER_HOST_PRIVATE} --username ${DOCKER_USERNAME} --password-stdin
docker push ${DOCKER_HOST_PRIVATE}/my-image:latestPublic registry
When docker_public_enable is set to true all images that are pushed to the private endpoint (docker_host_private)
cn be pulled without authentication from the public endpoint
export DOCKER_HOST_PUBLIC=$(terraform output -raw docker_host_public)
docker pull ${DOCKER_HOST_PUBLIC}/my-image:latestEndpoints
| endpoint | description | address |
|---|---|---|
| S3 | S3 api endpoint | <bucket>.s3.<name>.<dns_zone> |
| S3 Web | public accessible endpoint if web_access_public_enable is set to true |
<bucket>.s3-web.<name>.<dns_zone> |
| S3 Admin API | API endpoint for the GarageFS S3 admin API. Adress can be as well as the access token can be retrieved from the output garage_admin_address and garage_admin_token |
s3-admin.<name>.<dns_zone> |
| private docker registry | endpoint for publishing and pulling Docker images usein credentials | docker-private.s3-web.<name>.<dns_zone> |
| public docker registry | endpoint unauthorized pulling if enabled via docker_public_enable |
docker-public.s3-web.<name>.<dns_zone> |
Terraform Module
Requirements
| Name | Version |
|---|---|
| hcloud | >=1.56.0 |
| http | >= 3.3.0 |
Providers
| Name | Version |
|---|---|
| hcloud | >=1.56.0 |
| random | n/a |
Resources
| Name | Type |
|---|---|
| hcloud_primary_ip.ipv4 | resource |
| hcloud_primary_ip.ipv6 | resource |
| hcloud_server.server | resource |
| hcloud_volume.data | resource |
| hcloud_volume_attachment.data | resource |
| hcloud_zone_rrset.root_domain_catchall_ipv4 | resource |
| hcloud_zone_rrset.root_domain_ipv4 | resource |
| hcloud_zone_rrset.web_access_domains_ipv4 | resource |
| random_bytes.admin_token | resource |
| random_bytes.docker_ro_default_password | resource |
| random_bytes.docker_ro_default_user | resource |
| random_bytes.docker_ro_password | resource |
| random_bytes.docker_rw_default_password | resource |
| random_bytes.docker_rw_default_user | resource |
| random_bytes.docker_rw_password | resource |
| random_bytes.metrics_token | resource |
| random_bytes.owner_key_ids | resource |
| random_bytes.owner_secret_keys | resource |
| random_bytes.ro_key_ids | resource |
| random_bytes.ro_secret_keys | resource |
| random_bytes.rpc_secret | resource |
| random_bytes.rw_key_ids | resource |
| random_bytes.rw_secret_keys | resource |
Inputs
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| data_volume_size | data volume size in GB | number |
64 |
no |
| datacenter | n/a | string |
"nbg1-dc3" |
no |
| dns_zone | DNS zone to use for hostname and DNs entries | string |
n/a | yes |
| docker_enable | Enable Docker registry | bool |
false |
no |
| docker_public_enable | Enable public anonymous access to Docker registry, see https://pellepelster.github.io/solidblocks/hetzner/web-s3-docker/#docker for details | bool |
false |
no |
| docker_ro_users | Docker read-write users to provision. If no users is given a user will be auto.created, see https://pellepelster.github.io/solidblocks/hetzner/web-s3-docker/#docker for details | list(object({ |
[] |
no |
| docker_rw_users | Docker read-write users to provision. If no users is given a user will be auto.created, see https://pellepelster.github.io/solidblocks/hetzner/web-s3-docker/#docker for details | list(object({ |
[] |
no |
| labels | A list of labels to be attached to the server instance. | map(any) |
{} |
no |
| location | Hetzner location to use for provisioned resources | string |
"nbg1" |
no |
| name | Unique name for the server instance | string |
n/a | yes |
| s3_buckets | S3 buckets to provision, see https://pellepelster.github.io/solidblocks/hetzner/web-s3-docker/#s3-buckets for details | list(object({ |
[] |
no |
| server_type | Hetzner cloud server type, supports x86 and ARM architectures | string |
"cx23" |
no |
| ssh_keys | ssh keys to provision for instance access | list(number) |
n/a | yes |
Outputs
| Name | Description |
|---|---|
| docker_host_private | fully qualified domain for the private docker registry |
| docker_host_public | fully qualified domain for the public docker registry if enabled |
| docker_ro_users | readonly users for the docker registry |
| docker_rw_users | write users for the docker registry |
| garage_admin_address | address for the GarageFS admin endpoint |
| garage_admin_token | token for the GarageFS admin endpoint |
| ipv4_address | IPv4 address of the created server |
| ipv6_address | IPv6 address of the created server |
| s3_buckets | the created S3 bucket with access credentials and public endpoints if available |
| s3_host | fully qualified for the s3 endpoint |
| server_id | Hetzner ID of the created server |