16 Commits

Author SHA1 Message Date
3715ca5861 Update to 22.2.10 2022-07-19 19:03:18 +02:00
f44824f946 Update Nextcloud to 22.2.9 2022-06-20 23:38:18 +02:00
7e7c77ea75 Update to 22.2.8 2022-05-20 13:17:44 +02:00
5c9c873713 Update to 22.2.7 2022-04-21 23:26:28 +02:00
eeac6d79d9 Update Nextcloud to 22.2.6 2022-03-21 23:26:57 +01:00
c0229eabd6 Update Nextcloud to 22.2.5 2022-02-15 20:46:29 +01:00
7240120ac3 Update Nextcloud to 22.2.4 2022-01-27 21:08:00 +01:00
1a61a40cad Adjust workflow for branch 2021-12-08 21:17:07 +01:00
90381a94d0 Adding back smb support to the image 2021-12-07 16:52:51 +01:00
0b0a1da864 Fix typo in workflow cron argument 2021-12-07 16:52:51 +01:00
2bfc5e0eec Update README 2021-12-07 16:52:51 +01:00
d2861829ac Enable scan during build again and change trigger 2021-12-07 16:52:51 +01:00
e72b5f41c7 Update to Alpine 3.15 2021-12-07 16:52:51 +01:00
a5d934b8a9 Change .well-known regex 2021-12-07 16:52:51 +01:00
8c9f6b6cb7 Add imagick dependency 2021-12-07 16:52:51 +01:00
9867cd0938 Remove nc_port 2021-12-07 16:52:45 +01:00
11 changed files with 98 additions and 371 deletions

View File

@ -3,76 +3,47 @@ name: build
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: branches: [ version-22 ]
- master
- version-*
schedule: schedule:
# Build the image regularly (each Friday) # Build the image regularly (each Friday)
- cron: '23 04 * * 5' - cron: '23 04 * * 5'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/nextcloud
jobs: jobs:
build: build:
name: Build, push & sign name: Build, scan & push
runs-on: "ubuntu-latest" runs-on: "ubuntu-20.04"
permissions:
contents: read
packages: write
id-token: write
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Extract version for tags - name: Build an image from Dockerfile
run: | run: |
BRANCH="${GITHUB_REF#refs/heads/}" docker build \
VERSION=$(grep -oP '(?<=NEXTCLOUD_VERSION=).*' Dockerfile) -t ghcr.io/${{ github.actor }}/nextcloud:$(grep -oP '(?<=NEXTCLOUD_VERSION=).*' Dockerfile | head -c6) \
[ "$BRANCH" = "master" ] && echo "BRANCH_VERSION=latest" >> $GITHUB_ENV -t ghcr.io/${{ github.actor }}/nextcloud:$(grep -oP '(?<=NEXTCLOUD_VERSION=).*' Dockerfile | head -c2) \
echo "FULL_VERSION=${VERSION:0:7}" >> $GITHUB_ENV .
echo "MAJOR_VERSION=${VERSION:0:2}" >> $GITHUB_ENV
- name: Install cosign - name: Run Trivy vulnerability scanner
if: github.event_name != 'pull_request' uses: aquasecurity/trivy-action@master
uses: sigstore/cosign-installer@main
with: with:
cosign-release: 'v2.2.2' image-ref: 'ghcr.io/${{ github.actor }}/nextcloud'
format: 'template'
template: '@/contrib/sarif.tpl'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
vuln-type: "os"
- name: Set up Docker Buildx - name: Upload Trivy scan results to GitHub Security tab
uses: docker/setup-buildx-action@v1 uses: github/codeql-action/upload-sarif@v1
- name: Login to registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with: with:
registry: ${{ env.REGISTRY }} sarif_file: 'trivy-results.sarif'
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set Docker metadata - name: Login to the registry
id: meta run: >-
uses: docker/metadata-action@v3 echo "${{ secrets.GITHUB_TOKEN }}"
with: | docker login -u "${{ github.actor }}" --password-stdin ghcr.io
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
${{ env.BRANCH_VERSION }}
${{ env.FULL_VERSION }}
${{ env.MAJOR_VERSION }}
- name: Build and push Docker image - name: Push image to GitHub
id: build-and-push run: |
uses: docker/build-push-action@v2 docker push ghcr.io/${{ github.actor }}/nextcloud:$(grep -oP '(?<=NEXTCLOUD_VERSION=).*' Dockerfile | head -c6)
with: docker push ghcr.io/${{ github.actor }}/nextcloud:$(grep -oP '(?<=NEXTCLOUD_VERSION=).*' Dockerfile | head -c2)
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Sign the published Docker image
if: ${{ github.event_name != 'pull_request' }}
env:
COSIGN_EXPERIMENTAL: "true"
run: cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}

View File

@ -16,7 +16,7 @@ jobs:
- name: Run Trivy vulnerability scanner - name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master uses: aquasecurity/trivy-action@master
with: with:
image-ref: 'ghcr.io/${{ github.actor }}/nextcloud' image-ref: 'ghcr.io/hoellen/nextcloud'
format: 'template' format: 'template'
template: '@/contrib/sarif.tpl' template: '@/contrib/sarif.tpl'
output: 'trivy-results.sarif' output: 'trivy-results.sarif'

View File

@ -1,34 +1,25 @@
# -------------- Build-time variables -------------- # -------------- Build-time variables --------------
ARG NEXTCLOUD_VERSION=30.0.12 ARG NEXTCLOUD_VERSION=22.2.10
ARG PHP_VERSION=8.3 ARG PHP_VERSION=8.0
ARG NGINX_VERSION=1.26 ARG NGINX_VERSION=1.20
ARG ALPINE_VERSION=3.21 ARG ALPINE_VERSION=3.15
ARG HARDENED_MALLOC_VERSION=11 ARG HARDENED_MALLOC_VERSION=8
ARG SNUFFLEUPAGUS_VERSION=0.10.0
ARG UID=1000 ARG UID=1000
ARG GID=1000 ARG GID=1000
# nextcloud-30.0.12.tar.bz2
ARG SHA256_SUM="9e19b25f42273d4361218426b4762a766bee408cfa6aa8219f8c27f72095a7a8"
# Nextcloud Security <security@nextcloud.com> (D75899B9A724937A)
ARG GPG_FINGERPRINT="2880 6A87 8AE4 23A2 8372 792E D758 99B9 A724 937A"
# --------------------------------------------------- # ---------------------------------------------------
### Build PHP base ### Build PHP base
FROM docker.io/library/php:${PHP_VERSION}-fpm-alpine${ALPINE_VERSION} as base FROM php:${PHP_VERSION}-fpm-alpine${ALPINE_VERSION} as base
ARG SNUFFLEUPAGUS_VERSION ARG APCU_VERSION
ARG REDIS_VERSION
ENV IMAGICK_SHA 28f27044e435a2b203e32675e942eb8de620ee58
RUN apk -U upgrade \ RUN apk -U upgrade \
&& apk add -t build-deps \ && apk add -t build-deps \
$PHPIZE_DEPS \ $PHPIZE_DEPS \
freetype-dev \ freetype-dev \
git \
gmp-dev \ gmp-dev \
icu-dev \ icu-dev \
libjpeg-turbo-dev \ libjpeg-turbo-dev \
@ -45,7 +36,6 @@ RUN apk -U upgrade \
gmp \ gmp \
icu \ icu \
libjpeg-turbo \ libjpeg-turbo \
librsvg \
libpq \ libpq \
libpq \ libpq \
libwebp \ libwebp \
@ -61,48 +51,42 @@ RUN apk -U upgrade \
bcmath \ bcmath \
exif \ exif \
gd \ gd \
bz2 \
intl \ intl \
ldap \ ldap \
opcache \ opcache \
pcntl \ pcntl \
pdo_mysql \ pdo_mysql \
pdo_pgsql \ pdo_pgsql \
sysvsem \
zip \ zip \
gmp \ gmp \
&& pecl install smbclient \ && pecl install smbclient \
&& pecl install APCu \ && pecl install APCu \
&& pecl install redis \ && pecl install redis \
&& curl -L -o /tmp/imagick.tar.gz https://github.com/Imagick/imagick/archive/${IMAGICK_SHA}.tar.gz && tar --strip-components=1 -xf /tmp/imagick.tar.gz && phpize && ./configure && make && make install \ && pecl install imagick \
&& apk add --no-cache --virtual .imagick-runtime-deps imagemagick \
&& docker-php-ext-enable \ && docker-php-ext-enable \
smbclient \ smbclient \
redis \ redis \
imagick \ imagick \
&& cd /tmp && git clone --depth 1 --branch v${SNUFFLEUPAGUS_VERSION} https://github.com/jvoisin/snuffleupagus \
&& cd snuffleupagus/src && phpize && ./configure --enable-snuffleupagus && make && make install \
&& apk del build-deps \ && apk del build-deps \
&& rm -rf /var/cache/apk/* /tmp/* && rm -rf /var/cache/apk/*
### Build Hardened Malloc ### Build Hardened Malloc
ARG ALPINE_VERSION ARG ALPINE_VERSION
FROM docker.io/library/alpine:${ALPINE_VERSION} as build-malloc FROM alpine:${ALPINE_VERSION} as build-malloc
ARG HARDENED_MALLOC_VERSION ARG HARDENED_MALLOC_VERSION
ARG CONFIG_NATIVE=false ARG CONFIG_NATIVE=false
ARG VARIANT=light
RUN apk --no-cache add build-base git gnupg && cd /tmp \ RUN apk --no-cache add build-base git gnupg && cd /tmp \
&& wget -q https://github.com/thestinger.gpg && gpg --import thestinger.gpg \ && wget -q https://github.com/thestinger.gpg && gpg --import thestinger.gpg \
&& git clone --depth 1 --branch ${HARDENED_MALLOC_VERSION} https://github.com/GrapheneOS/hardened_malloc \ && git clone --depth 1 --branch ${HARDENED_MALLOC_VERSION} https://github.com/GrapheneOS/hardened_malloc \
&& cd hardened_malloc && git verify-tag $(git describe --tags) \ && cd hardened_malloc && git verify-tag $(git describe --tags) \
&& make CONFIG_NATIVE=${CONFIG_NATIVE} VARIANT=${VARIANT} && make CONFIG_NATIVE=${CONFIG_NATIVE}
### Fetch nginx ### Fetch nginx
FROM docker.io/library/nginx:${NGINX_VERSION}-alpine as nginx FROM nginx:${NGINX_VERSION}-alpine as nginx
### Build Nextcloud (production environemnt) ### Build Nextcloud (production environemnt)
@ -110,11 +94,10 @@ FROM base as nextcloud
COPY --from=nginx /usr/sbin/nginx /usr/sbin/nginx COPY --from=nginx /usr/sbin/nginx /usr/sbin/nginx
COPY --from=nginx /etc/nginx /etc/nginx COPY --from=nginx /etc/nginx /etc/nginx
COPY --from=build-malloc /tmp/hardened_malloc/out-light/libhardened_malloc-light.so /usr/local/lib/ COPY --from=build-malloc /tmp/hardened_malloc/libhardened_malloc.so /usr/local/lib/
ARG NEXTCLOUD_VERSION ARG NEXTCLOUD_VERSION
ARG SHA256_SUM ARG GPG_nextcloud="2880 6A87 8AE4 23A2 8372 792E D758 99B9 A724 937A"
ARG GPG_FINGERPRINT
ARG UID ARG UID
ARG GID ARG GID
@ -127,30 +110,31 @@ ENV UPLOAD_MAX_SIZE=10G \
CRON_MEMORY_LIMIT=1g \ CRON_MEMORY_LIMIT=1g \
DB_TYPE=sqlite3 \ DB_TYPE=sqlite3 \
DOMAIN=localhost \ DOMAIN=localhost \
PHP_HARDENING=true \ LD_PRELOAD="/usr/local/lib/libhardened_malloc.so /usr/lib/preloadable_libiconv.so"
LD_PRELOAD="/usr/local/lib/libhardened_malloc-light.so"
RUN apk --no-cache add \ RUN apk --no-cache add \
gnupg \ gnupg \
pcre2 \ gnu-libiconv \
pcre \
s6 \ s6 \
&& NEXTCLOUD_TARBALL="nextcloud-${NEXTCLOUD_VERSION}.tar.bz2" && cd /tmp \ && NEXTCLOUD_TARBALL="nextcloud-${NEXTCLOUD_VERSION}.tar.bz2" && cd /tmp \
&& wget -q https://download.nextcloud.com/server/releases/${NEXTCLOUD_TARBALL} \ && wget -q https://download.nextcloud.com/server/releases/${NEXTCLOUD_TARBALL} \
&& wget -q https://download.nextcloud.com/server/releases/${NEXTCLOUD_TARBALL}.sha512 \
&& wget -q https://download.nextcloud.com/server/releases/${NEXTCLOUD_TARBALL}.asc \ && wget -q https://download.nextcloud.com/server/releases/${NEXTCLOUD_TARBALL}.asc \
&& wget -q https://nextcloud.com/nextcloud.asc \ && wget -q https://nextcloud.com/nextcloud.asc \
&& echo "Verifying both integrity and authenticity of ${NEXTCLOUD_TARBALL}..." \ && echo "Verifying both integrity and authenticity of ${NEXTCLOUD_TARBALL}..." \
&& CHECKSUM_STATE=$(echo -n $(echo "${SHA256_SUM} ${NEXTCLOUD_TARBALL}" | sha256sum -c) | tail -c 2) \ && CHECKSUM_STATE=$(echo -n $(sha512sum -c ${NEXTCLOUD_TARBALL}.sha512) | tail -c 2) \
&& if [ "${CHECKSUM_STATE}" != "OK" ]; then echo "Error: checksum does not match" && exit 1; fi \ && if [ "${CHECKSUM_STATE}" != "OK" ]; then echo "Error: checksum does not match" && exit 1; fi \
&& gpg --import nextcloud.asc \ && gpg --import nextcloud.asc \
&& FINGERPRINT="$(LANG=C gpg --verify ${NEXTCLOUD_TARBALL}.asc ${NEXTCLOUD_TARBALL} 2>&1 \ && FINGERPRINT="$(LANG=C gpg --verify ${NEXTCLOUD_TARBALL}.asc ${NEXTCLOUD_TARBALL} 2>&1 \
| sed -n "s#Primary key fingerprint: \(.*\)#\1#p")" \ | sed -n "s#Primary key fingerprint: \(.*\)#\1#p")" \
&& if [ -z "${FINGERPRINT}" ]; then echo "Error: invalid GPG signature!" && exit 1; fi \ && if [ -z "${FINGERPRINT}" ]; then echo "Error: invalid GPG signature!" && exit 1; fi \
&& if [ "${FINGERPRINT}" != "${GPG_FINGERPRINT}" ]; then echo "Error: wrong GPG fingerprint" && exit 1; fi \ && if [ "${FINGERPRINT}" != "${GPG_nextcloud}" ]; then echo "Error: wrong GPG fingerprint" && exit 1; fi \
&& echo "All seems good, now unpacking ${NEXTCLOUD_TARBALL}..." \ && echo "All seems good, now unpacking ${NEXTCLOUD_TARBALL}..." \
&& mkdir /nextcloud && tar xjf ${NEXTCLOUD_TARBALL} --strip 1 -C /nextcloud \ && mkdir /nextcloud && tar xjf ${NEXTCLOUD_TARBALL} --strip 1 -C /nextcloud \
&& apk del gnupg && rm -rf /tmp/* /root/.gnupg \ && apk del gnupg && rm -rf /tmp/* /root/.gnupg \
&& adduser -g ${GID} -u ${UID} --disabled-password --gecos "" nextcloud \ && adduser -g ${GID} -u ${UID} --disabled-password --gecos "" nextcloud \
&& chown -R nextcloud:nextcloud /nextcloud/config && chown -R nextcloud:nextcloud /nextcloud
COPY --chown=nextcloud:nextcloud rootfs / COPY --chown=nextcloud:nextcloud rootfs /
@ -164,9 +148,8 @@ VOLUME /data /nextcloud/config /nextcloud/apps2 /nextcloud/themes
EXPOSE 8888 EXPOSE 8888
LABEL org.opencontainers.image.description="All-in-one Nextcloud image, based on Alpine Linux" \ LABEL description="A server software for creating file hosting services" \
org.opencontainers.image.version="${NEXTCLOUD_VERSION}" \ nextcloud="Nextcloud v${NEXTCLOUD_VERSION}" \
org.opencontainers.image.authors="Hoellen <dev@hoellen.eu>" \ maintainer="Hoellen <dev@hoellen.eu>"
org.opencontainers.image.source="https://github.com/hoellen/docker-nextcloud"
CMD ["run.sh"] CMD ["run.sh"]

106
README.md
View File

@ -3,115 +3,71 @@
Nextcloud [official website](https://nextcloud.com/) and [source code](https://github.com/nextcloud). Nextcloud [official website](https://nextcloud.com/) and [source code](https://github.com/nextcloud).
## About ## Why this image?
This non-official image is intended as an **all-in-one** (as in monolithic) Nextcloud **production** image. If you're not sure you want this image, you should probably use [the official image](https://hub.docker.com/r/nextcloud). The main goal is to provide an easy-to-use image with decent security standards. This repository is mainly based on [Wondefall/docker-nextcloud](https://github.com/Wonderfall/docker-nextcloud). This non-official image is intended as an **all-in-one** (as in monolithic) Nextcloud **production** image. It is based on the [Wondefall/docker-nextcloud](https://github.com/Wonderfall/docker-nextcloud) image. If you're not sure you want this image, you should probably use [the official image](https://hub.docker.com/r/nextcloud).
Check out Nextcloud [official website](https://nextcloud.com/) and [source code](https://github.com/nextcloud). ## Security
Don't run random images from random dudes on the Internet. Ideally, you want to maintain and build it yourself.
___ Images are scanned every day by [Trivy](https://github.com/aquasecurity/trivy) for OS vulnerabilities. Latest tag/version is automatically built weekly, so you should often update your images regardless if you're already using the latest Nextcloud version.
* [Features](#features) If you're building manually, you should always build production images without cache (use `docker build --no-cache` for instance). Latest dependencies will hence be used instead of outdated ones due to a cached layer.
* [Security](#security)
* [Tags](#tags)
* [Build-time variables](#build-time-variables)
* [Environment variables](#environment-variables)
* [Runtime](#runtime)
* [Startup](#startup)
* [Volumes](#volumes)
* [Ports](#ports)
* [Migration](#migration)
* [Usage](#usage)
## Features ## Features
- Based on [Alpine Linux](https://alpinelinux.org/).
- Fetching PHP/nginx from their official images. - Fetching PHP/nginx from their official images.
- **Rootless**: no privilege at any time, even at startup. - **Rootless**: no privilege at any time, even at startup.
- Uses [s6](https://skarnet.org/software/s6/) as a lightweight process supervisor. - Includes **hardened_malloc**, a hardened memory allocator.
- Supports MySQL/MariaDB, PostgresQL and SQLite3 database backends.
- Includes OPcache and APCu for improved caching & performance, also supports redis.
- Tarball integrity & authenticity checked during build process.
- Includes **hardened_malloc**, [a hardened memory allocator](https://github.com/GrapheneOS/hardened_malloc).
- Includes **Snuffleupagus**, [a PHP security module](https://github.com/jvoisin/snuffleupagus).
- Includes a simple **built-in cron** system. - Includes a simple **built-in cron** system.
- Much easier to maintain thanks to multi-stages build. - Much easier to maintain thanks to multi-stages build.
- Does not include imagick, samba, etc. by default. - Does not include imagick, samba, etc. by default.
You're free to make your own image based on this one if you want a specific feature. Uncommon features won't be included as they can increase attack surface: this image intends to stay **minimal**, but **functional enough** to cover basic needs. You're free to make your own image based on this one if you want a specific feature. Uncommon features won't be included as they can increase attack surface: this image intends to stay **minimal**, but **functional enough** to cover basic needs.
## Security
Don't run random images from random dudes on the Internet. Ideally, you want to maintain and build it yourself.
- **Images are scanned every day** by [Trivy](https://github.com/aquasecurity/trivy) for OS vulnerabilities. Known vulnerabilities will be automatically uploaded to [GitHub Security Lab](https://github.com/Wonderfall/docker-nextcloud/security/code-scanning) for full transparency. This also warns me if I have to take action to fix a vulnerability.
- **Latest tag/version is automatically built weekly**, so you should often update your images regardless if you're already using the latest Nextcloud version.
- **Build production images without cache** (use `docker build --no-cache` for instance) if you want to build your images manually. Latest dependencies will hence be used instead of outdated ones due to a cached layer.
- **A security module for PHP called [Snuffleupagus](https://github.com/jvoisin/snuffleupagus) is used by default**. This module aims at killing entire bug and security exploit classes (including weak PRNG, file-upload based code execution), thus raising the cost of attacks. For now we're using a configuration file derived from [the default one](https://github.com/jvoisin/snuffleupagus/blob/master/config/default_php8.rules), with some explicit exceptions related to Nextcloud. This configuration file is tested and shouldn't break basic functionality, but it can cause issues in specific and untested use cases: if that happens to you, get logs from either `syslog` or `/nginx/logs/error.log` inside the container, and [open an issue](https://github.com/hoellen/docker-nextcloud/issues). You can also disable the security module altogether by changing the `PHP_HARDENING` environment variable to `false` before recreating the container.
- **Images are signed with the GitHub-provided OIDC token in Actions** using the experimental "keyless" signing feature provided by [cosign](https://github.com/sigstore/cosign). You can verify the image signature using `cosign` as well:
```
COSIGN_EXPERIMENTAL=true cosign verify ghcr.io/hoellen/nextcloud
```
Verifying the signature isn't a requirement, and might not be as seamless as using *Docker Content Trust* (which is not supported by GitHub's OCI registry). However, it's strongly recommended to do so in a sensitive environment to ensure the authenticity of the images and further limit the risk of supply chain attacks.
## Tags ## Tags
- `latest` : latest Nextcloud version - `latest` : latest Nextcloud version
- `x` : latest Nextcloud x.x (e.g. `30`) - `x` : latest Nextcloud x.x (e.g. `21`)
- `x.x.x` : Nextcloud x.x.x (e.g. `30.0.0`) - `x.x.x` : Nextcloud x.x.x (e.g. `21.0.2`)
You can always have a glance [here](https://github.com/users/hoellen/packages/container/package/nextcloud). You can always have a glance [here](https://github.com/users/hoellen/packages/container/package/nextcloud).
Only the **latest stable version** will be maintained by myself. Only the **latest stable version** will be maintained by myself.
*Note: automated builds only target `linux/amd64` (x86_64). There is no technical reason preventing the image to be built for `arm64` (in fact you can build it yourself), but GitHub Actions runners are limited in memory, and this limit makes it currently impossible to target both platforms.*
## Build-time variables ## Build-time variables
| Variable | Description |
| --------------------------- | -------------------------- |
| **NEXTCLOUD_VERSION** | version of Nextcloud |
| **ALPINE_VERSION** | version of Alpine Linux |
| **PHP_VERSION** | version of PHP |
| **NGINX_VERSION** | version of nginx |
| **APCU_VERSION** | version of APCu (php ext) |
| **REDIS_VERSION** | version of redis (php ext) |
| **HARDENED_MALLOC_VERSION** | version of hardened_malloc |
| **CONFIG_NATIVE** | native code for hmalloc |
| **UID** | user id (default: 1000) |
| **GID** | group id (default: 1000) |
| Variable | Description | Default | For convenience they were put at [the very top of the Dockerfile](https://github.com/hoellen/docker-nextcloud/blob/master/Dockerfile#L1-L13) and their usage should be quite explicit if you intend to build this image yourself.
| --------------------------- | -------------------------------------- | ------------------ |
| **NEXTCLOUD_VERSION** | version of Nextcloud | * |
| **ALPINE_VERSION** | version of Alpine Linux | * |
| **PHP_VERSION** | version of PHP | * |
| **NGINX_VERSION** | version of nginx | * |
| **HARDENED_MALLOC_VERSION** | version of hardened_malloc | * |
| **SNUFFLEUPAGUS_VERSION** | version of Snuffleupagus (php ext) | * |
| **SHA256_SUM** | checksum of Nextcloud tarball (sha256) | * |
| **GPG_FINGERPRINT** | fingerprint of Nextcloud GPG key | * |
| **UID** | user id | 1000 |
| **GID** | group id | 1000 |
| **CONFIG_NATIVE** | native code for hardened_malloc | false |
| **VARIANT** | variant of hardened_malloc (see repo) | light |
*\* latest known available, likely to change regularly* ## Environment variables (Dockerfile)
For convenience they were put at [the very top of the Dockerfile](https://github.com/Wonderfall/docker-nextcloud/blob/main/Dockerfile#L1-L13) and their usage should be quite explicit if you intend to build this image yourself. If you intend to change `NEXTCLOUD_VERSION`, change `SHA256_SUM` accordingly.
## Environment variables
### Runtime
| Variable | Description | Default | | Variable | Description | Default |
| ------------------------- | --------------------------- | ------------------ | | ------------------------- | --------------------------- | ------------------ |
| **UPLOAD_MAX_SIZE** | file upload maximum size | 10G | | **UPLOAD_MAX_SIZE** | file upload maximum size | 10G |
| **APC_SHM_SIZE** | apc shared memory size | 128M | | **APC_SHM_SIZE** | apc shared memory size | 128M |
| **OPCACHE_MEM_SIZE** | opcache available memory | 128M |
| **MEMORY_LIMIT** | max php command mem usage | 512M | | **MEMORY_LIMIT** | max php command mem usage | 512M |
| **CRON_PERIOD** | cron time interval (min.) | 5m | | **CRON_PERIOD** | cron time interval (min.) | 5m |
| **CRON_MEMORY_LIMIT** | cron max memory usage | 1G | | **CRON_MEMORY_LIMIT** | cron max memory usage | 1G |
| **DB_TYPE** | sqlite3, mysql, pgsql | sqlite3 | | **DB_TYPE** | sqlite3, mysql, pgsql | sqlite3 |
| **DOMAIN** | host domain | localhost | | **DOMAIN** | host domain | localhost |
| **PHP_HARDENING** | enables snuffleupagus | true |
Leave them at default if you're not sure what you're doing. Leave them at default if you're not sure what you're doing.
### Startup ## Environment variables (used by setup.sh)
| Variable | Description | | Variable | Description |
| ------------------------- | --------------------------- | | ------------------------- | --------------------------- |
| **ADMIN_USER** | admin username | | **ADMIN_USER** | admin username |
| **ADMIN_PASSWORD** | admin password | | **ADMIN_PASSWORD** | admin password |
| **DB_TYPE** | sqlite3, mysql, pgsql | | **DB_TYPE** | sqlit3, mysql, pgsql |
| **DB_NAME** | name of the database | | **DB_NAME** | name of the database |
| **DB_USER** | name of the database user | | **DB_USER** | name of the database user |
| **DB_PASSWORD** | password of the db user | | **DB_PASSWORD** | password of the db user |
@ -122,29 +78,24 @@ Leave them at default if you're not sure what you're doing.
The usage of [Docker secrets](https://docs.docker.com/engine/swarm/secrets/) will be considered in the future, but `config.php` already covers quite a lot. The usage of [Docker secrets](https://docs.docker.com/engine/swarm/secrets/) will be considered in the future, but `config.php` already covers quite a lot.
## Volumes ## Volumes
| Variable | Description | | Variable | Description |
| ------------------------- | -------------------------- | | ------------------------- | -------------------------- |
| **/data** | data files | | **/data** | data files |
| **/nextcloud/config** | config files | | **/nextcloud/config** | config files |
| **/nextcloud/apps2** | 3rd-party apps | | **/nextcloud/apps2** | 3rd-party apps |
| **/nextcloud/themes** | custom themes | | **/nextcloud/themes** | custom themes |
| **/php/session** | PHP session files |
*Note: mounting `/php/session` isn't required but could be desirable in some circumstances.*
## Ports ## Ports
| Port | Use | | Port | Use |
| ------------------------- | -------------------------- | | ------------------------- | -------------------------- |
| **8888** (tcp) | Nextcloud web | | **8888** (tcp) | Nextcloud web |
A reverse proxy like [Traefik](https://doc.traefik.io/traefik/) or [Caddy](https://caddyserver.com/) can be used, and you should consider: A reverse proxy like [Traefik](https://doc.traefik.io/traefik/) or [Caddy](https://caddyserver.com/) can be used, and you should consider:
- Redirecting all HTTP traffic to HTTPS - Redirecting all HTTP traffic to HTTPS
- Setting the [HSTS header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) correctly - Setting the [HSTS header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) correctly
## Migration ## Migration from the legacy image
From now on you'll need to make sure all volumes have proper permissions. The default UID/GID is now 1000, so you'll need to build the image yourself if you want to change that, or you can just change the actual permissions of the volumes using `chown -R 1000:1000`. The flexibility provided by the legacy image came at some cost (performance & security), therefore this feature won't be provided anymore. From now on you'll need to make sure all volumes have proper permissions. The default UID/GID is now 1000, so you'll need to build the image yourself if you want to change that, or you can just change the actual permissions of the volumes using `chown -R 1000:1000`. The flexibility provided by the legacy image came at some cost (performance & security), therefore this feature won't be provided anymore.
Other changes that should be reflected in your configuration files: Other changes that should be reflected in your configuration files:
@ -154,6 +105,5 @@ Other changes that should be reflected in your configuration files:
You should edit your `docker-compose.yml` and `config.php` accordingly. You should edit your `docker-compose.yml` and `config.php` accordingly.
## Usage ## Get started
*To do.* *To do.*

View File

@ -1,30 +1,14 @@
# Security Policy # Security Policy
## Supported versions ## Supported Versions
All versions of the Nextcloud community version which still receive updates will be supported As of now, only the latest stable version will be supported.
and will receive the minor version updates and security patches.
| Version | Supported | | Version | Supported |
| ------- | ------------------ | | ------- | ------------------ |
| 30. x | :white_check_mark: | | 21. x | :white_check_mark: |
| 29. x | :white_check_mark: |
| 28. x | :white_check_mark: |
| 27. x | :negative_squared_cross_mark: |
| 26. x | :negative_squared_cross_mark: |
| 25. x | :negative_squared_cross_mark: |
| 24. x | :negative_squared_cross_mark: |
| 23. x | :negative_squared_cross_mark: |
| 22. x | :negative_squared_cross_mark: |
Please update to the latest version available. Major migrations are always tested before being pushed. ## Reporting a Vulnerability
An up-to-date list of the currently maintained Nextcloud versions can also be found in the [Nextcloud Repository Wiki](https://github.com/nextcloud/server/wiki/Maintenance-and-Release-Schedule).
## Automated vulnerability scanning
Uploaded images are regularly scanned for [OS vulnerabilities](https://github.com/Wonderfall/docker-nextcloud/security/code-scanning).
## Reporting a vulnerability
*Upstream* vulnerabilities should be reported to *upstream* projects according to their own security policies. *Upstream* vulnerabilities should be reported to *upstream* projects according to their own security policies.
@ -33,4 +17,4 @@ Regarding vulnerabilities specific to this project:
- Unsafe defaults - Unsafe defaults
- Dependencies security updates - Dependencies security updates
Those can be disclosed in private to `dev@hoellen.eu`. Those can be disclosed in private to `wonderfall@pm.me` or `wonderfall:targaryen.house` on Matrix (preferred).

View File

@ -18,10 +18,11 @@ server {
add_header Referrer-Policy "no-referrer" always; add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always; add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always; add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "noindex, nofollow" always; add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "0" always; add_header X-XSS-Protection "1; mode=block" always;
location = /robots.txt { location = /robots.txt {
allow all; allow all;
@ -30,8 +31,8 @@ server {
} }
location ^~ /.well-known { location ^~ /.well-known {
location = /.well-known/carddav { return 301 $nc_proto://$host/remote.php/dav/; } location = /.well-known/carddav { return 301 $nc_proto://$host/remote.php/dav; }
location = /.well-known/caldav { return 301 $nc_proto://$host/remote.php/dav/; } location = /.well-known/caldav { return 301 $nc_proto://$host/remote.php/dav; }
location ^~ /.well-known { return 301 $nc_proto://$host/index.php$uri; } location ^~ /.well-known { return 301 $nc_proto://$host/index.php$uri; }
try_files $uri $uri/ =404; try_files $uri $uri/ =404;
} }
@ -48,7 +49,7 @@ server {
return 404; return 404;
} }
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+|.+\/richdocumentscode\/proxy)\.php(?:$|\/) { location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
include /etc/nginx/fastcgi_params; include /etc/nginx/fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.*)$; fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
@ -61,18 +62,18 @@ server {
fastcgi_read_timeout 1200; fastcgi_read_timeout 1200;
} }
location ~ ^\/(?:updater|ocs-provider)(?:$|\/) { location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404; try_files $uri/ =404;
index index.php; index index.php;
} }
location ~ \.(?:css|js|mjs|svg|gif|png|jpg|ico|wasm|tflite|map|ogg|flac)$ { location ~ \.(?:css|js|svg|gif|map)$ {
try_files $uri /index.php$uri$is_args$args; try_files $uri /index.php$uri$is_args$args;
expires 6M; expires 6M;
access_log off; access_log off;
} }
location ~ \.(otf|woff2)?$ { location ~ \.woff2?$ {
try_files $uri /index.php$uri$is_args$args; try_files $uri /index.php$uri$is_args$args;
expires 7d; expires 7d;
access_log off; access_log off;

View File

@ -9,11 +9,6 @@ events {
http { http {
include /etc/nginx/mime.types; include /etc/nginx/mime.types;
# Add .mjs as a file extension for javascript
# https://github.com/nextcloud/server/pull/36057
types {
application/javascript mjs;
}
default_type application/octet-stream; default_type application/octet-stream;
access_log /nginx/logs/access.log combined; access_log /nginx/logs/access.log combined;

View File

@ -9,22 +9,6 @@ sed -i -e "s/<APC_SHM_SIZE>/$APC_SHM_SIZE/g" /usr/local/etc/php/conf.d/apcu.ini
-e "s/<UPLOAD_MAX_SIZE>/$UPLOAD_MAX_SIZE/g" /etc/nginx/nginx.conf /usr/local/etc/php-fpm.conf \ -e "s/<UPLOAD_MAX_SIZE>/$UPLOAD_MAX_SIZE/g" /etc/nginx/nginx.conf /usr/local/etc/php-fpm.conf \
-e "s/<MEMORY_LIMIT>/$MEMORY_LIMIT/g" /usr/local/etc/php-fpm.conf -e "s/<MEMORY_LIMIT>/$MEMORY_LIMIT/g" /usr/local/etc/php-fpm.conf
# Enable Snuffleupagus
if [ "$PHP_HARDENING" == "true" ] && [ ! -f /usr/local/etc/php/conf.d/snuffleupagus.ini ]; then
echo "Enabling Snuffleupagus..."
cp /usr/local/etc/php/snuffleupagus/* /usr/local/etc/php/conf.d
fi
# Check if database is available
if [ -n "${DB_TYPE}" ] && [ "${DB_TYPE}" != "sqlite3" ]; then
DB_PORT=${DB_PORT:-$( [ "${DB_TYPE}" = "pgsql" ] && echo 5432 || echo 3306 )}
until nc -z "${DB_HOST:-nextcloud-db}" "${DB_PORT}"
do
echo "waiting for the database container..."
sleep 1
done
fi
# If new install, run setup # If new install, run setup
if [ ! -f /nextcloud/config/config.php ]; then if [ ! -f /nextcloud/config/config.php ]; then
touch /nextcloud/config/CAN_INSTALL touch /nextcloud/config/CAN_INSTALL
@ -34,4 +18,4 @@ else
fi fi
# Run processes # Run processes
exec /usr/bin/s6-svscan /etc/s6.d exec /bin/s6-svscan /etc/s6.d

View File

@ -6,5 +6,3 @@ opcache.memory_consumption=<OPCACHE_MEM_SIZE>
opcache.interned_strings_buffer=16 opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000 opcache.max_accelerated_files=10000
opcache.revalidate_freq=60 opcache.revalidate_freq=60
opcache.jit=disable
opcache.jit_buffer_size=0

View File

@ -1,137 +0,0 @@
# This is the default configuration file for Snuffleupagus (https://snuffleupagus.rtfd.io),
# for php8.
# It contains "reasonable" defaults that won't break your websites,
# and a lot of commented directives that you can enable if you want to
# have a better protection.
# Harden the PRNG
sp.harden_random.enable();
# Disabled XXE
#sp.xxe_protection.enable();
# Global configuration variables
# sp.global.secret_key("YOU _DO_ NEED TO CHANGE THIS WITH SOME RANDOM CHARACTERS.");
# Globally activate strict mode
# https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict
sp.global_strict.enable();
# Prevent unserialize-related exploits
# sp.unserialize_hmac.enable();
# Only allow execution of read-only files. This is a low-hanging fruit that you should enable.
# sp.readonly_exec.enable();
# PHP has a lot of wrappers, most of them aren't usually useful, you should
# only enable the ones you're using.
# sp.wrappers_whitelist.list("file,php,phar");
# Prevent sloppy comparisons.
sp.sloppy_comparison.enable();
# Use SameSite on session cookie
# https://snuffleupagus.readthedocs.io/features.html#protection-against-cross-site-request-forgery
sp.cookie.name("PHPSESSID").samesite("lax");
# Nextcloud whitelist (tested with Nextcloud 27.0.1)
sp.disable_function.function("function_exists").param("function").value("proc_open").filename("/nextcloud/3rdparty/symfony/console/Terminal.php").allow();
sp.disable_function.function("function_exists").param("function").value("exec").filename("/nextcloud/lib/private/legacy/OC_Helper.php").allow();
sp.disable_function.function("function_exists").param("function").value("exec").filename("/nextcloud/lib/public/Util.php").allow();
sp.disable_function.function("proc_open").filename("/nextcloud/3rdparty/symfony/console/Terminal.php").allow();
sp.disable_function.function("ini_set").param("option").value_r("display_errors").filename("/nextcloud/lib/base.php").allow();
sp.disable_function.function("ini_get").param("option").value("open_basedir").filename("/nextcloud/3rdparty/bantu/ini-get-wrapper/src/IniGetWrapper.php").allow();
sp.disable_function.function("ini_get").param("option").value_r("suhosin").filename("/nextcloud/3rdparty/bantu/ini-get-wrapper/src/IniGetWrapper.php").allow();
sp.disable_function.function("ini_get").param("option").value("open_basedir").filename("/nextcloud/apps2/twofactor_webauthn/vendor/symfony/process/ExecutableFinder.php").allow();
sp.disable_function.function("ini_get").param("option").value("open_basedir").filename("/nextcloud/3rdparty/symfony/process/ExecutableFinder.php").allow();
sp.disable_function.function("ini_get").param("option").value("allow_url_fopen").filename("/nextcloud/3rdparty/guzzlehttp/guzzle/src/Utils.php").allow();
sp.disable_function.function("exec").param("command").value("apachectl -M | grep mpm").filename("/nextcloud/apps2/spreed/lib/Settings/Admin/AdminSettings.php").allow();
# Nextcloud inherently enables XXE-Protection since 27.0.1, therefore, drop setting a new external entity loader
sp.disable_function.function("libxml_set_external_entity_loader").filename("/nextcloud/lib/base.php").allow();
sp.disable_function.function("libxml_set_external_entity_loader").drop();
# Harden the `chmod` function (0777 (oct = 511, 0666 = 438)
sp.disable_function.function("chmod").param("permissions").value("438").drop();
sp.disable_function.function("chmod").param("permissions").value("511").drop();
# Prevent various `mail`-related vulnerabilities
sp.disable_function.function("mail").param("additional_parameters").value_r("\\-").drop();
# Since it's now burned, me might as well mitigate it publicly
sp.disable_function.function("putenv").param("assignment").value_r("LD_").drop()
# This one was burned in Nov 2019 - https://gist.github.com/LoadLow/90b60bd5535d6c3927bb24d5f9955b80
sp.disable_function.function("putenv").param("assignment").value_r("GCONV_").drop()
# Since people are stupid enough to use `extract` on things like $_GET or $_POST, we might as well mitigate this vector
sp.disable_function.function("extract").param("array").value_r("^_").drop()
sp.disable_function.function("extract").param("flags").value("0").drop()
# This is also burned:
# ini_set('open_basedir','..');chdir('..');…;chdir('..');ini_set('open_basedir','/');echo(file_get_contents('/etc/passwd'));
# Since we have no way of matching on two parameters at the same time, we're
# blocking calls to open_basedir altogether: nobody is using it via ini_set anyway.
# Moreover, there are non-public bypasses that are also using this vector ;)
sp.disable_function.function("ini_set").param("option").value_r("open_basedir").drop()
# Prevent various `include`-related vulnerabilities
sp.disable_function.function("require_once").value_r("\.(inc|phtml|php)$").allow();
sp.disable_function.function("include_once").value_r("\.(inc|phtml|php)$").allow();
sp.disable_function.function("require").value_r("\.(inc|phtml|php)$").allow();
sp.disable_function.function("include").value_r("\.(inc|phtml|php)$").allow();
sp.disable_function.function("require_once").drop()
sp.disable_function.function("include_once").drop()
sp.disable_function.function("require").drop()
sp.disable_function.function("include").drop()
# Prevent `system`-related injections
sp.disable_function.function("system").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
sp.disable_function.function("shell_exec").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
sp.disable_function.function("exec").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
sp.disable_function.function("proc_open").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
# Prevent runtime modification of interesting things
sp.disable_function.function("ini_set").param("option").value("assert.active").drop();
sp.disable_function.function("ini_set").param("option").value("zend.assertions").drop();
sp.disable_function.function("ini_set").param("option").value("memory_limit").drop();
sp.disable_function.function("ini_set").param("option").value("include_path").drop();
sp.disable_function.function("ini_set").param("option").value("open_basedir").drop();
# Detect some backdoors via environment recon
sp.disable_function.function("ini_get").param("option").value("allow_url_fopen").drop();
sp.disable_function.function("ini_get").param("option").value("open_basedir").drop();
sp.disable_function.function("ini_get").param("option").value_r("suhosin").drop();
sp.disable_function.function("function_exists").param("function").value("eval").drop();
sp.disable_function.function("function_exists").param("function").value("exec").drop();
sp.disable_function.function("function_exists").param("function").value("system").drop();
sp.disable_function.function("function_exists").param("function").value("shell_exec").drop();
sp.disable_function.function("function_exists").param("function").value("proc_open").drop();
sp.disable_function.function("function_exists").param("function").value("passthru").drop();
sp.disable_function.function("is_callable").param("value").value("eval").drop();
sp.disable_function.function("is_callable").param("value").value("exec").drop();
sp.disable_function.function("is_callable").param("value").value("system").drop();
sp.disable_function.function("is_callable").param("value").value("shell_exec").drop();
sp.disable_function.function("is_callable").param("value").value("proc_open").drop();
sp.disable_function.function("is_callable").param("value").value("passthru").drop();
# Ghetto error-based sqli detection
# sp.disable_function.function("mysql_query").ret("FALSE").drop();
# sp.disable_function.function("mysqli_query").ret("FALSE").drop();
# sp.disable_function.function("PDO::query").ret("FALSE").drop();
# Ensure that certificates are properly verified
sp.disable_function.function("curl_setopt").param("value").value("1").allow();
sp.disable_function.function("curl_setopt").param("value").value("2").allow();
# `81` is SSL_VERIFYHOST and `64` SSL_VERIFYPEER
sp.disable_function.function("curl_setopt").param("option").value("64").drop().alias("Please don't turn CURLOPT_SSL_VERIFYCLIENT off.");
sp.disable_function.function("curl_setopt").param("option").value("81").drop().alias("Please don't turn CURLOPT_SSL_VERIFYHOST off.");
# File upload
sp.disable_function.function("move_uploaded_file").param("to").value_r("\\.ph").drop();
sp.disable_function.function("move_uploaded_file").param("to").value_r("\\.ht").drop();
# Logging lockdown
sp.disable_function.function("ini_set").param("option").value_r("error_log").drop()
sp.disable_function.function("ini_set").param("option").value_r("error_reporting").drop()
sp.disable_function.function("ini_set").param("option").value_r("display_errors").drop()

View File

@ -1,2 +0,0 @@
extension=snuffleupagus.so
sp.configuration_file=/usr/local/etc/php/conf.d/nextcloud-php8.rules