diff --git a/.env.sample b/.env.sample index 0f3576a9c..d64d4bc1b 100644 --- a/.env.sample +++ b/.env.sample @@ -18,6 +18,9 @@ SMTP_PORT=2525 HONEYCOMB_API_KEY=your-api-key-here OTEL_SERVICE_NAME=awbw +# Asset CDN (DigitalOcean Spaces) +# ASSET_HOST=https://the-bucket.sfo3.cdn.digitaloceanspaces.com + # Other RAILS_ENV=development APP_HOST=localhost:3000 diff --git a/Dockerfile b/Dockerfile index fed3244cd..90bcd2e9a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,7 @@ RUN apt-get update -qq && apt-get install -y \ libyaml-dev \ nodejs \ npm \ + s3cmd \ zlib1g-dev # Copy app code and install dependencies @@ -49,6 +50,33 @@ RUN SECRET_KEY_BASE=1 \ SMTP_PASSWORD=dummy \ bundle exec rake assets:precompile +# Sync precompiled assets to DigitalOcean Spaces CDN (optional). +# Pass --build-arg DO_SPACES_KEY=... etc. to enable. +ARG DO_SPACES_KEY +ARG DO_SPACES_SECRET +ARG DO_SPACES_REGION +ARG DO_SPACES_BUCKET_ASSETS +RUN if [ -n "$DO_SPACES_KEY" ]; then \ + s3cmd --access_key="$DO_SPACES_KEY" \ + --secret_key="$DO_SPACES_SECRET" \ + --host="${DO_SPACES_REGION}.digitaloceanspaces.com" \ + --host-bucket="%(bucket)s.${DO_SPACES_REGION}.digitaloceanspaces.com" \ + --region="$DO_SPACES_REGION" \ + --no-mime-magic \ + --acl-public \ + --add-header="Cache-Control:public, immutable, max-age=31536000" \ + sync public/assets/ "s3://${DO_SPACES_BUCKET_ASSETS}/assets/" && \ + s3cmd --access_key="$DO_SPACES_KEY" \ + --secret_key="$DO_SPACES_SECRET" \ + --host="${DO_SPACES_REGION}.digitaloceanspaces.com" \ + --host-bucket="%(bucket)s.${DO_SPACES_REGION}.digitaloceanspaces.com" \ + --region="$DO_SPACES_REGION" \ + --no-mime-magic \ + --acl-public \ + --add-header="Cache-Control:public, immutable, max-age=31536000" \ + sync public/vite/ "s3://${DO_SPACES_BUCKET_ASSETS}/vite/"; \ + fi + FROM base AS server RUN apt-get update -qq && apt-get install --no-install-recommends -y \ diff --git a/bin/sync-assets b/bin/sync-assets new file mode 100755 index 000000000..4e5fdd28c --- /dev/null +++ b/bin/sync-assets @@ -0,0 +1,43 @@ +#!/bin/bash +set -euo pipefail + +# Sync precompiled assets from a Docker image to DigitalOcean Spaces. +# Requires: aws CLI, docker, and DO_SPACES_KEY/DO_SPACES_SECRET/DO_SPACES_REGION env vars. +# +# Usage: bin/sync-assets [image_name] +# image_name defaults to "awbw:latest" + +IMAGE="${1:-awbw:latest}" +BUCKET="${DO_SPACES_BUCKET_ASSETS:?Set DO_SPACES_BUCKET_ASSETS (e.g. awbw-assets-staging)}" +REGION="${DO_SPACES_REGION:?Set DO_SPACES_REGION (e.g. sfo3)}" +ENDPOINT="https://${REGION}.digitaloceanspaces.com" + +export AWS_ACCESS_KEY_ID="${DO_SPACES_KEY:?Set DO_SPACES_KEY}" +export AWS_SECRET_ACCESS_KEY="${DO_SPACES_SECRET:?Set DO_SPACES_SECRET}" + +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +echo "Extracting assets from ${IMAGE}..." +CONTAINER=$(docker create "$IMAGE") +docker cp "${CONTAINER}:/app/public/assets" "$TMPDIR/assets" 2>/dev/null || true +docker cp "${CONTAINER}:/app/public/vite" "$TMPDIR/vite" 2>/dev/null || true +docker rm "$CONTAINER" > /dev/null + +echo "Syncing to s3://${BUCKET} via ${ENDPOINT}..." + +if [ -d "$TMPDIR/assets" ]; then + aws s3 sync "$TMPDIR/assets" "s3://${BUCKET}/assets/" \ + --endpoint-url "$ENDPOINT" \ + --cache-control "public, immutable, max-age=31536000" \ + --acl public-read +fi + +if [ -d "$TMPDIR/vite" ]; then + aws s3 sync "$TMPDIR/vite" "s3://${BUCKET}/vite/" \ + --endpoint-url "$ENDPOINT" \ + --cache-control "public, immutable, max-age=31536000" \ + --acl public-read +fi + +echo "Done. Assets available at https://${BUCKET}.${REGION}.cdn.digitaloceanspaces.com" diff --git a/config/environments/production.rb b/config/environments/production.rb index f56cdc66c..7923cfa09 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -103,7 +103,7 @@ } # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.asset_host = "http://assets.example.com" + config.asset_host = ENV["ASSET_HOST"] if ENV["ASSET_HOST"].present? config.action_mailer.asset_host = "https://#{app_host}" # Specify outgoing SMTP server. Remember to add smtp/* credentials via bin/rails credentials:edit.