Totally baffled how to get started *newbie alert*

@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 command docker 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 with docker-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';"
1 Like