intial commit

This commit is contained in:
KARMACOMA 2025-12-27 00:36:05 +01:00
parent 14876ffaec
commit 359159a4ba
3 changed files with 271 additions and 0 deletions

21
.env Normal file
View file

@ -0,0 +1,21 @@
# Core versions (can be overridden per deployment)
NEXTCLOUD_VERSION=32-apache
MARIADB_VERSION=11.4
REDIS_VERSION=7-alpine
ONLYOFFICE_VERSION=8.0
# Networking
NEXTCLOUD_DOMAIN=cloud.example.com
# Nextcloud defaults (non-secret)
NEXTCLOUD_ADMIN_USER=ncadmin
MARIADB_DATABASE=nextcloud
MARIADB_USER=nextcloud
# Secrets (must be generated per deployment)
# Provide strong random values; leave empty in git and set in Coolify or local overrides.
MARIADB_PASSWORD=
MARIADB_ROOT_PASSWORD=
NEXTCLOUD_ADMIN_PASSWORD=
REDIS_PASSWORD=
ONLYOFFICE_JWT_SECRET=

137
README.md
View file

@ -1,2 +1,139 @@
# knet-cloud # knet-cloud
Modern Nextcloud stack with MariaDB, Redis caching, and OnlyOffice Document Server. Auth is expected through your own authentik OIDC provider.
## Stack
- Nextcloud (Apache) + dedicated cron sidecar
- MariaDB 11
- Redis 7 (locking/file cache)
- OnlyOffice Document Server
## Quick start (local or generic Compose)
1. Install Docker Engine + Docker Compose.
2. Copy and edit [.env](.env) for visibility; the compose file carries defaults for non-secrets, but you must set the secrets.
3. Generate secrets (do not commit them):
```bash
cp .env .env.local
# Fill these with strong randoms
openssl rand -hex 32 # set MARIADB_PASSWORD
openssl rand -hex 32 # set MARIADB_ROOT_PASSWORD
openssl rand -hex 32 # set NEXTCLOUD_ADMIN_PASSWORD
openssl rand -hex 32 # set REDIS_PASSWORD
openssl rand -hex 32 # set ONLYOFFICE_JWT_SECRET
```
4. Bring the stack up:
```bash
docker compose --env-file .env.local up -d
```
5. First login at `https://<your-domain>` with `NEXTCLOUD_ADMIN_USER` and `NEXTCLOUD_ADMIN_PASSWORD`.
## Required post-deploy hardening
Run these once after the first boot. Replace placeholders where noted.
```bash
# Set Redis as the locking cache (pick the same password as REDIS_PASSWORD)
docker compose exec nextcloud php occ config:system:set memcache.local --value='\OC\Memcache\APCu'
docker compose exec nextcloud php occ config:system:set memcache.locking --value='\OC\Memcache\Redis'
docker compose exec nextcloud php occ config:system:set redis host --value=redis
docker compose exec nextcloud php occ config:system:set redis port --value=6379 --type=integer
docker compose exec nextcloud php occ config:system:set redis password --value='<redis-password>'
# Force HTTPS and trusted domains
docker compose exec nextcloud php occ config:system:set overwriteprotocol --value=https
docker compose exec nextcloud php occ config:system:set trusted_domains 1 --value='<your-domain>'
# Install core apps we'll need
docker compose exec nextcloud php occ app:install user_oidc
docker compose exec nextcloud php occ app:install onlyoffice
```
## Wire authentik (OIDC)
1. In authentik create an OIDC Provider + Application:
- Redirect URI: `https://<your-domain>/apps/user_oidc/callback`
- Post-logout redirect: `https://<your-domain>/logout`
- Scopes: `openid email profile offline_access`
- Algorithm: RS256, with discovery enabled.
2. Save the client ID and client secret.
3. Configure the `user_oidc` app in Nextcloud (CLI example):
```bash
docker compose exec nextcloud php occ config:app:set user_oidc oidc_login_provider_url --value='https://auth.example.com/application/o/<provider-slug>/'
docker compose exec nextcloud php occ config:app:set user_oidc oidc_login_client_id --value='<client-id>'
docker compose exec nextcloud php occ config:app:set user_oidc oidc_login_client_secret --value='<client-secret>'
docker compose exec nextcloud php occ config:app:set user_oidc oidc_login_scope --value='openid email profile offline_access'
docker compose exec nextcloud php occ config:app:set user_oidc oidc_login_button_text --value='Login with authentik'
docker compose exec nextcloud php occ config:app:set user_oidc oidc_login_end_session_redirect --value='https://<your-domain>/logout'
```
4. Test SSO and disable local password login for regular users once confirmed.
## Hook up OnlyOffice
1. In Nextcloud, enable the `onlyoffice` app (already installed above).
2. Set URLs and JWT secret (internal URL keeps traffic inside the bridge network):
```bash
docker compose exec nextcloud php occ config:app:set onlyoffice DocumentServerUrl --value='https://<your-domain-for-office>'
docker compose exec nextcloud php occ config:app:set onlyoffice DocumentServerInternalUrl --value='http://onlyoffice/'
docker compose exec nextcloud php occ config:app:set onlyoffice StorageUrl --value='http://nextcloud/'
docker compose exec nextcloud php occ config:app:set onlyoffice jwt_secret --value='<onlyoffice-jwt-secret>'
docker compose exec nextcloud php occ config:app:set onlyoffice jwt_header --value='Authorization'
```
- `<onlyoffice-jwt-secret>` should match `ONLYOFFICE_JWT_SECRET` in [.env](.env).
## Operational notes
- Run behind a TLS reverse proxy (Traefik, Caddy, or NGINX). In Coolify, Traefik is managed for you and no host ports need to be exposed in the compose file.
- Backups: snapshot `nextcloud_data`, `nextcloud_config`, and `db_data`; also export MariaDB dumps regularly.
- Updates: bump the version tags in [.env](.env) and `docker compose pull && docker compose up -d`.
- Logs: `docker compose logs -f nextcloud` and `onlyoffice` are your primary places to debug.
## Deploy with Coolify (step-by-step)
Coolify ignores `.env` files. Enter every variable in the UI. Use [.env](.env) as a reference for names and defaults. Secrets must be generated per deployment.
1. Create or select a Project in Coolify.
2. Add Resource → Docker Compose → “Import from Git”; point to this repo/branch.
3. In the Compose Resource settings, add environment variables:
- Non-secret defaults (override as needed):
- `NEXTCLOUD_VERSION=32-apache`
- `MARIADB_VERSION=11.4`
- `REDIS_VERSION=7-alpine`
- `ONLYOFFICE_VERSION=8.0`
- `NEXTCLOUD_DOMAIN=cloud.example.com` (set to your actual domain)
- `NEXTCLOUD_ADMIN_USER=ncadmin`
- `MARIADB_DATABASE=nextcloud`
- `MARIADB_USER=nextcloud`
- Required secrets (must be strong randoms):
- `MARIADB_PASSWORD`
- `MARIADB_ROOT_PASSWORD`
- `NEXTCLOUD_ADMIN_PASSWORD`
- `REDIS_PASSWORD`
- `ONLYOFFICE_JWT_SECRET`
4. Volumes: ensure the named volumes (`nextcloud_data`, `nextcloud_apps`, `nextcloud_config`, `db_data`, `redis_data`, `onlyoffice_data`, `onlyoffice_logs`) are set as persistent in Coolify (they map to Docker named volumes and will persist across deploys).
5. Domains/ingress: no port mappings required. Assign your domain(s) to the service in Coolify; Traefik handles HTTPS. Keep `NEXTCLOUD_DOMAIN` matching the public hostname.
6. Deploy and monitor logs until DB init and healthchecks are healthy.
7. Run the hardening `occ` commands (Redis cache, trusted domains/HTTPS, app installs) via the Coolify Console against the `nextcloud` container.
## Quality-of-life ideas
- Offload primary storage to S3/MinIO using the Nextcloud object store config for simpler scaling.
- Enable metrics/monitoring (Prometheus exporters for MariaDB/Redis, Traefik dashboard if used) plus alerting on failed healthchecks.
- Configure TOTP/WebAuthn in authentik and enforce SSO-only login on Nextcloud for consistent access policy.
- Use a dedicated backup tool (restic or Borg) with encryption and retention against a separate target.
- Add a content-delivery rule (CDN or edge cache) for static assets if hosting for many remote users.

113
docker-compose.yml Normal file
View file

@ -0,0 +1,113 @@
version: "3.9"
services:
nextcloud:
image: nextcloud:${NEXTCLOUD_VERSION:-32-apache}
restart: unless-stopped
depends_on:
- db
- redis
- onlyoffice
environment:
MYSQL_HOST: db
MYSQL_DATABASE: ${MARIADB_DATABASE:-nextcloud}
MYSQL_USER: ${MARIADB_USER:-nextcloud}
MYSQL_PASSWORD: ${MARIADB_PASSWORD?set_mariadb_password}
NEXTCLOUD_ADMIN_USER: ${NEXTCLOUD_ADMIN_USER:-ncadmin}
NEXTCLOUD_ADMIN_PASSWORD: ${NEXTCLOUD_ADMIN_PASSWORD?set_nextcloud_admin_password}
NEXTCLOUD_TRUSTED_DOMAINS: ${NEXTCLOUD_DOMAIN:-cloud.example.com}
OVERWRITEHOST: ${NEXTCLOUD_DOMAIN:-cloud.example.com}
OVERWRITEPROTOCOL: https
REDIS_HOST: redis
REDIS_HOST_PASSWORD: ${REDIS_PASSWORD?generate_redis_password}
PHP_MEMORY_LIMIT: 1G
PHP_UPLOAD_LIMIT: 2G
volumes:
- nextcloud_data:/var/www/html
- nextcloud_apps:/var/www/html/custom_apps
- nextcloud_config:/var/www/html/config
nextcloud-cron:
image: nextcloud:${NEXTCLOUD_VERSION:-32-apache}
restart: unless-stopped
entrypoint: /cron.sh
depends_on:
- db
- redis
environment:
MYSQL_HOST: db
MYSQL_DATABASE: ${MARIADB_DATABASE:-nextcloud}
MYSQL_USER: ${MARIADB_USER:-nextcloud}
MYSQL_PASSWORD: ${MARIADB_PASSWORD?set_mariadb_password}
NEXTCLOUD_ADMIN_USER: ${NEXTCLOUD_ADMIN_USER:-ncadmin}
NEXTCLOUD_ADMIN_PASSWORD: ${NEXTCLOUD_ADMIN_PASSWORD?set_nextcloud_admin_password}
NEXTCLOUD_TRUSTED_DOMAINS: ${NEXTCLOUD_DOMAIN:-cloud.example.com}
OVERWRITEHOST: ${NEXTCLOUD_DOMAIN:-cloud.example.com}
OVERWRITEPROTOCOL: https
REDIS_HOST: redis
REDIS_HOST_PASSWORD: ${REDIS_PASSWORD?generate_redis_password}
PHP_MEMORY_LIMIT: 1G
PHP_UPLOAD_LIMIT: 2G
volumes:
- nextcloud_data:/var/www/html
- nextcloud_apps:/var/www/html/custom_apps
- nextcloud_config:/var/www/html/config
db:
image: mariadb:${MARIADB_VERSION:-11.4}
restart: unless-stopped
command:
- --transaction-isolation=READ-COMMITTED
- --binlog-format=ROW
- --innodb_read_only_compressed=OFF
environment:
MYSQL_DATABASE: ${MARIADB_DATABASE:-nextcloud}
MYSQL_USER: ${MARIADB_USER:-nextcloud}
MYSQL_PASSWORD: ${MARIADB_PASSWORD?set_mariadb_password}
MYSQL_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD?set_mariadb_root_password}
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 30s
timeout: 5s
retries: 5
redis:
image: redis:${REDIS_VERSION:-7-alpine}
restart: unless-stopped
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD?generate_redis_password}"]
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD?generate_redis_password}", "ping"]
interval: 30s
timeout: 5s
retries: 5
onlyoffice:
image: onlyoffice/documentserver:${ONLYOFFICE_VERSION:-8.0}
restart: unless-stopped
environment:
JWT_ENABLED: "true"
JWT_SECRET: ${ONLYOFFICE_JWT_SECRET?generate_onlyoffice_jwt_secret}
JWT_HEADER: Authorization
depends_on:
- redis
volumes:
- onlyoffice_data:/var/www/onlyoffice/Data
- onlyoffice_logs:/var/log/onlyoffice
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost/healthcheck || exit 1"]
interval: 30s
timeout: 10s
retries: 5
volumes:
nextcloud_data:
nextcloud_apps:
nextcloud_config:
db_data:
redis_data:
onlyoffice_data:
onlyoffice_logs: