When looking for self-hosted alternatives for Amazons S3 one comes up with two products, Ceph+RadosGW and Minio. Since Ceph is overkill in hosting only a couple of static websites or content I decided to go along with Minio. Simply use the official Docker image or your prefered automation tool. On FreeBSD there is a well maintained port. Installation and configuration is not covered here and is pretty straight forward when not using replication.

  • Install Minio and get your credentials
  • create a new bucket say example-com
  • Upload your website to Minio (minio-client, s3cmd, awscli)
  • set bucket policy to download

Like Amazon S3 only files are objects not directories. One as to tell Apache to add index.html on case that the object is missing.

    <VirtualHost *:443>
        ServerName example.com
        ServerAlias www.example.com

        RewriteEngine on
        RewriteCond %{REQUEST_METHOD} !^(OPTIONS|GET|HEAD|POST)$
        RewriteRule .* - [R=403]

        Header unset Server

        RewriteCond %{HTTP_HOST} ^www\.example\.com$
        RewriteRule ^(.*)$  https://example.com$1 [R=301,L]

        RewriteRule ^/blubb.html$ /index.html [PT]

        DocumentRoot /usr/local/www/apache24/vhosts/example.com

        ErrorLog /var/log/httpd-example_error.log
        CustomLog /var/log/httpd-example_access.log combined

        <Directory /usr/local/www/apache24/vhosts/example.com>
            Options -MultiViews
            # Apache < 2.4
            #Allow from all
            #AllowOverride all
            # Apache >= 2.4
            Require all granted
        </Directory>

        SSLEngine On
        SSLCertificateFile    /etc/letsencrypt/live/example.com/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
        SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
        SSLCipherSuite          EECDH+AES:CHACHA20:EDH+AES:!SHA1:!aNULL@STRENGTH
        SSLHonorCipherOrder on
        Header always set Strict-Transport-Security "max-age=63072000"
        Header always set X-Frame-Options "deny"
        Header always set X-XSS-Protection "1; mode=block"
        Header always set X-Content-Type-Options "nosniff"
        Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-src 'self'; img-src * data: blob:; font-src 'self' data:; media-src *; connect-src *"

        ProxyPass /.well-known !
        ProxyPass / http://localhost:9000/example-com/

        RewriteRule ^(.*)/$ /$1/index.html [PT,L]
        SecRuleEngine on

    </VirtualHost>

Voilà, your content is served by Minio. You may consider using h2c when proxying to Minio. I haven't tried this yet.