From cb44198ca2057b075c15eee3369cc3cf6a5a534b Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Sat, 2 Dec 2023 02:27:27 +0000 Subject: [PATCH] Initial commit --- Dockerfile | 58 +++++++++++++++++++++++++++++++++++ README.md | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ serve.json | 1 + supervisord.conf | 19 ++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 serve.json create mode 100644 supervisord.conf diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6e5073b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,58 @@ +FROM public.ecr.aws/amazonlinux/amazonlinux:2023 as builder + +# We need the full version of GnuPG +RUN dnf install -y --allowerasing wget gnupg2 + +RUN MP_ARCH=`uname -p | sed s/aarch64/arm64/` && \ + wget -q "https://s3.amazonaws.com/mountpoint-s3-release/latest/$MP_ARCH/mount-s3.rpm" && \ + wget -q "https://s3.amazonaws.com/mountpoint-s3-release/latest/$MP_ARCH/mount-s3.rpm.asc" && \ + wget -q https://s3.amazonaws.com/mountpoint-s3-release/public_keys/KEYS + +# Import the key and validate it has the fingerprint we expect +RUN gpg --import KEYS && \ + (gpg --fingerprint mountpoint-s3@amazon.com | grep "673F E406 1506 BB46 9A0E F857 BE39 7A52 B086 DA5A") + +# Verify the downloaded binary +RUN gpg --verify mount-s3.rpm.asc + +# Node.js binary verification instructions: https://github.com/nodejs/node?tab=readme-ov-file#verifying-binaries +ARG NODE_VERSION=20.9.0 +RUN wget --quiet https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz \ + && wget --quiet https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt{,.sig} \ + && gpg --keyserver hkps://keys.openpgp.org --recv-keys C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ + && gpg --verify SHASUMS256.txt{.sig,} \ + && grep node-v${NODE_VERSION}-linux-x64.tar.xz SHASUMS256.txt | sha256sum -c - \ + && rm -f SHASUMS256.txt{,.sig} \ + && mv node-v${NODE_VERSION}-linux-x64.tar.xz node.tar.xz + +FROM amazonlinux:2023 +COPY --from=builder /mount-s3.rpm /mount-s3.rpm + +RUN dnf upgrade -y && \ + dnf install -y ./mount-s3.rpm && \ + dnf clean all && \ + rm mount-s3.rpm + +RUN dnf upgrade -y \ + && dnf install -y python3-pip + +RUN pip install supervisor + +COPY --from=builder /node.tar.xz /node.tar.xz +RUN dnf upgrade -y \ + && dnf install -y tar xz \ + && tar -xf /node.tar.xz -C /usr/local --strip-components=1 \ + && rm /node.tar.xz + +RUN npm install -g serve + +COPY ./serve.json /etc/serve.json +COPY ./supervisord.conf /etc/supervisord.conf + +# Optional environment variables +ENV MOUNTPOINT_S3_ADDITIONAL_ARGS="" +ENV SERVE_ADDITIONAL_ARGS="" + +# Run in foreground mode so that the container can be detached without exiting Mountpoint +ENTRYPOINT [ "supervisord" ] + diff --git a/README.md b/README.md new file mode 100644 index 0000000..348e846 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# s3-serve + +Runs [serve][serve] with an [S3-compatible backend][mountpoint-s3]. Useful for serving websites from S3[^rewrite]. + +[serve]: https://github.com/vercel/serve +[mountpoint-s3]: https://github.com/awslabs/mountpoint-s3 +[^rewrite]: S3 does not support [clean URLs](https://github.com/vercel/serve-handler/blob/da507891/README.md#cleanurls-booleanarray). The closest you can get is to use [index documents](https://docs.aws.amazon.com/AmazonS3/latest/userguide/IndexDocumentSupport.html), but this only supports `index.html` and not other files (e.g. `about.html`. A workaround is to convert all `.html` files to `/index.html` files, but that is error-prone because it's not the default behaviour of frameworks like [Next.js](https://nextjs.org/)). Moreover, in some S3-compatible storage backends like [Ceph Object Gateway](https://docs.ceph.com/en/latest/radosgw/s3/), the support for index documents requires setting `rgw_dns_name` and `rgw_dns_s3website_name`, which restricts the RGW instance to only serve from two domains. On the other hand, [serve][serve] supports clean URLs the box. This project combines the two to provide clean URLs on S3. + +## Getting started + +```bash +export AWS_ACCESS_KEY_ID= +export AWS_SECRET_ACCESS_KEY= +export S3_ENDPOINT_URL= +export S3_BUCKET= + +docker run --rm --cap-add SYS_ADMIN --device /dev/fuse --name s3-serve \ + -e AWS_ACCESS_KEY_ID \ + -e AWS_SECRET_ACCESS_KEY \ + -e S3_ENDPOINT_URL \ + -e S3_BUCKET \ + -p 3000:3000 \ + ghcr.io/watonomous/s3-serve +``` + +### Use path-style addressing + +If your S3 endpoint does not support virtual-hosted-style addressing, you can use path-style addressing by including `--force-path-style` in the `MOUNTPOINT_S3_ADDITIONAL_ARGS` environment variable: + +```bash +# In addition to the above environment variables +export MOUNTPOINT_S3_ADDITIONAL_ARGS="--force-path-style" + +docker run --rm --cap-add SYS_ADMIN --device /dev/fuse --name s3-serve \ + -e AWS_ACCESS_KEY_ID \ + -e AWS_SECRET_ACCESS_KEY \ + -e S3_ENDPOINT_URL \ + -e S3_BUCKET \ + -e MOUNTPOINT_S3_ADDITIONAL_ARGS \ + -p 3000:3000 \ + ghcr.io/watonomous/s3-serve +``` + +### Reduce logging + +By default, [serve][serve] and [mountpoint-s3][mountpoint-s3] log all requests[^logging]. You can reduce the amount of logging by including the following environment variables: + +```bash +# In addition to the above environment variables +export SERVE_ADDITIONAL_ARGS="--no-request-logging" +export MOUNTPOINT_LOG="error,awscrt=off" + +docker run --rm --cap-add SYS_ADMIN --device /dev/fuse --name s3-serve \ + -e AWS_ACCESS_KEY_ID \ + -e AWS_SECRET_ACCESS_KEY \ + -e S3_ENDPOINT_URL \ + -e S3_BUCKET \ + -e SERVE_ADDITIONAL_ARGS \ + -e MOUNTPOINT_LOG \ + -p 3000:3000 \ + ghcr.io/watonomous/s3-serve +``` + +[^logging]: [`serve` logging documentation](https://github.com/vercel/serve/blob/1ea55b/source/utilities/cli.ts#L47), `mountpoint-s3` logging documentation [1](https://github.com/awslabs/mountpoint-s3/blob/27bac02/doc/LOGGING.md) [2](https://github.com/awslabs/mountpoint-s3/blob/27bac02/mountpoint-s3/src/main.rs#L289-L304) + +### Use a custom `serve` configuration + +You can use a custom `serve` configuration by mounting a [`serve.json`](https://github.com/vercel/serve/blob/1ea55b/readme.md#configuration) file to `/etc/serve.json`: + +```bash +docker run --rm --cap-add SYS_ADMIN --device /dev/fuse --name s3-serve \ + -e AWS_ACCESS_KEY_ID \ + -e AWS_SECRET_ACCESS_KEY \ + -e S3_ENDPOINT_URL \ + -e S3_BUCKET \ + -v /path/to/serve.json:/etc/serve.json:ro \ + -p 3000:3000 \ + ghcr.io/watonomous/s3-serve +``` + diff --git a/serve.json b/serve.json new file mode 100644 index 0000000..bec8e93 --- /dev/null +++ b/serve.json @@ -0,0 +1 @@ +{ "directoryListing": false } diff --git a/supervisord.conf b/supervisord.conf new file mode 100644 index 0000000..ac5d8b2 --- /dev/null +++ b/supervisord.conf @@ -0,0 +1,19 @@ +[supervisord] +nodaemon=true +user=root + +[program:mountpoint-s3] +command=/usr/bin/mount-s3 --foreground --endpoint-url %(ENV_S3_ENDPOINT_URL)s %(ENV_MOUNTPOINT_S3_ADDITIONAL_ARGS)s %(ENV_S3_BUCKET)s /mnt +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true +priority=10 + +[program:serve] +command=/usr/local/bin/serve --config /etc/serve.json --listen tcp://0.0.0.0:3000 %(ENV_SERVE_ADDITIONAL_ARGS)s +directory=/mnt +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true +priority=20 +