@digitalgerry don’t expect too much here. hosting your own service enforces the admin to understand what happens under the hood. engaged people will help you but you have to follow the guides and understand what you do.
My personal recommendation and disclaimer: never ever just copy&paste something to your system until you are safe this will cause no harm. this applies to commands, scripts, programs and apps.
The setup I share here is Nextcloud with MariaDB, Redis behind Traefik Reverse proxy ready to be used from Internet with Letsencrypt certificates. I skipped additional functionality like Collabora and Turn server for the sake of simplicity.
I had slightly different setup on my Qnap so I tried to build simple possible Docker Compose file - if it doesn’t work just follow the logs maybe there is some typo or other mistake…
- First you need to login with ssh to your Qnap NAS (putty, powershell) using admin credentials. Newer version have menu which you simply quit by “Q” > “Y” keys.
- once reached command line proceed to the Container Station root (
cd /share/Container
) - here you can create a folder for your application and persistent docker volumes
mkdir nextcloud
mkdir nextcloud/db
mkdir nextcloud/apps
mkdir nextcloud/config
mkdir nextcloud/files
mkdir nextcloud/traefik
mkdir nextcloud/traefik/config
cd nextcloud
-
Qnap has special Docker network which allow you to connect container directly to your LAN - just provide free fixed IP address - this is useful for Nextcloud WebServer as ports 80/443 may be used by Qnap itself
– identify this network be commanddocker network ls
this is called like qnap-static-[part of the MAC address] if it doesn’t exist review this article to create it
– you need the name to adjust traefik container networks section -
in your /share/Container/nextcloud folder you can create the
– docker-compose.yaml and
– .env and
– traefik/config/tls.yaml
files (you may copy the files with file manager your are familiar with - the Container folder is exposed with SMB) -
adjust the files with your values
– use secure passwords
– provide public fqdn for your Nextcloud instance (dynDNS)
– provide fixed IP for traefik (reverse proxy)
– adjust container image version (I prefer to use fixed version for better control)
– adjust the Qnap network you noted before
Hint: docker-compose file uses variables from .env file almost everywhere (if some value is used multiple times you can reuse it). Once you are ready run
docker-compose config
and this will display the config with all value replaced by values from .env (and complain about syntax errors).
- setup public FQDN (like dynDNS/your own domain)
- activate port forwarding to the IP you defined in traefik service (for TLS certificates)
- start your application with
docker-compose up
- this is an interactive start showing all the logs from build and start of the containers to command output. you can access the IP/FQDN you provided and setup Nextcloud. Once it’s starts successfull just Ctrl+Z (or Ctrl+C which stops everything and start withdocker-compose up -d
)
/share/Container/nextcloud/docker-compose.yaml
---
version: '3.3'
services:
reverse-proxy:
image: traefik:v2.3
container_name: traefik
hostname: traefik
restart: always
command:
- "--api=true"
- "--api.insecure=true"
- "--api.dashboard=true"
- "--log.level=WARNING"
- "--log.filePath=/etc/traefik/traefik.log"
- "--providers.docker.endpoint=unix:///var/run/docker.sock"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=lan"
- "--providers.docker.network=traefik_proxy"
- "--providers.file.filename=/etc/traefik/config/tls.yaml"
- "--providers.file.watch=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.web-secure.address=:443"
# Let's Encrypt
- "--certificatesresolvers.letsencryptresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencryptresolver.acme.httpchallenge=true"
- "--certificatesresolvers.letsencryptresolver.acme.email=<your@email>"
- "--certificatesresolvers.letsencryptresolver.acme.storage=/etc/traefik/acme.json"
# Logging options, what to log
- "--accesslog=true"
- "--accesslog.format=json"
- "--accessLog.filters.statusCodes=400-499"
volumes:
- ./traefik:/etc/traefik
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
qnet-static-eth0-24b018:
#static IP address
ipv4_address: 192.168.1.199
traefik_proxy:
labels:
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https@docker"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
nextcloud-db:
image: mariadb
container_name: nextcloud-db
command: --transaction-isolation=READ-COMMITTED --log-bin=ROW
restart: always
volumes:
- ./db:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_INITDB_SKIP_TZINFO=1 # Behebt die bekannten Startprobleme der Datenbank
nextcloud-redis:
image: redis:alpine
container_name: nextcloud-redis
hostname: nextcloud-redis
command: redis-server --requirepass ${REDIS_HOST_PASSWORD}
networks:
- default
restart: always
nextcloud-app:
image: nextcloud:19.0.8
container_name: nextcloud-app
restart: always
depends_on:
- nextcloud-db
- nextcloud-redis
environment:
- REDIS_HOST=nextcloud-redis
- REDIS_HOST_PASSWORD=${REDIS_HOST_PASSWORD}
- OVERWRITEHOST=${NEXTCLOUD_FQDN}
- OVERWRITEPROTOCOL=https
- overwrite.cli.url=https://${NEXTCLOUD_FQDN}
- NEXTCLOUD_TRUSTED_DOMAINS='${NEXTCLOUD_FQDN}'
volumes:
- ./app:/var/www/html
- ./config:/var/www/config
- ./files:/var/www/html/data
labels:
- "traefik.enable=true"
- "traefik.http.middlewares.nextcloud-https.redirectscheme.scheme=https"
- "traefik.http.routers.nextcloud-http.entrypoints=web"
- "traefik.http.routers.nextcloud-http.rule=Host(`<NEXTCLOUD_FQDN>`)" #Domain anpassen
- "traefik.http.routers.nextcloud-http.middlewares=nextcloud-https@docker"
- "traefik.http.routers.nextcloud.entrypoints=web-secure"
- "traefik.http.routers.nextcloud.rule=Host(`<NEXTCLOUD_FQDN>`)" #Domain anpassen
- "traefik.http.routers.nextcloud.tls=true"
- "traefik.http.routers.nextcloud.tls.certresolver=letsencryptresolver"
- "traefik.http.routers.nextcloud.middlewares=nextcloud-dav,secHeaders@file"
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
- "traefik.http.middlewares.nextcloud-dav.replacepathregex.regex=https://(.*)/.well-known/(card|cal)dav"
- "traefik.http.middlewares.nextcloud-dav.replacepathregex.replacement=https://$${1}/remote.php/dav/"
networks:
- traefik_proxy
- default
nextcloud-cron:
image: nextcloud:19.0.8
container_name: nextcloud-cron
restart: unless-stopped
volumes:
- ./app:/var/www/html
- ./config:/var/www/config
- ./files:/var/www/html/data
entrypoint: /cron.sh
depends_on:
- nextcloud-db
- nextcloud-redis
networks:
traefik_proxy:
external:
name: traefik_proxy
default:
driver: bridge
lan:
external:
name: qnet-static-eth0-24b018
/share/Container/nextcloud/.env
NEXTCLOUD_FQDN=<your public fqdn>
MYSQL_HOST=nextcloud-db
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud
MYSQL_PASSWORD=<your mysql nextcloud user pwd>
MYSQL_ROOT_PASSWORD=<mysql root user pwd>
REDIS_HOST=nextcloud-redis
REDIS_HOST_PASSWORD=<redis pwd>
/share/Container/nextcloud/traefik/config/tls.yaml
tls:
options:
TLSv13:
minVersion: VersionTLS13
cipherSuites:
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
http:
middlewares:
secHeaders:
headers:
browserXssFilter: true
contentTypeNosniff: true
frameDeny: true
sslRedirect: true
#HSTS Configuration
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 15768000
secHeaders2:
headers:
browserXssFilter: true
contentTypeNosniff: true
frameDeny: true
customFrameOptionsValue: SAMEORIGIN
referrerPolicy: same-origin
sslRedirect: true
#HSTS Configuration
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 15768000
forceSTSHeader: true
sslForceHost: true
browserXssFilter: true
customResponseHeaders:
server: "" # removes "Server" header
X-Powered-By: "" # Removes X-Powered-By
# for some reason NC doesn't like additiona directives
#X-Robots-Tag: "none, noarchive, nosnippet, notranslate, noimageindex"
X-Robots-Tag: "none"
#https://securityheaders.com/ is camera+mic enough?
Permissions-Policy: camera=('self'), microphone=('self'), autoplay=('self'), payment=(), screen-wake-lock=('self'), geolocation=()
Feature-Policy: "camera 'self'; microphone 'self'; payment 'none'; screen-wake-lock 'self'; geolocation 'none'; usb 'none'; vr 'none';"