Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/deuxfleurs-org/garage/llms.txt

Use this file to discover all available pages before exploring further.

Garage provides excellent support for hosting static websites. Many static site generators have built-in support for S3 deployment, and you can easily configure them to work with Garage.

How Website Hosting Works

Garage’s website serving functionality provides:
  • Static-only hosting: No support for server-side languages (PHP, Python, etc.)
  • Configurable index files: Default is index.html, customizable per bucket
  • Custom error pages: Configure custom 404 error documents
  • No directory listing: For security and privacy
  • Flexible URL routing: Support for both subdomain and custom domain access

URL Patterns

Garage serves websites using two URL patterns:
If your root_domain is .web.example.com and your bucket is named mysite:
mysite.web.example.com
This allows you to dedicate a subdomain to your users.

Supported Static Site Generators

GeneratorStatusNotes
HugoNative S3 deployment support
PubliiGUI-based, requires vhost endpoint
JekyllVia generic CLI tools
ZolaVia generic CLI tools
GatsbyVia generic CLI tools
PelicanVia generic CLI tools

Quick Setup

Before deploying any website, configure your bucket for website access:
1

Create Bucket

garage bucket create my-website
garage key create website-key
garage bucket allow my-website --read --write --key website-key
2

Enable Website

garage bucket website --allow my-website
3

Configure DNS

Point your domain to the Garage web endpoint:
  • A record: Your Garage server IP
  • CNAME: my-website.web.garage.example.com

Hugo

Hugo has built-in support for deploying to S3-compatible storage.

Configuration

Add to your config.toml:
[[deployment.targets]]
URL = "s3://<bucket>?endpoint=<endpoint>&disableSSL=<bool>&s3ForcePathStyle=true&region=garage"

Example Configuration

[[deployment.targets]]
URL = "s3://my-blog?endpoint=localhost:3900&disableSSL=true&s3ForcePathStyle=true&region=garage"

Deployment

1

Set Credentials

export AWS_ACCESS_KEY_ID=GKxxxx
export AWS_SECRET_ACCESS_KEY=xxxx
2

Build and Deploy

hugo
hugo deploy

Advanced Configuration

Hugo deployment supports additional options:
[[deployment.targets]]
name = "production"
URL = "s3://my-blog?endpoint=garage.example.com&region=garage&s3ForcePathStyle=true"

[[deployment.matchers]]
# Cache static assets for 1 year
pattern = "^.+\\.(js|css|svg|ttf|woff|woff2)$"
cacheControl = "max-age=31536000, no-transform, public"
gzip = true

[[deployment.matchers]]
# Set custom cache for images
pattern = "^.+\\.(png|jpg|jpeg|gif|webp)$"
cacheControl = "max-age=2592000, public"
See Hugo deployment documentation for more configuration options.

Publii

Publii is a desktop CMS that makes creating static websites easy with its GUI.

Prerequisites

Publii requires your Garage instance to be configured with vhost-style bucket access. Ensure this is set up before proceeding.

Setup

1

Open Server Settings

In Publii, click on the server icon in the left menu.
2

Choose S3 Protocol

Select “S3” as the protocol.
3

Configure S3 Settings

  • Website URL: Your final website URL (e.g., http://my-bucket.web.garage.localhost:3902)
  • Use custom S3 provider: ✅ Tick this option
  • S3 Endpoint: Your Garage endpoint (e.g., http://s3.garage.localhost:3900)
  • Access Key: Your access key (e.g., GKxxxx)
  • Secret Key: Your secret key
  • Bucket: Your bucket name (e.g., my-bucket)
4

Save and Sync

Click “Save settings” then use “Sync your website” to deploy.

Generic Deployment

For static site generators without native S3 support (Jekyll, Zola, Gatsby, Pelican, etc.), use CLI tools to upload your built site.

Using Minio Client

1

Configure mc

mc alias set garage \
  http://127.0.0.1:3900 \
  GKxxxx \
  your-secret-key \
  --api S3v4
2

Build Your Site

jekyll build
Output directory: _site
3

Deploy to Garage

mc mirror --overwrite <output-dir> garage/my-website
Examples:
# Jekyll
mc mirror --overwrite _site garage/my-website

# Zola/Gatsby
mc mirror --overwrite public garage/my-website

# Pelican
mc mirror --overwrite output garage/my-website

Using AWS CLI

Alternatively, use the AWS CLI:
aws s3 sync <output-dir> s3://my-website --delete
The --delete flag removes files that no longer exist in your local build.

Using rclone

For more advanced sync options:
rclone sync <output-dir> garage:my-website \
  --progress \
  --s3-upload-cutoff 0 \
  --s3-chunk-size 5M

Advanced Website Configuration

Custom Index Document

Set a custom index file (default is index.html):
garage bucket website --allow my-website --index-document home.html

Custom Error Document

Configure a custom 404 page:
garage bucket website --allow my-website --error-document error.html

Test Locally

You can test website functionality without DNS configuration using curl:
# Upload test file
echo "Hello, World!" > /tmp/index.html
mc cp /tmp/index.html garage/my-website/

# Test with custom Host header
curl -H 'Host: my-website' http://localhost:3902
curl -H 'Host: my-website.web.example.com' http://localhost:3902

Production Setup

Reverse Proxy Configuration

For production deployments, use a reverse proxy for HTTPS and caching:
server {
    listen 443 ssl http2;
    server_name *.web.example.com;
    
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    location / {
        proxy_pass http://127.0.0.1:3902;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Port Configuration

You can configure Garage to listen on port 80 or use iptables:
Edit garage.toml:
[s3_web]
bind_addr = "0.0.0.0:80"
root_domain = ".web.example.com"

Automation and CI/CD

GitHub Actions

name: Deploy Website

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: 'latest'
      
      - name: Build
        run: hugo
      
      - name: Configure S3
        run: |
          pip install awscli
          aws configure set aws_access_key_id ${{ secrets.S3_ACCESS_KEY }}
          aws configure set aws_secret_access_key ${{ secrets.S3_SECRET_KEY }}
          aws configure set default.region garage
      
      - name: Deploy
        run: |
          aws --endpoint-url ${{ secrets.S3_ENDPOINT }} \
            s3 sync public/ s3://my-website --delete

GitLab CI

deploy:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache curl
    - curl https://dl.min.io/client/mc/release/linux-amd64/mc --output /usr/local/bin/mc
    - chmod +x /usr/local/bin/mc
  script:
    - mc alias set garage $S3_ENDPOINT $S3_ACCESS_KEY $S3_SECRET_KEY
    - mc mirror --overwrite public/ garage/my-website
  only:
    - main

Troubleshooting

Ensure the bucket is configured for website access:
garage bucket website --allow my-website
Make sure each subdirectory has an index.html file. Garage does not support directory listing.
Check that your HTML uses relative paths or absolute paths starting with /.
Clear browser cache or use hard refresh (Ctrl+F5). Consider configuring cache headers.

Next Steps

CLI Tools

Learn about S3 CLI tools for website deployment

Application Integrations

Integrate web applications with Garage

Reverse Proxy Setup

Configure HTTPS and caching with reverse proxies

Monitoring

Monitor your website hosting performance

Build docs developers (and LLMs) love