Files
nextcloud/README.md

114 lines
4.7 KiB
Markdown

# nextcloud
Config and compose files for my self-hosted Nextcloud at `drive.net.mulas.me`.
Two pieces:
- `nginx/` — the vhost, TLS profile, and header set I wrote and hardened for Nextcloud back in **2019** and have been using in production since then. I revised it in 2026 to match new Nextcloud docs directives.
- `docker/` — a small Compose stack with MariaDB, Redis, and Memcached. Nextcloud itself runs on the host, served by NGINX and PHP-FPM, because I had an abysmal experience with Nextcloud's containerised setup, in particular on updating and adding modules. The containers only provide the backing services.
## Layout
`docker/docker-compose.yml` — the MariaDB + Redis + Memcached stack.
Everything under `nginx/` mirrors `/etc/nginx/` on the server:
- `nginx.conf` — main `http{}` block: tuning, real-ip, gzip, headers-more
- `conf.d/header.conf` — HSTS and the Nextcloud-recommended hardening headers
- `conf.d/ssl.conf` — TLS 1.2, AEAD ciphers, OCSP stapling
- `sites-available/drive.mulas.me` — the vhost
- `custom.d/` — mime types, cors, error pages, charset maps
- `fcgi.d/` — fastcgi / scgi / uwsgi params
- `snippets/` — letsencrypt ACME challenge, snakeoil
## Docker stack
Images are pinned, all overridable via env:
| Service | Default tag | Env override |
|-------------|--------------------|---------------------------|
| `db` | `mariadb:11.8-ubi9`| `ENV_MARIADB_VERSION` |
| `redis` | `redis:7.4.9-alpine`| `ENV_REDIS_VERSION` |
| `memcached` | `memcached:alpine3.23`| `ENV_MEMCACHED_VERSION` |
State, configs, and sockets land under `${ENV_BASE_DIR}/<service>/{data,config,socket}`. In production `ENV_BASE_DIR=/opt/nextcloud`.
MariaDB credentials are mounted as Docker secrets — files on the host, never in the repo:
```
/opt/nextcloud/secrets/mariadb_root_password.txt
/opt/nextcloud/secrets/mariadb_app_password.txt
```
`MYSQL_USER` and `MYSQL_DATABASE` are intentionally blank in the compose file; fill them in (or move them to an `.env`) before bringing the stack up.
## Bringing it up
```bash
# host paths
sudo mkdir -p /opt/nextcloud/{mariadb,redis,memcached}/{data,config,socket}
sudo mkdir -p /opt/nextcloud/secrets && sudo chmod 700 /opt/nextcloud/secrets
# secrets
openssl rand -base64 48 | sudo tee /opt/nextcloud/secrets/mariadb_root_password.txt
openssl rand -base64 48 | sudo tee /opt/nextcloud/secrets/mariadb_app_password.txt
sudo chmod 600 /opt/nextcloud/secrets/*.txt
# env
echo 'ENV_BASE_DIR=/opt/nextcloud' > docker/.env
# go
( cd docker && docker compose up -d )
```
Wait for the `db` healthcheck (it pings `mysqladmin`) to come up green before pointing Nextcloud at it.
## Nginx install
```bash
sudo cp nginx/nginx.conf /etc/nginx/nginx.conf
sudo cp -r nginx/conf.d/* /etc/nginx/conf.d/
sudo cp -r nginx/custom.d nginx/fcgi.d /etc/nginx/
sudo cp -r nginx/snippets/* /etc/nginx/snippets/
sudo cp nginx/sites-available/drive.mulas.me /etc/nginx/sites-available/
sudo ln -sf /etc/nginx/sites-available/drive.mulas.me /etc/nginx/sites-enabled/drive.mulas.me
sudo nginx -t && sudo systemctl reload nginx
```
What you need on the host for this to work:
- Nginx built with `headers-more` (the config uses `more_set_headers`)
- PHP-FPM 8.5 with a socket at `/var/run/php/php8.5-fpm.sock`
- A Let's Encrypt cert for `drive.net.mulas.me` and a `dhparams.pem` at `/etc/ssl/private/dhparams.pem`
- Nextcloud unpacked at `/ssda1/www/drive.net.mulas.me/`
## Wiring Nextcloud to the stack
In `config/config.php` (not in this repo):
```php
'dbtype' => 'mysql',
'dbhost' => '127.0.0.1:3306',
'dbname' => '<MYSQL_DATABASE>',
'dbuser' => '<MYSQL_USER>',
'dbpassword' => trim(file_get_contents('/opt/nextcloud/secrets/mariadb_app_password.txt')),
'memcache.local' => '\OC\Memcache\APCu',
'memcache.distributed' => '\OC\Memcache\Memcached',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => ['host' => '127.0.0.1', 'port' => 6379],
'memcached_servers' => [['127.0.0.1', 11211]],
```
## Things worth knowing before reusing this elsewhere
- The compose file publishes 3306/6379/11211 on all interfaces — fine when Nextcloud runs on the same host and the box has a firewall, but bind them to `127.0.0.1` if you're not in that situation.
- `set_real_ip_from` in `nginx.conf` trusts `127.0.0.1` and `192.168.1.0/24`. Change it for your network.
- `ssl.conf` is TLS 1.2 only. There's a commented-out line to flip on TLS 1.3 when you're ready.
- `client_max_body_size` is 50 GB and the proxy/fastcgi timeouts are essentially infinite — that's deliberate for large WebDAV uploads and long sync sessions, not an oversight.
## License
BSD 3-clause — see [LICENSE](LICENSE).