diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 622f88a1..e9fad3cf 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -4,7 +4,12 @@ ARG TARGETPLATFORM ARG SERVER_VERSION=0.0.0 ENV SERVER_VERSION=${SERVER_VERSION} -RUN apk --no-cache add ca-certificates tzdata file +RUN set -eux \ + && apk --no-cache add \ + ca-certificates \ + tzdata \ + file \ + && true RUN set -ex; \ case "$TARGETPLATFORM" in \ @@ -33,23 +38,55 @@ RUN set -ex \ FROM alpine:3.21.5 ARG SERVER_VERSION=0.0.0 -ENV SERVER_VERSION=${SERVER_VERSION} +ARG SERVER_USER_NAME=sws +ARG SERVER_USER_ID=1000 +ARG SERVER_GROUP_NAME=sws +ARG SERVER_GROUP_ID=1000 + +ENV SERVER_VERSION=$SERVER_VERSION +ENV SERVER_USER_ID=$SERVER_USER_ID +ENV SERVER_USER_NAME=$SERVER_USER_NAME +ENV SERVER_GROUP_ID=$SERVER_GROUP_ID +ENV SERVER_GROUP_NAME=$SERVER_GROUP_NAME LABEL version="${SERVER_VERSION}" \ description="A cross-platform, high-performance and asynchronous web server for static files-serving." \ maintainer="Jose Quintana " -RUN apk --no-cache add ca-certificates tzdata +RUN set -eux \ + && addgroup -g $SERVER_GROUP_ID $SERVER_GROUP_NAME \ + && adduser -D -u $SERVER_USER_ID -G $SERVER_GROUP_NAME $SERVER_USER_NAME \ + && true -COPY --from=build /usr/local/bin/static-web-server /usr/local/bin/ -COPY ./docker/alpine/entrypoint.sh / -COPY ./docker/public /public +RUN set -eux \ + && apk --no-cache add \ + ca-certificates \ + tzdata \ + && true + +RUN set -eux \ + && mkdir -p /home/$SERVER_USER_NAME/public \ + && chown -R $SERVER_USER_NAME:$SERVER_GROUP_NAME /home/$SERVER_USER_NAME \ + && ln -s /home/$SERVER_USER_NAME/public /var/public \ + && chown -R $SERVER_USER_NAME:$SERVER_GROUP_NAME /var/public \ + && true + +USER $SERVER_USER_NAME:$SERVER_GROUP_NAME + +COPY --from=build --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + /usr/local/bin/static-web-server /usr/local/bin/static-web-server +COPY --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + ./docker/alpine/entrypoint.sh /usr/local/bin/entrypoint.sh +COPY --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + ./docker/public /home/$SERVER_USER_NAME/public + +WORKDIR /home/$SERVER_USER_NAME EXPOSE 80 STOPSIGNAL SIGQUIT -ENTRYPOINT ["/entrypoint.sh"] +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] CMD ["static-web-server"] @@ -59,4 +96,4 @@ LABEL org.opencontainers.image.vendor="Jose Quintana" \ org.opencontainers.image.title="Static Web Server" \ org.opencontainers.image.description="A cross-platform, high-performance and asynchronous web server for static files-serving." \ org.opencontainers.image.version="${SERVER_VERSION}" \ - org.opencontainers.image.documentation="https://github.com/static-web-server/static-web-server" + org.opencontainers.image.documentation="https://static-web-server.net" diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index 06533d6a..154278eb 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM debian:12.12-slim AS build +FROM --platform=$BUILDPLATFORM debian:13.1-slim AS build ARG TARGETPLATFORM ARG SERVER_VERSION=0.0.0 @@ -7,10 +7,10 @@ ENV SERVER_VERSION=${SERVER_VERSION} RUN set -eux \ && DEBIAN_FRONTEND=noninteractive apt-get update -qq \ && DEBIAN_FRONTEND=noninteractive apt-get install -qq -y --no-install-recommends --no-install-suggests \ - ca-certificates \ - curl \ - file \ - tzdata \ + ca-certificates \ + curl \ + file \ + tzdata \ && true RUN set -ex \ @@ -48,34 +48,62 @@ RUN set -ex \ && file /usr/local/bin/static-web-server \ && true -FROM debian:12.12-slim +FROM debian:13.1-slim ARG SERVER_VERSION=0.0.0 -ENV SERVER_VERSION=${SERVER_VERSION} +ARG SERVER_USER_NAME=sws +ARG SERVER_USER_ID=1000 +ARG SERVER_GROUP_NAME=sws +ARG SERVER_GROUP_ID=1000 + +ENV SERVER_VERSION=$SERVER_VERSION +ENV SERVER_USER_ID=$SERVER_USER_ID +ENV SERVER_USER_NAME=$SERVER_USER_NAME +ENV SERVER_GROUP_ID=$SERVER_GROUP_ID +ENV SERVER_GROUP_NAME=$SERVER_GROUP_NAME LABEL version="${SERVER_VERSION}" \ description="A cross-platform, high-performance and asynchronous web server for static files-serving." \ maintainer="Jose Quintana " +RUN set -eux \ + && groupadd -r -g $SERVER_GROUP_ID $SERVER_GROUP_NAME \ + && useradd -r -g $SERVER_GROUP_ID -u $SERVER_USER_ID $SERVER_USER_NAME \ + && true + RUN set -eux \ && DEBIAN_FRONTEND=noninteractive apt-get update -qq \ && DEBIAN_FRONTEND=noninteractive apt-get install -qq -y --no-install-recommends --no-install-suggests \ - ca-certificates \ - tzdata \ + ca-certificates \ + tzdata \ # Clean up local repository of retrieved packages and remove the package lists && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ && true -COPY --from=build /usr/local/bin/static-web-server /usr/local/bin/ -COPY ./docker/debian/entrypoint.sh / -COPY ./docker/public /public +RUN set -eux \ + && mkdir -p /home/$SERVER_USER_NAME/public \ + && chown -R $SERVER_USER_NAME:$SERVER_GROUP_NAME /home/$SERVER_USER_NAME \ + && ln -s /home/$SERVER_USER_NAME/public /var/public \ + && chown -R $SERVER_USER_NAME:$SERVER_GROUP_NAME /var/public \ + && true + +USER $SERVER_USER_NAME:$SERVER_GROUP_NAME + +COPY --from=build --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + /usr/local/bin/static-web-server /usr/local/bin/static-web-server +COPY --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + ./docker/debian/entrypoint.sh /usr/local/bin/entrypoint.sh +COPY --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + ./docker/public /home/$SERVER_USER_NAME/public + +WORKDIR /home/$SERVER_USER_NAME EXPOSE 80 STOPSIGNAL SIGQUIT -ENTRYPOINT ["/entrypoint.sh"] +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] CMD ["static-web-server"] diff --git a/docker/devel/Dockerfile.alpine b/docker/devel/Dockerfile.alpine index 455f875c..1e37d89f 100644 --- a/docker/devel/Dockerfile.alpine +++ b/docker/devel/Dockerfile.alpine @@ -1,22 +1,55 @@ FROM alpine:3.21.5 -ENV SERVER_VERSION=devel +ARG SERVER_VERSION=devel +ARG SERVER_USER_NAME=sws +ARG SERVER_USER_ID=1000 +ARG SERVER_GROUP_NAME=sws +ARG SERVER_GROUP_ID=1000 + +ENV SERVER_VERSION=$SERVER_VERSION +ENV SERVER_USER_ID=$SERVER_USER_ID +ENV SERVER_USER_NAME=$SERVER_USER_NAME +ENV SERVER_GROUP_ID=$SERVER_GROUP_ID +ENV SERVER_GROUP_NAME=$SERVER_GROUP_NAME LABEL version="${SERVER_VERSION}" \ description="A cross-platform, high-performance and asynchronous web server for static files-serving." \ maintainer="Jose Quintana " -RUN apk --no-cache add ca-certificates tzdata +RUN set -eux \ + && addgroup -g $SERVER_GROUP_ID $SERVER_GROUP_NAME \ + && adduser -D -u $SERVER_USER_ID -G $SERVER_GROUP_NAME $SERVER_USER_NAME \ + && true -COPY ./docker/devel/static-web-server /usr/local/bin/ -COPY ./docker/alpine/entrypoint.sh / -COPY ./docker/public /public +RUN set -eux \ + && apk --no-cache add \ + ca-certificates \ + tzdata \ + && true + +RUN set -eux \ + && mkdir -p /home/$SERVER_USER_NAME/public \ + && chown -R $SERVER_USER_NAME:$SERVER_GROUP_NAME /home/$SERVER_USER_NAME \ + && ln -s /home/$SERVER_USER_NAME/public /var/public \ + && chown -R $SERVER_USER_NAME:$SERVER_GROUP_NAME /var/public \ + && true + +USER $SERVER_USER_NAME:$SERVER_GROUP_NAME + +COPY --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + ./docker/devel/static-web-server /usr/local/bin/static-web-server +COPY --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + ./docker/debian/entrypoint.sh /usr/local/bin/entrypoint.sh +COPY --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + ./docker/public /home/$SERVER_USER_NAME/public + +WORKDIR /home/$SERVER_USER_NAME EXPOSE 80 STOPSIGNAL SIGQUIT -ENTRYPOINT ["/entrypoint.sh"] +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] CMD ["static-web-server"] @@ -25,5 +58,5 @@ LABEL org.opencontainers.image.vendor="Jose Quintana" \ org.opencontainers.image.url="https://github.com/static-web-server/static-web-server" \ org.opencontainers.image.title="Static Web Server" \ org.opencontainers.image.description="A cross-platform, high-performance and asynchronous web server for static files-serving." \ - org.opencontainers.image.version="${SERVER_VERSION}" \ - org.opencontainers.image.documentation="https://github.com/static-web-server/static-web-server" + org.opencontainers.image.version="$SERVER_VERSION" \ + org.opencontainers.image.documentation="https://static-web-server.net" diff --git a/docker/devel/Dockerfile.debian b/docker/devel/Dockerfile.debian index 11f1839e..51583155 100644 --- a/docker/devel/Dockerfile.debian +++ b/docker/devel/Dockerfile.debian @@ -1,30 +1,59 @@ -FROM debian:12.12-slim +FROM debian:13.1-slim -ENV SERVER_VERSION=devel +ARG SERVER_VERSION=devel +ARG SERVER_USER_NAME=sws +ARG SERVER_USER_ID=1000 +ARG SERVER_GROUP_NAME=sws +ARG SERVER_GROUP_ID=1000 + +ENV SERVER_VERSION=$SERVER_VERSION +ENV SERVER_USER_ID=$SERVER_USER_ID +ENV SERVER_USER_NAME=$SERVER_USER_NAME +ENV SERVER_GROUP_ID=$SERVER_GROUP_ID +ENV SERVER_GROUP_NAME=$SERVER_GROUP_NAME LABEL version="${SERVER_VERSION}" \ description="A cross-platform, high-performance and asynchronous web server for static files-serving." \ maintainer="Jose Quintana " +RUN set -eux \ + && groupadd -r -g $SERVER_GROUP_ID $SERVER_GROUP_NAME \ + && useradd -r -g $SERVER_GROUP_ID -u $SERVER_USER_ID $SERVER_USER_NAME \ + && true + RUN set -eux \ && DEBIAN_FRONTEND=noninteractive apt-get update -qq \ && DEBIAN_FRONTEND=noninteractive apt-get install -qq -y --no-install-recommends --no-install-suggests \ - ca-certificates \ - tzdata \ + ca-certificates \ + tzdata \ # Clean up local repository of retrieved packages and remove the package lists && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ && true -COPY ./docker/devel/static-web-server /usr/local/bin/ -COPY ./docker/debian/entrypoint.sh / -COPY ./docker/public /public +RUN set -eux \ + && mkdir -p /home/$SERVER_USER_NAME/public \ + && chown -R $SERVER_USER_NAME:$SERVER_GROUP_NAME /home/$SERVER_USER_NAME \ + && ln -s /home/$SERVER_USER_NAME/public /var/public \ + && chown -R $SERVER_USER_NAME:$SERVER_GROUP_NAME /var/public \ + && true + +USER $SERVER_USER_NAME:$SERVER_GROUP_NAME + +COPY --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + ./docker/devel/static-web-server /usr/local/bin/static-web-server +COPY --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + ./docker/debian/entrypoint.sh /usr/local/bin/entrypoint.sh +COPY --chown=$SERVER_USER_NAME:$SERVER_GROUP_NAME \ + ./docker/public /home/$SERVER_USER_NAME/public + +WORKDIR /home/$SERVER_USER_NAME EXPOSE 80 STOPSIGNAL SIGQUIT -ENTRYPOINT ["/entrypoint.sh"] +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] CMD ["static-web-server"] @@ -33,5 +62,5 @@ LABEL org.opencontainers.image.vendor="Jose Quintana" \ org.opencontainers.image.url="https://github.com/static-web-server/static-web-server" \ org.opencontainers.image.title="Static Web Server" \ org.opencontainers.image.description="A cross-platform, high-performance and asynchronous web server for static files-serving." \ - org.opencontainers.image.version="${SERVER_VERSION}" \ - org.opencontainers.image.documentation="https://github.com/static-web-server/static-web-server" + org.opencontainers.image.version="$SERVER_VERSION" \ + org.opencontainers.image.documentation="https://static-web-server.net" diff --git a/docker/devel/Dockerfile.scratch b/docker/devel/Dockerfile.scratch index 6cf9e61c..747d6127 100644 --- a/docker/devel/Dockerfile.scratch +++ b/docker/devel/Dockerfile.scratch @@ -21,5 +21,5 @@ LABEL org.opencontainers.image.vendor="Jose Quintana" \ org.opencontainers.image.url="https://github.com/static-web-server/static-web-server" \ org.opencontainers.image.title="Static Web Server" \ org.opencontainers.image.description="A cross-platform, high-performance and asynchronous web server for static files-serving." \ - org.opencontainers.image.version="${SERVER_VERSION}" \ - org.opencontainers.image.documentation="https://github.com/static-web-server/static-web-server" + org.opencontainers.image.version="$SERVER_VERSION" \ + org.opencontainers.image.documentation="https://static-web-server.net" diff --git a/docker/scratch/Dockerfile b/docker/scratch/Dockerfile index b702dbfe..37298a6d6 100644 --- a/docker/scratch/Dockerfile +++ b/docker/scratch/Dockerfile @@ -25,5 +25,5 @@ LABEL org.opencontainers.image.vendor="Jose Quintana" \ org.opencontainers.image.url="https://github.com/static-web-server/static-web-server" \ org.opencontainers.image.title="Static Web Server" \ org.opencontainers.image.description="A cross-platform, high-performance and asynchronous web server for static files-serving." \ - org.opencontainers.image.version="${SERVER_VERSION}" \ - org.opencontainers.image.documentation="https://github.com/static-web-server/static-web-server" + org.opencontainers.image.version="$SERVER_VERSION" \ + org.opencontainers.image.documentation="https://static-web-server.net" diff --git a/docs/content/features/docker.md b/docs/content/features/docker.md index 1cfd3eda..fbf0d8ad 100644 --- a/docs/content/features/docker.md +++ b/docs/content/features/docker.md @@ -21,6 +21,23 @@ All Docker images are [Multi-Arch](https://www.docker.com/blog/how-to-rapidly-bu !!! tip "SWS statically-linked binary" All the Docker images use the SWS statically-linked binary, meaning that the binary is highly optimized, performant, and dependency-free thanks to [musl libc](https://www.musl-libc.org/). +## Rootless + +The **Debian** and **Alpine** Docker images are rootless **by default** using a dedicated `sws` user and group. This reduces the attack surface and improves security. + +!!! info "Remember" + Users can still run the containers as root if they _explicitly_ set the user to _root_ when running the container, e.g., using the `--user root` flag with `docker run`. + +The `static-web-server` binary and all files under `/home/sws` (home directory) are owned by the non-root `sws` user and group. + +For convenience, those paths are also available: + +- **Home directory:** `/home/sws` +- **Public directory:** `/home/sws/public` +- **Public directory symlink:** `/var/public` -> `/home/sws/public` + +The current working directory is the _home directory_ by default. + ## Run a container To give the server a quick try just run the following commands. diff --git a/docs/content/getting-started.md b/docs/content/getting-started.md index 1750fd01..171174d1 100644 --- a/docs/content/getting-started.md +++ b/docs/content/getting-started.md @@ -13,7 +13,7 @@ docker run --rm -it -p 8787:80 joseluisq/static-web-server:2 ``` !!! info "Docker Tip" - You can specify a Docker volume like `-v $HOME/my-public-dir:/public` to overwrite the default root directory. See [Docker examples](features/docker.md). + You can specify a Docker volume like `-v $HOME/my-public-dir:/var/public` to overwrite the default root directory. See [Docker examples](features/docker.md). - Type `static-web-server --help` or see the [Command-line arguments](./configuration/command-line-arguments.md) section. - See how to configure the server using a [configuration file](configuration/config-file.md).