Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .docker/garages3.config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

$bucket = getenv('GARAGES3_BUCKET') ?: 'nextcloud';
$key = getenv('GARAGES3_KEY');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use the generated Garage access key ID

The bootstrap writes the usable S3 access key to GARAGES3_KEY_ID and stores only the human key name (nextcloud-app) in GARAGES3_KEY, while this compose file only exports GARAGES3_KEY_ID to the app/cron containers. With the documented make setup-garages3 flow, this line leaves $key empty and throws at startup; if a user manually exports GARAGES3_KEY, Nextcloud would authenticate with the key name rather than the Garage access key ID. Read GARAGES3_KEY_ID or map it into GARAGES3_KEY here.

Useful? React with 👍 / 👎.

$secret = getenv('GARAGES3_SECRET');

if ($key === false || $key === '' || $secret === false || $secret === '') {
throw new RuntimeException('GARAGES3_KEY and GARAGES3_SECRET must be set for Garage S3 primary storage.');
}

$CONFIG = [
'objectstore' => [
'class' => '\\OC\\Files\\ObjectStore\\S3',
'arguments' => [
'bucket' => $bucket,
'hostname' => getenv('GARAGES3_HOSTNAME') ?: 'host.docker.internal',
'port' => (int) (getenv('GARAGES3_PORT') ?: 3900),
'region' => getenv('GARAGES3_REGION') ?: 'garage',
'key' => $key,
'secret' => $secret,
'use_ssl' => filter_var(getenv('GARAGES3_USE_SSL') ?: 'false', FILTER_VALIDATE_BOOLEAN),
'use_path_style' => filter_var(getenv('GARAGES3_USE_PATH_STYLE') ?: 'true', FILTER_VALIDATE_BOOLEAN),
'autocreate' => filter_var(getenv('GARAGES3_AUTOCREATE') ?: 'true', FILTER_VALIDATE_BOOLEAN),
'verify_bucket_exists' => filter_var(getenv('GARAGES3_VERIFY_BUCKET_EXISTS') ?: 'true', FILTER_VALIDATE_BOOLEAN),
],
],
];
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,16 @@ NEXTCLOUD_ADMIN_USER=
NEXTCLOUD_ADMIN_PASSWORD=

NEXTCLOUD_TRUSTED_DOMAINS=

# Garage S3 primary storage (used by docker-compose-garages3.yml)
GARAGES3_BUCKET=nextcloud
GARAGES3_KEY=
GARAGES3_KEY_ID=
GARAGES3_SECRET=
GARAGES3_HOSTNAME=host.docker.internal
GARAGES3_PORT=3900
GARAGES3_REGION=garage
GARAGES3_USE_SSL=false
GARAGES3_USE_PATH_STYLE=true
GARAGES3_AUTOCREATE=true
GARAGES3_VERIFY_BUCKET_EXISTS=true
27 changes: 27 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
COMPOSE ?= docker compose
GARAGES3_COMPOSE_FILE ?= docker-compose-garages3.yml

.PHONY: up-garages3 down-garages3 bootstrap-garages3 garage-status-garages3 start-garages3 wait-nextcloud-garages3 setup-garages3

up-garages3:
$(COMPOSE) -f $(GARAGES3_COMPOSE_FILE) up -d garage

down-garages3:
$(COMPOSE) -f $(GARAGES3_COMPOSE_FILE) down

garage-status-garages3:
$(COMPOSE) -f $(GARAGES3_COMPOSE_FILE) exec -T garage /garage status

bootstrap-garages3:
./scripts/bootstrap-garages3.sh

start-garages3:
$(COMPOSE) -f $(GARAGES3_COMPOSE_FILE) up -d db app web cron

wait-nextcloud-garages3:
@until $(COMPOSE) -f $(GARAGES3_COMPOSE_FILE) exec --user www-data app php occ status --output=json 2>/dev/null | grep -q '"installed":true'; do echo "Awaiting Nextcloud"; sleep 10; done

setup-garages3:
$(MAKE) bootstrap-garages3
$(MAKE) start-garages3
$(MAKE) wait-nextcloud-garages3
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,39 @@ docker compose exec -u www-data app ./occ db:convert-filecache-bigint

You can do this using environments and creating a file called `docker-compose.override.yml` to add new services.

### Garage S3 primary storage

Use `docker-compose-garages3.yml` when you want Nextcloud to store files in a Garage S3 bucket instead of the local `data/` directory.

The stack expects these values in `.env`:

- `GARAGES3_BUCKET`
- `GARAGES3_KEY`
- `GARAGES3_KEY_ID`
- `GARAGES3_SECRET`
- `GARAGES3_HOSTNAME`, defaulting to `host.docker.internal`
- `GARAGES3_PORT`, defaulting to `3900`
- `GARAGES3_REGION`, defaulting to `garage`

Create the bucket and access key in Garage before starting Nextcloud with this compose file. `GARAGES3_KEY_ID` must contain the Garage access key ID used by Nextcloud.

The Garage service uses `garage/garage.toml`. Update `rpc_secret` before using it in a real environment.

Use `make up-garages3` to start Garage, and `make bootstrap-garages3` to create the Garage bucket and access key.
The bootstrap updates `.env` in place with the generated Garage credentials.
Use `make setup-garages3` to run the full setup and wait for Nextcloud to report as installed.
The stack now uses PostgreSQL 16. If you already created the database volume with an older PostgreSQL major version, recreate or migrate that volume once before starting the updated compose file.

For a clean local installation, use `make reset-garages3`.
Use `make setup-garages3` if you want to keep the existing local state and only rerun the setup steps.

Basic flow:

1. Copy `.env.example` to `.env` if needed.
2. Update `garage/garage.toml` and replace the placeholder `rpc_secret`.
3. Run `make setup-garages3`.
4. Open the Nextcloud URL and finish the initial admin setup if it is still pending.

### PHP

- Create your `.ini` file at `volumes/php/` folder. Example: `volumes/php/xdebug.ini`
Expand Down
121 changes: 121 additions & 0 deletions docker-compose-garages3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
networks:
reverse-proxy:
external: true
name: reverse-proxy
internal:
driver: bridge

services:
db:
image: postgres:16
restart: always
volumes:
- ./volumes/postgres/data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-SECRET_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB:-nextcloud}
- POSTGRES_USER=${POSTGRES_USER:-nextcloud}
networks:
- internal

garage:
image: dxflrs/garage:v1.0.0
restart: unless-stopped
network_mode: host
volumes:
- ./garage/garage.toml:/etc/garage.toml
- ./garage/meta:/var/lib/garage/meta
- ./garage/data:/var/lib/garage/data

app:
build:
context: .docker/app
args:
NEXTCLOUD_VERSION: ${NEXTCLOUD_VERSION:-stable-fpm}
restart: unless-stopped
volumes:
- ./volumes/nextcloud:/var/www/html
- ./app-hooks/post-installation:/docker-entrypoint-hooks.d/post-installation
- ./.docker/garages3.config.php:/var/www/html/config/garages3.config.php:ro
environment:
- POSTGRES_DB=${POSTGRES_DB:-nextcloud}
- POSTGRES_USER=${POSTGRES_USER:-nextcloud}
- POSTGRES_PASSWORD
- POSTGRES_HOST=db
- NEXTCLOUD_ADMIN_USER
- NEXTCLOUD_ADMIN_PASSWORD
- NEXTCLOUD_ADMIN_EMAIL
- NEXTCLOUD_TRUSTED_DOMAINS
- SMTP_HOST
- SMTP_SECURE
- SMTP_PORT
- SMTP_AUTHTYPE
- SMTP_NAME
- SMTP_PASSWORD
- MAIL_FROM_ADDRESS
- MAIL_DOMAIN
- TZ
- GARAGES3_BUCKET
- GARAGES3_KEY_ID=${GARAGES3_KEY_ID:-${GARAGES3_KEY:-}}
- GARAGES3_SECRET=${GARAGES3_SECRET:-}
- GARAGES3_HOSTNAME=${GARAGES3_HOSTNAME:-host.docker.internal}
- GARAGES3_PORT=${GARAGES3_PORT:-3900}
- GARAGES3_REGION=${GARAGES3_REGION:-garage}
- GARAGES3_USE_SSL=${GARAGES3_USE_SSL:-0}
- GARAGES3_USE_PATH_STYLE=${GARAGES3_USE_PATH_STYLE:-1}
- GARAGES3_AUTOCREATE=${GARAGES3_AUTOCREATE:-1}
- GARAGES3_VERIFY_BUCKET_EXISTS=${GARAGES3_VERIFY_BUCKET_EXISTS:-1}
extra_hosts:
- host.docker.internal:host-gateway
depends_on:
- db
- garage
networks:
- internal

web:
build: .docker/web
restart: unless-stopped
volumes:
- ./volumes/nextcloud:/var/www/html:ro
- ./volumes/nginx/includes:/etc/nginx/conf.d/includes:rw
environment:
- VIRTUAL_HOST
- LETSENCRYPT_HOST
- LETSENCRYPT_EMAIL
- TZ
depends_on:
- app
networks:
- internal
- reverse-proxy

cron:
build:
context: .docker/app
args:
NEXTCLOUD_VERSION: ${NEXTCLOUD_VERSION:-stable-fpm}
restart: unless-stopped
environment:
- TZ
- GARAGES3_BUCKET
- GARAGES3_KEY_ID=${GARAGES3_KEY_ID:-${GARAGES3_KEY:-}}
- GARAGES3_SECRET=${GARAGES3_SECRET:-}
- GARAGES3_HOSTNAME=${GARAGES3_HOSTNAME:-host.docker.internal}
- GARAGES3_PORT=${GARAGES3_PORT:-3900}
- GARAGES3_REGION=${GARAGES3_REGION:-garage}
- GARAGES3_USE_SSL=${GARAGES3_USE_SSL:-0}
- GARAGES3_USE_PATH_STYLE=${GARAGES3_USE_PATH_STYLE:-1}
- GARAGES3_AUTOCREATE=${GARAGES3_AUTOCREATE:-1}
- GARAGES3_VERIFY_BUCKET_EXISTS=${GARAGES3_VERIFY_BUCKET_EXISTS:-1}
volumes:
- ./volumes/nextcloud:/var/www/html
- ./.docker/garages3.config.php:/var/www/html/config/garages3.config.php:ro
extra_hosts:
- host.docker.internal:host-gateway
depends_on:
- db
- garage
networks:
- internal
entrypoint: /cron.sh
33 changes: 33 additions & 0 deletions docs/README_ptBR.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,39 @@ docker compose exec -u www-data app ./occ db:convert-filecache-bigint

Você pode fazer isso usando variáveis de ambiente e criando um arquivo chamado `docker-compose.override.yml` para adicionar novos serviços.

### Storage primário Garage S3

Use `docker-compose-garages3.yml` quando quiser que o Nextcloud grave os arquivos em um bucket Garage S3 em vez do diretório local `data/`.

O stack espera estes valores em `.env`:

- `GARAGES3_BUCKET`
- `GARAGES3_KEY`
- `GARAGES3_KEY_ID`
- `GARAGES3_SECRET`
- `GARAGES3_HOSTNAME`, com padrão `host.docker.internal`
- `GARAGES3_PORT`, com padrão `3900`
- `GARAGES3_REGION`, com padrão `garage`

Crie o bucket e a chave de acesso no Garage antes de iniciar o Nextcloud com este compose. `GARAGES3_KEY_ID` deve conter o access key ID do Garage usado pelo Nextcloud.

O serviço Garage usa `garage/garage.toml`. Atualize `rpc_secret` antes de usar em ambiente real.

Use `make up-garages3` para subir o Garage e `make bootstrap-garages3` para criar o bucket e a chave de acesso no Garage.
O bootstrap atualiza `.env` com as credenciais geradas do Garage.
Use `make setup-garages3` para executar a configuração completa e aguardar o Nextcloud reportar como instalado.
O stack agora usa PostgreSQL 16. Se você já criou o volume do banco com uma versão major mais antiga, recrie ou migre esse volume uma vez antes de subir o compose atualizado.

Para uma instalação local limpa, use `make reset-garages3`.
Use `make setup-garages3` se quiser manter o estado local existente e apenas repetir as etapas de setup.

Fluxo básico:

1. Copie `.env.example` para `.env`, se necessário.
2. Atualize `garage/garage.toml` e substitua o `rpc_secret` placeholder.
3. Execute `make setup-garages3`.
4. Abra a URL do Nextcloud e finalize a configuração inicial do admin, se ainda estiver pendente.

### PHP

- Crie seu arquivo `.ini` na pasta `volumes/php/`. Exemplo: `volumes/php/xdebug.ini`
Expand Down
5 changes: 5 additions & 0 deletions garage/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
meta/*
data/*
!.gitignore
!meta/.gitkeep
!data/.gitkeep
1 change: 1 addition & 0 deletions garage/data/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

22 changes: 22 additions & 0 deletions garage/garage.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "lmdb"
metadata_auto_snapshot_interval = "6h"

replication_factor = 3

compression_level = 2

rpc_bind_addr = "[::]:3901"
rpc_public_addr = ":3901"
rpc_secret = "99eed281cbe8f1ae7bba15bc4091f57bdbacf913f0e2487ad53b65d88c4955fa"

[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.garage"

[s3_web]
bind_addr = "[::]:3902"
root_domain = ".web.garage"
index = "index.html"
1 change: 1 addition & 0 deletions garage/meta/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

15 changes: 14 additions & 1 deletion local/.env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,18 @@ POSTGRES_DB=nextcloud
POSTGRES_USER=nextcloud
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD=admin
NEXTCLOUD_TRUSTED_DOMAINS=mydomain.coop
NEXTCLOUD_TRUSTED_DOMAINS=localhost,127.0.0.1,localhost:8080,127.0.0.1:8080

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Separate trusted domains with spaces

The Nextcloud Docker image treats NEXTCLOUD_TRUSTED_DOMAINS as a space-separated list, so this comma-separated default is installed as one literal trusted domain. In the advertised local setup, requests to localhost:8080 or 127.0.0.1:8080 will still hit Nextcloud's untrusted-domain page after installation; use spaces here and in the compose default.

Useful? React with 👍 / 👎.

CA_STORE=/usr/local/share/ca-certificates
NEXTCLOUD_VERSION=stable-apache

GARAGES3_BUCKET=nextcloud
GARAGES3_KEY=
GARAGES3_KEY_ID=
GARAGES3_SECRET=
GARAGES3_HOSTNAME=garage
GARAGES3_PORT=3900
GARAGES3_REGION=garage
GARAGES3_USE_SSL=false
GARAGES3_USE_PATH_STYLE=true
GARAGES3_AUTOCREATE=true
GARAGES3_VERIFY_BUCKET_EXISTS=true
46 changes: 46 additions & 0 deletions local/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,49 @@ set-config:

init-cron:
docker-compose up -d cron

GARAGES3_COMPOSE_FILE=docker-compose-garages3.yml

init-all-garages3: init-garages3-db init-garages3-bootstrap init-garages3-volume init-garages3-perms init-garages3-app set-locale-garages3 set-config-garages3 init-garages3-cron

setup-garages3: init-all-garages3

reset-garages3: down-garages3 clean-garages3-state setup-garages3

down-garages3:
docker compose -f $(GARAGES3_COMPOSE_FILE) down

clean-garages3-state:
docker run --rm -v $(CURDIR)/volumes/postgres/data:/data alpine:3.20 sh -lc 'rm -rf /data/* /data/.[!.]* /data/..?*'
docker run --rm -v $(CURDIR)/volumes/nextcloud:/data alpine:3.20 sh -lc 'rm -rf /data/* /data/.[!.]* /data/..?*'
docker run --rm -v $(CURDIR)/garage:/data alpine:3.20 sh -lc 'mkdir -p /data/meta /data/data && rm -rf /data/meta/* /data/data/*'
rm -f .env

init-garages3-db:
docker compose -f $(GARAGES3_COMPOSE_FILE) up -d db
until docker compose -f $(GARAGES3_COMPOSE_FILE) exec db pg_isready; do echo "Awaiting for Postgres"; sleep 5; done

init-garages3-bootstrap:
GARAGES3_COMPOSE_FILE=$(GARAGES3_COMPOSE_FILE) GARAGES3_GARAGE_TOML=garage/garage.toml GARAGES3_ENV_FILE=.env GARAGES3_HOSTNAME=garage GARAGES3_AUTO_LAYOUT=true GARAGES3_LAYOUT_ZONE=local GARAGES3_LAYOUT_CAPACITY=1TB ../scripts/bootstrap-garages3.sh

init-garages3-volume:
docker compose -f $(GARAGES3_COMPOSE_FILE) run --rm --user root --entrypoint sh app -lc 'if [ ! -f /var/www/html/lib/versioncheck.php ]; then cd /usr/src/nextcloud && tar --exclude=./config/s3.config.php -cf - . | tar -xf - -C /var/www/html/; fi'

init-garages3-perms:
docker compose -f $(GARAGES3_COMPOSE_FILE) run --rm --user root --entrypoint sh app -lc 'find /var/www/html \( -path /var/www/html/config/s3.config.php \) -prune -o -exec chown www-data:www-data {} +'

init-garages3-app:
docker compose -f $(GARAGES3_COMPOSE_FILE) up -d app
if ! docker compose -f $(GARAGES3_COMPOSE_FILE) exec -w /var/www/html --user www-data app php occ status --output=json | grep -q "{\"installed\":true,"; then docker compose -f $(GARAGES3_COMPOSE_FILE) exec -w /var/www/html --user www-data app sh -lc 'php occ maintenance:install --database pgsql --database-host "$$POSTGRES_HOST" --database-name "$$POSTGRES_DB" --database-user "$$POSTGRES_USER" --database-pass "$$POSTGRES_PASSWORD" --admin-user "$$NEXTCLOUD_ADMIN_USER" --admin-pass "$$NEXTCLOUD_ADMIN_PASSWORD" --no-interaction'; fi
until docker compose -f $(GARAGES3_COMPOSE_FILE) exec -w /var/www/html --user www-data app php occ status --output=json | grep -e "{\"installed\":true,"; do echo "Awaiting for NextCloud installation"; sleep 10; done

set-locale-garages3:
docker compose -f $(GARAGES3_COMPOSE_FILE) exec -w /var/www/html --user www-data app php occ config:system:set default_locale --value ${LANG}
docker compose -f $(GARAGES3_COMPOSE_FILE) exec -w /var/www/html --user www-data app php occ config:system:set default_language --value ${LANG}
docker compose -f $(GARAGES3_COMPOSE_FILE) exec -w /var/www/html --user www-data app sh -c "php occ user:setting \$$NEXTCLOUD_ADMIN_USER core lang ${LANG}"

set-config-garages3:
docker compose -f $(GARAGES3_COMPOSE_FILE) exec -w /var/www/html --user www-data app php occ config:system:set skeletondirectory --value ""

init-garages3-cron:
docker compose -f $(GARAGES3_COMPOSE_FILE) up -d cron
Loading
Loading