intial commit
This commit is contained in:
parent
14876ffaec
commit
359159a4ba
3 changed files with 271 additions and 0 deletions
21
.env
Normal file
21
.env
Normal 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
137
README.md
|
|
@ -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
113
docker-compose.yml
Normal 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:
|
||||||
Loading…
Reference in a new issue