diff --git a/README.md b/README.md index 558dad95..e6f9481b 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,7 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose | 📝 **Flatnotes** | A simple, self-hosted note-taking app using Markdown files. | [Details](services/flatnotes) | | 👨🏼‍💻 **Forgejo** | A community-driven, self-hosted Git service. | [Details](services/forgejo) | | 📋 **Formbricks** | A self-hosted, open-source platform for collecting user feedback, surveys, and NPS. | [Details](services/formbricks) | +| 💾 **Garage** | A self-hosted, open-source s3 compatible object storage backend built to be resilient and performant | [Details](services/garage) | | 👨🏼‍💻 **Gitea** | A lightweight, self-hosted Git service with repository hosting, pull requests, and issue tracking. | [Details](services/gitea) | | ✍️ **Ghost** | A modern, open-source publishing platform for blogs and newsletters. | [Details](services/ghost) | | 🧑‍🧑‍🧒‍🧒 **Gramps Web** | A web-based genealogy platform for collaborative family tree browsing, editing, AI-powered chat, media tagging, mapping, charts, search, and reporting. | [Details](services/grampsweb) | diff --git a/services/garage/.env b/services/garage/.env new file mode 100644 index 00000000..5b2fb6a3 --- /dev/null +++ b/services/garage/.env @@ -0,0 +1,33 @@ +#version=1.1 +#URL=https://github.com/tailscale-dev/ScaleTail +#COMPOSE_PROJECT_NAME= # Optional: only use when running multiple deployments on the same infrastructure. + +# Service Configuration +# Service name (e.g., adguard). Used as hostname in Tailscale and for container naming (app-${SERVICE}). +SERVICE=garage +# Docker image URL from container registry (e.g., adguard/adguard-home). +IMAGE_URL=dxflrs/garage:v2.3.0 + +# Network Configuration +# Port to expose to local network. Uncomment the "ports:" section in compose.yaml to enable. +SERVICEPORT= + +# Preferred DNS server for Tailscale. Uncomment the "dns:" section in compose.yaml to enable. +DNS_SERVER=9.9.9.9 + +# Tailscale Configuration +# Auth key from https://tailscale.com/admin/authkeys. See: https://tailscale.com/kb/1085/auth-keys#generate-an-auth-key for instructions. +TS_AUTHKEY= + +# Optional Service variables +# PUID=1000 + +#Time Zone setting for containers +TZ=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +# Any Container environment variables are declared below. See https://docs.docker.com/compose/how-tos/environment-variables/ + +# Before running please configure Garage's secrets by running the openssl commands below and copying the output +GARAGE_RPC_SECRET= # "openssl rand -hex 32" +GARAGE_ADMIN_TOKEN= # "openssl rand -base64 32" +GARAGE_METRICS_TOKEN= # "openssl rand -base64 32" diff --git a/services/garage/README.md b/services/garage/README.md new file mode 100644 index 00000000..f4bba5be --- /dev/null +++ b/services/garage/README.md @@ -0,0 +1,92 @@ +# Garage with Tailscale Sidecar Configuration + +This Docker Compose configuration sets up [**Garage**](https://garagehq.deuxfleurs.fr/) with tailscale as a sidecar container. Allowing you to securely host your own S3 compatible backend on your tailnet + +## Garage + +[**Garage**](https://garagehq.deuxfleurs.fr/) is an S3 compatible storage solution designed for self hosting at a small scale. Supporting Geo-replication and redundancy optimised for performance and resiliance to node failures. + +## Key Features + +- S3 API +- Geo-distribution +- Flexible deployments +- Multiple replication modes +- Compression & Deduplication +- And many more [**here**](https://garagehq.deuxfleurs.fr/documentation/reference-manual/features/) + +## Configuration Overview + +In this deployment, the `tailscale-garage` service runs the Tailscale client to establish a secure private network. The `garage` container uses `network_mode: service:tailscale-garage` to route its traffic through the Tailscale interface. This ensures that all Garage api routes are only accessible securely through your tailnet. + +| Port | Purpose | Address | +|:-----|:--------|:--------| +| 3900 | S3 API | `https://garage..ts.net` | +| 3902 | Static Websites | `https://garage..ts.net:3902` | +| 3903 | Admin API & Metrics | `https://garage..ts.net:3903` | + +## Files to check + +Please check the following variables in the .env file + +- `TS_AUTHKEY` // Auth Key from [https://tailscale.com/admin/authkeys](https://tailscale.com/admin/authkeys) +- `TZ` // Configure the correct time zone +- `GARAGE_RPC_SECRET` //Generate from the command in `.env` +- `GARAGE_ADMIN_TOKEN` //Generate from the command in `.env` +- `GARAGE_METRICS_TOKEN` //Generate from the command in `.env` + +## Setup Guidelines + +Before you start using garage you need to configure your instance. + +### 1. Check Garage is configured correctly + +```bash +docker exec app-garage /garage status +``` + +You should get a output like this: + +```bash +==== HEALTHY NODES ==== +ID Hostname Address Tags Zone Capacity DataAvail Version +4014a6c5a274f246 garage 127.0.0.1:3901 NO ROLE ASSIGNED v2.3.0 +``` + +### 2. Configure the layout + +```bash +docker exec app-garage /garage layout assign -z dc1 -c 1G +``` + +node ID is taken from step 1 e.g. 4014a6c5a274f246 + +To assign more than 1GB of storage change the ``` 1G ``` parameter in the command. + +### 3. Apply the configured layout + +```bash +docker exec app-garage /garage layout apply --version 1 +``` + +### 4. Create a bucket + +```bash +docker exec app-garage /garage bucket create test-bucket +``` + +### 5. Create a key + +```bash +docker exec app-garage /garage key create my-key +``` + +Save these credentials and keep them secret! + +### 6. Grant key access to the test-bucket bucket + +```bash +docker exec app-garage /garage bucket allow --read --write --owner test-bucket --key my-key +``` + +### Congratulations your all setup with a s3 compatible bucket and key for more info take a look at the [documentation](https://garagehq.deuxfleurs.fr/documentation/quick-start/) diff --git a/services/garage/compose.yaml b/services/garage/compose.yaml new file mode 100644 index 00000000..d5835884 --- /dev/null +++ b/services/garage/compose.yaml @@ -0,0 +1,80 @@ +configs: + ts-serve: + content: | + {"TCP":{"443":{"HTTPS":true},"3902":{"HTTPS":true},"3903":{"HTTPS":true}}, + "Web":{"$${TS_CERT_DOMAIN}:443": + {"Handlers":{"/": + {"Proxy":"http://127.0.0.1:3900"}}}, + "$${TS_CERT_DOMAIN}:3902": + {"Handlers":{"/": + {"Proxy":"http://127.0.0.1:3902"}}}, + "$${TS_CERT_DOMAIN}:3903": + {"Handlers":{"/": + {"Proxy":"http://127.0.0.1:3903"}}}}, + "AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}} + +services: +# Make sure you have updated/checked the .env file with the correct variables. +# All the ${ xx } need to be defined there. + # Tailscale Sidecar Configuration + tailscale: + image: tailscale/tailscale:latest # Image to be used + container_name: tailscale-${SERVICE} # Name for local container management + hostname: ${SERVICE} # Name used within your Tailscale environment + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_STATE_DIR=/var/lib/tailscale + - TS_SERVE_CONFIG=/config/serve.json # Tailscale Serve configuration to expose the web interface on your local Tailnet - remove this line if not required + - TS_USERSPACE=false + - TS_ENABLE_HEALTH_CHECK=true # Enable healthcheck endpoint: "/healthz" + - TS_LOCAL_ADDR_PORT=127.0.0.1:41234 # The : for the healthz endpoint + #- TS_ACCEPT_DNS=true # Uncomment when using MagicDNS + - TS_AUTH_ONCE=true + configs: + - source: ts-serve + target: /config/serve.json + volumes: + - ./config:/config # Config folder used to store Tailscale files - you may need to change the path + - ./ts/state:/var/lib/tailscale # Tailscale requirement - you may need to change the path + devices: + - /dev/net/tun:/dev/net/tun # Network configuration for Tailscale to work + cap_add: + - net_admin # Tailscale requirement + #ports: + # - 0.0.0.0:${SERVICEPORT}:${SERVICEPORT} # Binding port ${SERVICE}PORT to the local network - may be removed if only exposure to your Tailnet is required + # If any DNS issues arise, use your preferred DNS provider by uncommenting the config below + #dns: + # - ${DNS_SERVER} + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"] # Check Tailscale has a Tailnet IP and is operational + interval: 1m # How often to perform the check + timeout: 10s # Time to wait for the check to succeed + retries: 3 # Number of retries before marking as unhealthy + start_period: 10s # Time to wait before starting health checks + restart: always + + # ${SERVICE} + application: + image: ${IMAGE_URL} # Image to be used + network_mode: service:tailscale # Sidecar configuration to route ${SERVICE} through Tailscale + container_name: app-${SERVICE} # Name for local container management + environment: # Variables are delared in .env file. + - TZ=${TZ} + - GARAGE_RPC_SECRET=${GARAGE_RPC_SECRET} + - GARAGE_ADMIN_TOKEN=${GARAGE_ADMIN_TOKEN} + - GARAGE_METRICS_TOKEN=${GARAGE_METRICS_TOKEN} + #- EXAMPLE_VAR=${EXAMPLE_VAR} + volumes: + - ./garage.toml:/etc/garage.toml + - ./${SERVICE}-data/data:/var/lib/garage/data + - ./${SERVICE}-data/meta:/var/lib/garage/meta + depends_on: + tailscale: + condition: service_healthy + healthcheck: + test: ["CMD", "/garage", "status"] # Check that the Garage node responds over RPC + interval: 1m # How often to perform the check + timeout: 10s # Time to wait for the check to succeed + retries: 3 # Number of retries before marking as unhealthy + start_period: 30s # Time to wait before starting health checks + restart: always diff --git a/services/garage/garage.toml b/services/garage/garage.toml new file mode 100644 index 00000000..fd9f5a61 --- /dev/null +++ b/services/garage/garage.toml @@ -0,0 +1,22 @@ +metadata_dir = "/var/lib/garage/meta" +data_dir = "/var/lib/garage/data" +db_engine = "sqlite" + +replication_factor = 1 + +rpc_bind_addr = "[::]:3901" +rpc_public_addr = "127.0.0.1:3901" + + +[s3_api] +s3_region = "garage" +api_bind_addr = "[::]:3900" +root_domain = ".s3.garage.localhost" + +[s3_web] +bind_addr = "127.0.0.1:3902" +root_domain = ".web.garage.localhost" +index = "index.html" + +[admin] +api_bind_addr = "127.0.0.1:3903" \ No newline at end of file