--- - name: nextcloud hosts: all tasks: - name: Create /home/docker/nextcloud.{{inventory_hostname}} dir ansible.builtin.file: path: /home/docker/nextcloud.{{inventory_hostname}} owner: root group: docker state: directory mode: '0550' - name: /home/docker/nextcloud.{{inventory_hostname}}/genpw.sh (generate Random PW for Nextcloud and DB) blockinfile: path: /home/docker/nextcloud.{{inventory_hostname}}/genpw.sh create: yes mode: 0550 owner: root group: docker marker: "# {mark} ANSIBLE MANAGED BLOCK" block: | cd /home/docker/nextcloud.{{inventory_hostname}} ncadminpassword=$(pwgen -s 32 1) mysqluser=$(pwgen -s 32 1) mysqlpassword=$(pwgen -s 32 1) [ -f env ] || echo "MYSQL_USER=!MYSQLUSER! MYSQL_PASSWORD=!MYSQLPASSWORD! NEXTCLOUD_ADMIN_PASSWORD=!NCADMINPASSWORD! " >env [ -f env.db ] || echo "MARIADB_USER=!MYSQLUSER! MARIADB_PASSWORD=!MYSQLPASSWORD! " >env.db [ -f env.phpmyadmin ] || echo "PMA_USER=!MYSQLUSER! PMA_PASSWORD=!MYSQLPASSWORD! " >env.phpmyadmin chmod 440 env env.db env.phpmyadmin chown root:docker env env.db env.phpmyadmin sed -i "s/\!MYSQLUSER\!/$mysqluser/g" env env.db env.phpmyadmin sed -i "s/\!MYSQLPASSWORD\!/$mysqlpassword/g" env env.db env.phpmyadmin sed -i "s/\!NCADMINPASSWORD\!/$ncadminpassword/g" env backup: yes validate: /bin/bash -n %s notify: run genpw.sh - name: /home/docker/nextcloud.{{inventory_hostname}}/genpw.sh shebang lineinfile: path: /home/docker/nextcloud.{{inventory_hostname}}/genpw.sh insertbefore: BOF line: "#!/bin/bash -e" - name: Gen initial passwords if not exists ansible.builtin.shell: ./genpw.sh args: chdir: /home/docker/nextcloud.{{inventory_hostname}} creates: /home/docker/nextcloud.{{inventory_hostname}}/env - name: /home/docker/nextcloud.{{inventory_hostname}}/fulldockerfile.sh (Download full Dockerfile) blockinfile: path: /home/docker/nextcloud.{{inventory_hostname}}/fulldockerfile.sh create: yes mode: 0550 owner: root group: docker marker: "# {mark} ANSIBLE MANAGED BLOCK" block: | cd /home/docker/nextcloud.{{inventory_hostname}} wget -q https://github.com/nextcloud/docker/raw/master/.examples/dockerfiles/full/apache/Dockerfile -O Dockerfile #sed -i 's/^FROM nextcloud:apache/FROM nextcloud:production-apache/' Dockerfile sed -i 's/^# libreoffice/ libreoffice/' Dockerfile wget -q https://github.com/nextcloud/docker/raw/master/.examples/dockerfiles/full/apache/supervisord.conf -O supervisord.conf backup: yes validate: /bin/bash -n %s notify: run fulldockerfile.sh - name: /home/docker/nextcloud.{{inventory_hostname}}/fulldockerfile.sh shebang lineinfile: path: /home/docker/nextcloud.{{inventory_hostname}}/fulldockerfile.sh insertbefore: BOF line: "#!/bin/bash -e" - name: Gen initial passwords if not exists ansible.builtin.shell: ./fulldockerfile.sh args: chdir: /home/docker/nextcloud.{{inventory_hostname}} creates: /home/docker/nextcloud.{{inventory_hostname}}/Dockerfile - name: /home/docker/nextcloud.{{inventory_hostname}}/remoteip.conf (real IP logging and no Proxy IP) blockinfile: path: /home/docker/nextcloud.{{inventory_hostname}}/remoteip.conf create: yes mode: 0444 owner: root group: docker marker: "# {mark} ANSIBLE MANAGED BLOCK" block: | RemoteIPHeader X-Forwarded-For RemoteIPInternalProxy 10.0.0.0/8 RemoteIPInternalProxy 172.16.0.0/12 RemoteIPInternalProxy 192.168.0.0/16 backup: yes notify: Restart nextcloud - name: /home/docker/nextcloud.{{inventory_hostname}}/turnserver.conf blockinfile: path: /home/docker/nextcloud.{{inventory_hostname}}/turnserver.conf mode: "0400" owner: root group: root create: yes marker: "# {mark} ANSIBLE MANAGED BLOCK" block: | syslog listening-port=3478 fingerprint use-auth-secret static-auth-secret= realm=nextcloud.{{inventory_hostname}} total-quota=100 bps-capacity=0 stale-nonce no-multicast-peers backup: yes - name: /home/docker/nextcloud.{{inventory_hostname}}/docker-compose.yml Container Configuration blockinfile: path: /home/docker/nextcloud.{{inventory_hostname}}/docker-compose.yml create: yes mode: 0440 owner: root group: docker marker: "# {mark} ANSIBLE MANAGED BLOCK" block: | version: '3.6' services: nextcloud.{{inventory_hostname}}: build: context: . dockerfile: Dockerfile security_opt: - no-new-privileges:true restart: unless-stopped volumes: - ./nextcloud-data:/var/www/html - ./remoteip.conf:/etc/apache2/conf-enabled/remoteip.conf:ro - /etc/localtime:/etc/localtime:ro depends_on: - nextcloud.{{inventory_hostname}}--db - nextcloud.{{inventory_hostname}}--redis env_file: env environment: - MYSQL_HOST=nextcloud.{{inventory_hostname}}--db - MYSQL_DATABASE=nextcloud-db - NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.{{inventory_hostname}} - TRUSTED_PROXIES=192.168.41.200/24 - REDIS_HOST=nextcloud.{{inventory_hostname}}--redis - SMTP_HOST=mail.{{inventory_hostname}} - SMTP_PORT=25 - MAIL_FROM_ADDRESS=nextcloud - MAIL_DOMAIN={{inventory_hostname}} - OVERWRITEPROTOCOL=https - NEXTCLOUD_ADMIN_USER=ncadmin networks: - nextcloud.{{inventory_hostname}}--network - traefik labels: - traefik.enable=true # HTTPS - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}.rule=Host(`nextcloud.{{ ansible_facts['nodename'] }}`) - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}.entrypoints=https - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}.tls=true # Proxy to service-port - traefik.http.services.nextcloud-{{ ansible_facts['hostname'] }}.loadbalancer.server.port=80 - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}.service=nextcloud-{{ ansible_facts['hostname'] }} # cert via letsencrypt - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}.tls.certresolver=letsencrypt # Traefik network - traefik.docker.network=traefik # Nextcloud specific # .well-known for dav - traefik.http.middlewares.nextcloud-{{ ansible_facts['hostname'] }}-dav.redirectRegex.permanent=true - traefik.http.middlewares.nextcloud-{{ ansible_facts['hostname'] }}-dav.redirectRegex.regex=https://(.*)/.well-known/(card|cal)dav - traefik.http.middlewares.nextcloud-{{ ansible_facts['hostname'] }}-dav.redirectRegex.replacement=https://$${1}/remote.php/dav/ # activate secHeaders@file and .well.known - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}.middlewares=secHeaders@file,nextcloud-{{ ansible_facts['hostname'] }}-dav nextcloud.{{inventory_hostname}}--db: image: mariadb:latest cap_add: - SYS_NICE restart: unless-stopped volumes: - ./nextclouddb-data:/var/lib/mysql - /etc/localtime:/etc/localtime:ro env_file: env.db environment: - MARIADB_RANDOM_ROOT_PASSWORD=1 - MARIADB_DATABASE=nextcloud-db - MARIADB_AUTO_UPGRADE=1 - MARIADB_INITDB_SKIP_TZINFO=1 networks: - nextcloud.{{inventory_hostname}}--network nextcloud.{{inventory_hostname}}--redis: image: redis:latest restart: unless-stopped networks: - nextcloud.{{inventory_hostname}}--network nextcloud.{{inventory_hostname}}--cron: image: nextcloud:production restart: unless-stopped volumes: - ./nextcloud-data:/var/www/html - /etc/localtime:/etc/localtime:ro entrypoint: /cron.sh depends_on: - nextcloud.{{inventory_hostname}}--db networks: - nextcloud.{{inventory_hostname}}--network nextcloud.{{inventory_hostname}}--phpmyadmin: image: phpmyadmin:latest restart: unless-stopped env_file: env.phpmyadmin environment: - PMA_ARBITRARY=0 - PMA_HOST=nextcloud.{{inventory_hostname}}--db volumes: - /etc/localtime:/etc/localtime:ro networks: - nextcloud.{{inventory_hostname}}--network - traefik labels: - traefik.enable=true # HTTPS - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}--phpmyadmin.rule=Host(`nextcloud-phpmyadmin.{{ ansible_facts['nodename'] }}`) - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}--phpmyadmin.entrypoints=https - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}--phpmyadmin.tls=true # Proxy to service-port - traefik.http.services.nextcloud-{{ ansible_facts['hostname'] }}--phpmyadmin.loadbalancer.server.port=80 - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}--phpmyadmin.service=nextcloud-{{ ansible_facts['hostname'] }}--phpmyadmin # cert via letsencrypt - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}--phpmyadmin.tls.certresolver=letsencrypt # Auth - traefik.http.routers.nextcloud-{{ ansible_facts['hostname'] }}--phpmyadmin.middlewares=secHeaders@file,nextcloud-{{ ansible_facts['hostname'] }}--phpmyadmin-auth - traefik.http.middlewares.nextcloud-{{ ansible_facts['hostname'] }}--phpmyadmin-auth.basicauth.users=admin:$$apr1$$XLxGs/Ba$$3phZ1a2RtfExOp8x6NFjZ. # Traefik network - traefik.docker.network=traefik networks: nextcloud.{{inventory_hostname}}--network: driver: bridge driver_opts: com.docker.network.bridge.name: br-nextcloud traefik: external: true backup: yes notify: Restart nextcloud - name: Start nextcloud ansible.builtin.shell: docker-compose up -d args: chdir: /home/docker/nextcloud.{{inventory_hostname}} creates: /home/docker/nextcloud.{{inventory_hostname}}/nextcloud-data/config/config.php - name: Wait until nextcloud install is finished wait_for: path: /home/docker/nextcloud.{{inventory_hostname}}/nextcloud-data/config/config.php - name: /home/docker/nextcloud.{{inventory_hostname}}/nextcloud-data/config/local.config.php (local nextcloud config) blockinfile: path: /home/docker/nextcloud.{{inventory_hostname}}/nextcloud-data/config/local.config.php create: yes mode: 0444 owner: root group: docker marker: "// {mark} ANSIBLE MANAGED BLOCK" block: | $CONFIG = array ( 'loglevel' => 1, 'logtimezone' => 'Europe/Berlin', 'log_rotate_size' => 10485760, 'default_phone_region' => 'DE', 'session_lifetime' => 28800, 'session_keepalive' => true, 'skeletondirectory' => '', ); backup: yes - name: /home/docker/nextcloud.{{inventory_hostname}}/nextcloud-data/config/local.config.php shebang lineinfile: path: /home/docker/nextcloud.{{inventory_hostname}}/nextcloud-data/config/local.config.php insertbefore: BOF line: "app.${app}.installed 2>&1 [ -f app.${app}.installed ] || docker-compose exec -T -u www-data nextcloud.{{ ansible_facts['hostname'] }}.dedyn.io ./occ app:enable ${app} | tee -a nextcloud.init.log >app.${app}.installed 2>&1 done # disable apps for app in dashboard nextcloud_announcements serverinfo support updatenotification weather_status do [ -f app.${app}.installed ] || docker-compose exec -T -u www-data nextcloud.{{ ansible_facts['hostname'] }}.dedyn.io ./occ app:disable ${app} | tee -a nextcloud.update.log >app.${app}.disabled 2>&1 done # stun/turn server if [ -s /home/docker/turn.{{inventory_hostname}}/env ] then source /home/docker/turn.{{inventory_hostname}}/env docker-compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ talk:turn:add --secret $TURN_SECRET turns turn.{{inventory_hostname}}:5349 udp,tcp docker-compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ talk:stun:add turn.{{inventory_hostname}}:5349 docker-compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ talk:stun:delete stun.nextcloud.com:443 fi exit 0 backup: yes validate: /bin/bash -n %s notify: run nextcloud.init - name: Run nextcloud.init after install ansible.builtin.shell: bash /home/docker/nextcloud.{{inventory_hostname}}/nextcloud.init.sh args: chdir: /home/docker/nextcloud.{{inventory_hostname}} creates: /home/docker/nextcloud.{{inventory_hostname}}/nextcloud.init.log - name: /usr/local/sbin/autoupdate.d/nextcloud.update blockinfile: path: /usr/local/sbin/autoupdate.d/nextcloud.update mode: "0400" owner: root group: root create: yes marker: "# {mark} ANSIBLE MANAGED BLOCK" block: | cd /home/docker/nextcloud.{{inventory_hostname}} || continue # Update full Dockerfile /home/docker/nextcloud.{{inventory_hostname}}/fulldockerfile.sh # Nextcloud maintenance and app-update docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ db:add-missing-columns docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ db:add-missing-indices docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ db:add-missing-primary-keys docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ app:update --all docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ dav:sync-birthday-calendar docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ trashbin:cleanup --all-users docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ files:cleanup docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ files:scan --all --home-only docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ maps:scan-photos docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ db:convert-filecache-bigint -n # define stun/turn server maybe new password if [ -s /home/docker/turn.{{inventory_hostname}}/env ] then # turn source /home/docker/turn.{{inventory_hostname}}/env docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ talk:turn:delete turns turn.{{inventory_hostname}}:5349 udp,tcp docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ talk:turn:add --secret $TURN_SECRET turns turn.{{inventory_hostname}}:5349 udp,tcp # stun docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ talk:stun:delete turn.{{inventory_hostname}}:5349 docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ talk:stun:add turn.{{inventory_hostname}}:5349 docker compose exec -T -u www-data nextcloud.{{inventory_hostname}} ./occ talk:stun:delete stun.nextcloud.com:443 fi backup: yes validate: /bin/bash -n %s notify: run nextcloud.update handlers: - name: run genpw.sh ansible.builtin.shell: ./genpw.sh args: chdir: /home/docker/nextcloud.{{inventory_hostname}} notify: Restart nextcloud - name: run fulldockerfile.sh ansible.builtin.shell: ./fulldockerfile.sh args: chdir: /home/docker/nextcloud.{{inventory_hostname}} - name: run nextcloud.update ansible.builtin.shell: bash /usr/local/sbin/autoupdate.d/nextcloud.update - name: run nextcloud.init ansible.builtin.shell: bash /home/docker/nextcloud.{{inventory_hostname}}/nextcloud.init.sh - name: Restart nextcloud ansible.builtin.shell: docker-compose up -d --force-recreate args: chdir: /home/docker/nextcloud.{{inventory_hostname}}