Installer Nextcloud sur Fedora Servers Cloud grâce à Terraform et Ansible, part2

Vue d’ensemble du code de provision des VMs

Maintenant que l’on a notre code pour l’infra, il est temps de passer à la partie provision des vms. Pour cela, comme je vous le disais, j’utilise Ansible. Pourquoi ? Parce qu’il est de plus en plus inclus dans l’écosystème RedHat, que la communauté autour du projet est très vivante et que l’on n’a aucun de mal à trouver des infos. Je vous rappelle que ce code met à disposition des serveurs dans un réseau isolé. Je vous montre l’arborescence des rôles et playbooks en fonction de mon architecture :

.
├── playbooks
│   ├── db.yml
│   ├── main.yml
│   ├── nc.yml
│   └── rd.yml
└── roles
    ├── common
    │   ├── handlers
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml
    ├── firewalld
    │   ├── handlers
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml
    ├── httpd
    │   ├── handlers
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml
    ├── mariadb
    │   ├── handlers
    │   │   └── main.yml
    │   ├── tasks
    │   │   └── main.yml
    │   └── templates
    │       ├── my.cnf.j2
    │       └── mycnf.j2
    ├── nextcloud
    │   ├── handlers
    │   │   └── main.yml
    │   ├── tasks
    │   │   ├── fips.yml
    │   │   ├── main.yml
    │   │   ├── nextcloud_httpd.yml
    │   │   ├── nextcloud_mariadb.yml
    │   │   └── nextcloud_php.yml
    │   ├── templates
    │   │   ├── 10-opcache.ini.j2
    │   │   ├── dhparams.pem.j2
    │   │   ├── htaccess.j2
    │   │   ├── httpd.conf.j2
    │   │   ├── nextcloud.conf.j2
    │   │   ├── php.ini.j2
    │   │   ├── upgrade.sh.j2
    │   │   └── www.conf.j2
    │   └── vars
    │       └── main.yml
    ├── php
    │   ├── files
    │   │   └── phpinfo.php
    │   ├── handlers
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml
    └── redis
        ├── handlers
        │   └── main.yml
        ├── tasks
        │   └── main.yml
        └── templates
            └── redis.conf.j2

30 directories, 37 files

Pour ce qui est du durcissement, de la sécurité des souches, il existe un rôle mis à disposition par Openstack, basé sur les recommandations STIG, je vous le conseille : https://docs.openstack.org/ansible-hardening/latest/

Les playbooks

Je vais passer en revue les fichiers les plus importants. On commence par le fichier d’entrée, main.yml qui est lancé par terraform :

---
- hosts: all
  become: yes
  gather_facts: yes
  tasks:
    - name: Load variables
      include_vars:
        dir: ../roles/nextcloud/vars
        name: main
        extensions: [yml]
  roles:
    - role: common

- name: Include Redis play
  import_playbook: rd.yml

- name: Include Mariadb play
  import_playbook: db.yml

- name: Include Nextcloud play
  import_playbook: nc.yml
...

On charge le fichier des variables que j’ai placé dans le répertoire vars du rôle nextcloud. On exécute le rôle common et ensuite on lance les différents playbooks pour redis, mariadb et l’application Nextcloud.

---
- name: Install Redis Server
  hosts: lan_rd
  become: true
  vars:
    list_open_ports: ["6379"]
  roles:
    - role: redis
    - role: firewalld
...

Le playbook rd.yml va exécuter les rôles redis et firewalld sur le group lan_rd.

---
- name: Install DB Server for Nextcloud
  hosts: lan_db
  become: true
  roles:
    - role: mariadb
    - role: firewalld
      vars:
        list_open_services: ["mysql"]
...

Même logique sur le groupe lan_db, mais cette fois pour mariadb.

---
- name: Install Nextcloud
  hosts: lan_nc
  become: true
  vars:
    list_open_services: ["http", "https"]
    openssl_dhparam:
  roles:
    - role: httpd
    - role: firewalld
    - role: php
    - role: nextcloud
...

Les rôles

Je ne vais pas m’attarder sur les rôles simples comme httpd, php, redis. Le plus important dans ces rôles est la configuration qui souvent se trouve dans un template.

common

Le rôle common s’applique sur l’ensemble des serveurs.

- name: yum-clean-metadata
  command: yum clean metadata
  args:
    warn: no
---
- name: add epel repo
  yum_repository:
    name: epel
    description: Extra Packages for Enterprise Linux 7 - $basearch
    mirrorlist: https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
    gpgkey: https://getfedora.org/static/352C64E5.txt
    enabled: yes
  notify: yum-clean-metadata

- name: Install tools
  dnf:
    name: ['unzip', 'wget', 'bzip2', 'certbot', 'cronie', 'sysfsutils', 'setroubleshoot', 'mariadb']
    state: latest

- name: Enable and start crond.service
  service:
    name: crond.service
    state: started
    enabled: yes

J’ai ajouté le repo EPEL, c’est inutile sauf si on veut par la suite installer des packages spécifiques. Vous pouvez retirer le bloc…

firewalld

---
- name: reload_firewall
  command: firewall-cmd --reload
---
- name: Install firewalld package
  dnf:
     name: firewalld
     state: latest
- name: Enable and start Firewalld
  service:
    name: firewalld
    enabled: yes
    state: started

- name: Get firewalld default zone
  shell: firewall-cmd --get-default-zone
  register: firewall_zone
  changed_when: false
  failed_when: false

- name: Get zone of interface eth0
  shell: firewall-cmd --get-zone-of-interface=eth0
  register: zone_of_interface
  changed_when: false
  failed_when: false

- name: Set add new interface to firewalld zone "{{ server_fw_zone | default('internal') }}"
  command: firewall-cmd --permanent --zone="{{ server_fw_zone | default('internal') }}" --change-interface=eth0
  when: '"internal" not in zone_of_interface.stdout'

- name: Set default zone to Firewalld
  command: firewall-cmd --set-default-zone="{{ server_fw_zone | default('internal') }}"
  when: '"internal" not in firewall_zone.stdout'

- name: Add ports in firewalld rules
  firewalld:
     zone: "{{ server_fw_zone | default('internal') }}"
     port: "{{ item }}/tcp"
     permanent: yes
     immediate: yes
     state: enabled
  with_items:
    - '{{ list_open_ports }}'
  when: list_open_ports is defined
  notify: reload_firewall
- name: Add services in firewall rules
  firewalld:
     zone: "{{ server_fw_zone | default('internal') }}"
     service: "{{ item }}"
     permanent: yes
     immediate: yes
     state: enabled
  with_items:
    - '{{ list_open_services }}'
  when: list_open_services is defined
  notify: reload_firewall
...

Pour le firewall, on ouvre les ports par numéro ou nom de service en l’indiquant dans une variable lors de l’appel au rôle.

redis

---
- name: 'restart_redis'
  service: name=redis state=restarted
...
---
- name: Install Redis
  dnf:
    name: ['redis']
    state: present

- name: Redis Installed Starting
  service:
    name: redis
    state: started
    enabled: yes

- name: Change redis conf to unixsocket
  template:
    src: redis.conf.j2
    dest: /etc/redis.conf
    owner: root
    group: root
    mode: '0644'
  notify: restart_redis

- name: Checking overcommit memory
  shell: 'cat /proc/sys/vm/overcommit_memory'
  register: overcommit_memory
  changed_when: false
  failed_when: false

- name: Overcommit memory
  sysctl:
    name: vm.overcommit_memory
    value: '1'
    state: present
  when: '"1" not in overcommit_memory.stdout'
  tags: cf

- name: Increase max connections
  sysctl:
    name: net.core.somaxconn
    value: '511'
    state: present
  tags: cf

- name: Disable THP
  shell: echo never > /sys/kernel/mm/transparent_hugepage/enabled
  notify: restart_redis
...

On place la configuration de redis qui va bien dans le template suivant :

bind {{ ansible_default_ipv4.address }}
protected-mode yes
port 6379
unixsocket /var/run/redis/redis.sock
unixsocketperm 775
maxclients 512
tcp-backlog 511
timeout 1.5
tcp-keepalive 300
daemonize yes
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile /var/log/redis/redis.log
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes

mariadb

---
- name: restart_mariadb
  service:
    name: mariadb
    state: restarted
---
- name: Install MariaDB package
  dnf:
    name: ['mariadb', 'mariadb-server', 'python3-PyMySQL']
    state: latest

- name: Install Python for PyMariaDB package
  dnf:
    name: python3-PyMySQL
    state: latest

- name: Start MariaDB Service
  service:
    name: mariadb
    state: started
    enabled: yes

- name: Configure MariaDB
  template:
    src: my.cnf.j2
    dest: /etc/my.cnf
  notify: restart_mariadb

- name: Generate new root password
  command: openssl rand -hex 7 creates=/root/.my.cnf
  register: mysql_new_root_pass

- name: Secure MariaDB -- remove anonymous user
  mysql_user:
    name: ''
    host_all: yes
    state: absent
    login_unix_socket: "/var/lib/mysql/mysql.sock"
  when: mysql_new_root_pass.changed

- name: Secure MariaDB -- remove test db
  mysql_db:
    name: test
    state: absent
    login_unix_socket: "/var/lib/mysql/mysql.sock"
  when: mysql_new_root_pass.changed

- name: Output new root password
  debug:
   msg: "New root password is {{ mysql_new_root_pass.stdout }}"
  when: mysql_new_root_pass.changed

- name: Update root password
  mysql_user:
    name: root
    host_all: yes
    password: "{{ mysql_new_root_pass.stdout }}"
    login_unix_socket: "/var/lib/mysql/mysql.sock"
  when: mysql_new_root_pass.changed

- name: Create my.cnf
  template: src=mycnf.j2 dest=/root/.my.cnf
  when: mysql_new_root_pass.changed

- name: Initialize nextcloud database
  include_role:
    name: nextcloud
    tasks_from: nextcloud_mariadb
...
[client]
user=root
password={{ mysql_new_root_pass.stdout }}
[client]
default-character-set = utf8mb4
socket=/var/lib/mysql/mysql.sock
port = 3306

[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
nice = 0
socket=/var/lib/mysql/mysql.sock

[mysqld]
basedir = /usr
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mariadb/mariadb.log
pid-file=/run/mariadb/mariadb.pid
bind-address = 0.0.0.0
port = 3306
binlog_format = ROW
bulk_insert_buffer_size = 16M
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
concurrent_insert = 2
connect_timeout = 5
default_storage_engine = InnoDB
expire_logs_days = 7
innodb_buffer_pool_size = 1024M
innodb_buffer_pool_instances = 1
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 32M
innodb_max_dirty_pages_pct = 90
innodb_file_per_table = 1
innodb_open_files = 400
innodb_io_capacity = 4000
innodb_flush_method = O_DIRECT
innodb_large_prefix = true
innodb_file_format = barracuda
key_buffer_size = 128M
long_query_time = 1
max_allowed_packet = 16M
max_binlog_size = 100M
max_connections = 300
max_heap_table_size = 64M
myisam_recover_options = BACKUP
myisam_sort_buffer_size = 512M
port = 3306
query_cache_limit = 2M
query_cache_size = 64M
query_cache_type = 1
query_cache_min_res_unit = 2k
read_buffer_size = 2M
read_rnd_buffer_size = 1M
skip-external-locking
skip-name-resolve
sort_buffer_size = 4M
table_open_cache = 400
thread_cache_size = 128
tmp_table_size = 64M
tmpdir = /tmp
transaction_isolation = READ-COMMITTED
wait_timeout = 600

[mysqldump]
max_allowed_packet = 16M
quick
quote-names

[isamchk]
key_buffer = 16M

httpd

- name: httpd_restart
  service:
    name: httpd
    state: restarted
---
- name: Installing Web Server
  dnf:
    name: [httpd, mod_ssl, openssl]
    state: latest

- name: Web Server Installed Starting
  service:
    name: httpd
    state: started
    enabled: yes

- name: httpd Configuration for Nextcloud
  include_role:
    name: nextcloud
    tasks_from: "nextcloud_httpd.yml"
...

php

---
- name: php_restart
  service:
    name: php-fpm
    state: restarted
---
- name: Install PHP
  dnf:
    name: ['php', 'php-gd', 'php-common', 'php-dom', 'php-zlib', 'php-json', 'php-mbstring', 'php-intl', 'php-pecl-apcu', 'php-mysqlnd', 'php-pecl-redis', 'php-opcache', 'php-imagick', 'php-zip', 'php-process', 'php-pear', 'php-pdo_mysql', 'php-ctype']
    state: present

- name: PHP Installed Starting
  service:
    name: php-fpm
    state: started
    enabled: yes

- name: Nextcloud specific php configuration
  include_role:
    name: nextcloud
    tasks_from: nextcloud_php
...

nextcloud

Toute la configuration se trouve dedans le dernier rôle nextcloud.

---
- name: reboot
  reboot:
    reboot_timeout: 60
- name: httpd_restart
  service:
    name: httpd
    state: restarted
- name: php_restart
  service:
    name: php-fpm
    state: restarted

Pour FIPS ci-dessous, c’est facultatif…

---
- name: Install tools
  dnf:
    name: ['dracut-fips', 'dracut-fips-aesni']
    state: latest
  tags: fips

- name: Checking GRUB cmdline
  shell: 'grep "fips=1" /etc/default/grub'
  register: grub_cfg_grep
  changed_when: false
  failed_when: false
  tags: fips

- name: Recreate initramfs file
  command: dracut -f
  when: '"fips=1" not in grub_cfg_grep.stdout'
  tags: fips

- name: Find uuid of /boot
  command: findmnt -no uuid /
  register: boot_uuid
  when: '"fips=1" not in grub_cfg_grep.stdout'
  tags: fips

- name: Configuring GRUB cmdline
  replace:
    path: '/etc/default/grub'
    regexp: '^GRUB_CMDLINE_LINUX="((\w.?)*)"$'
    replace: 'GRUB_CMDLINE_LINUX=" boot=UUID={{ boot_uuid.stdout }} fips=1"'
  when: '"fips=1" not in grub_cfg_grep.stdout'
  tags: fips

- name: Reconfigure grub
  command: grub2-mkconfig -o /boot/grub2/grub.cfg
  when: '"fips=1" not in grub_cfg_grep.stdout'
  tags: fips
  notify: reboot
---
- name: Configure FIPS
  include_tasks: fips.yml
  tags: fips
  when: fips | bool

- name: Test if nextcloud config exists
  stat: path=/var/www/html/nextcloud/config/config.php
  register: nc_config_stat

- name: Extract installer
  unarchive:
    src: "{{ nextcloud_url }}"
    dest: /var/www/html/
    remote_src: True
    owner: apache
    group: apache
  when: not nc_config_stat.stat.exists

- name: Create Data Directory with permissions
  file:
    dest: "/var/nc_data"
    owner: apache
    group: apache
    mode: 0775
    state: directory
  changed_when: false

- name: SELinux allow apache to modify files in differents directories
  sefcontext:
    target: "{{ item }}"
    setype: httpd_sys_rw_content_t
    state: present
  with_items:
    - '/var/www/html/nextcloud/config(/.*)?'
    - '/var/nc_data(/.*)?'
    - '/var/www/html/nextcloud/data(/.*)?'
    - '/var/www/html/nextcloud/apps(/.*)?'
    - '/var/www/nextcloud/assets(/.*)?'
    - '/var/www/html/nextcloud/.htaccess'
    - '/var/www/html/nextcloud/.user.ini'
    - '/var/www/html/nextcloud/3rdparty/aws/aws-sdk-php/src/data/logs(/.*)?'
  tags: selinux

- name: Set httpd_can_network_connect flag on and keep it persistent across reboots
  seboolean:
    name: "{{ item }}"
    state: yes
    persistent: yes
  with_items:
    - httpd_can_network_connect
    - httpd_can_network_connect_db
    - httpd_can_network_relay
    - httpd_unified
    - httpd_graceful_shutdown
    - httpd_can_sendmail
    - httpd_use_cifs
    - httpd_use_fusefs
    - httpd_use_gpg
    - httpd_execmem
  tags: selinux

- name: Configure httpd and selinux
  shell: |
    restorecon -Rv "{{ item }}"
  with_items: ["/var/nc_data", "/var/www/html/nextcloud"]

# if you have trouble with php-fpm and selinux in this nextcloud configuration :
# # ausearch -c 'php-fpm' --raw | audit2allow -M my-phpfpm
# # semodule -X 300 -i my-phpfpm.pp
# # ausearch -c 'df' --raw | audit2allow -M my-df
# # semodule -X 300 -i my-df.pp

- name: Put SELinux in enforcing mode
  selinux:
    policy: targeted
    state: "{{ selinux_state | default(enforcing) }}"
  notify: reboot
  tags: selinux

- name: Add a php cron task for apache
  cron:
    name: "php nextcloud tasks"
    minute: "*/5"
    job: "php -f /var/www/html/nextcloud/cron.php > /dev/null 2>&1"
    user: apache
  tags: cron

- name: Nextcloud silent installation
  shell: |
      sudo -u apache php occ maintenance:install --database="mysql" --database-name="{{ nextcloud_db }}" --database-host="{{ hostvars[groups['lan_db'][0]]['inventory_hostname'] }}" --database-user="{{ nextcloud_db_user }}" --database-pass="{{ nextcloud_db_password }}" --database-table-prefix="" --admin-user="{{ nextcloud_admin_user }}" --admin-pass="{{ nextcloud_admin_password }}" --data-dir "/var/nc_data"
      sudo -u apache php occ config:system:set trusted_domains 1 --value="{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
      sudo -u apache php occ config:system:set trusted_domains 2 --value="{{ nextcloud_gateway }}"
      sudo -u apache php occ config:system:set overwrite.cli.url --value=https://"{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
      sudo -u apache php occ background:cron
      sudo -u apache php occ app:disable firstrunwizard
      sudo -u apache php occ app:disable survey_client
      sudo -u apache php occ app:install files_external
      sudo -u apache php occ app:enable files_external
      systemctl stop httpd
      sudo -u apache php occ db:add-missing-indices
      systemctl start httpd
  args:
    chdir: /var/www/html/nextcloud/
  tags: install
  when: not nc_config_stat.stat.exists

- name: Change conf in .htaccess file
  notify: [httpd_restart, php_restart]
  tags: htaccess
  blockinfile:
    path: /var/www/html/nextcloud/.htaccess
    marker: "# {mark} ANSIBLE MANAGED BLOCK"
    block: |
          <IfModule mod_rewrite.c>
          Options -MultiViews
          RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
          RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
          RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff2?|ico|jpg|jpeg)$
          RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
          RewriteCond %{REQUEST_FILENAME} !core/img/manifest.json$
          RewriteCond %{REQUEST_FILENAME} !/remote.php
          RewriteCond %{REQUEST_FILENAME} !/public.php
          RewriteCond %{REQUEST_FILENAME} !/cron.php
          RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php
          RewriteCond %{REQUEST_FILENAME} !/status.php
          RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php
          RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php
          RewriteCond %{REQUEST_FILENAME} !/robots.txt
          RewriteCond %{REQUEST_FILENAME} !/updater/
          RewriteCond %{REQUEST_FILENAME} !/ocs-provider/
          RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
          RewriteRule . index.php [PT,E=PATH_INFO:$1]
          RewriteBase /
          <IfModule mod_env.c>
          SetEnv front_controller_active true
          <IfModule mod_dir.c>
          DirectorySlash off
          </IfModule>
          </IfModule>
          </IfModule>

- name: Adapt nextcloud configuration
  blockinfile:
    path: /var/www/html/nextcloud/config/config.php
    marker: "// {mark} ANSIBLE MANAGED BLOCK"
    insertbefore: \);$
    block: |
        'activity_expire_days' => 14,
        'auth.bruteforce.protection.enabled' => true,
        'blacklisted_files' =>
        array (
        0 => '.htaccess',
        1 => 'Thumbs.db',
        2 => 'thumbs.db',
        ),
        'cron_log' => true,
        'enable_previews' => true,
        'enabledPreviewProviders' =>
        array (
        0 => 'OC\\Preview\\PNG',
        1 => 'OC\\Preview\\JPEG',
        2 => 'OC\\Preview\\GIF',
        3 => 'OC\\Preview\\BMP',
        4 => 'OC\\Preview\\XBitmap',
        5 => 'OC\\Preview\\Movie',
        6 => 'OC\\Preview\\PDF',
        7 => 'OC\\Preview\\MP3',
        8 => 'OC\\Preview\\TXT',
        9 => 'OC\\Preview\\MarkDown',
        ),
        'filesystem_check_changes' => 0,
        'filelocking.enabled' => 'true',
        'htaccess.RewriteBase' => '/',
        'integrity.check.disabled' => false,
        'knowledgebaseenabled' => false,
        'logfile' => '/var/nc_data/nextcloud.log',
        'loglevel' => 2,
        'logtimezone' => 'Europe/Paris',
        'log_rotate_size' => 104857600,
        'maintenance' => false,
        'memcache.local' => '\\OC\\Memcache\\APCu',
        'memcache.locking' => '\\OC\\Memcache\\Redis',
        'overwriteprotocol' => 'https',
        'preview_max_x' => 1024,
        'preview_max_y' => 768,
        'preview_max_scale_factor' => 1,
        'redis' =>
        array (
        'host' => '{{ hostvars[groups['lan_rd'][0]]['inventory_hostname'] }}',
        'port' => 6379,
        'dbindex' => 0,
        'timeout' => 1.5,
        ),
        'quota_include_external_storage' => false,
        'share_folder' => '/Shares',
        'skeletondirectory' => '',
        'theme' => '',
        'trashbin_retention_obligation' => 'auto, 7',
        'updater.release.channel' => 'stable',
  notify: [httpd_restart, php_restart]
  tags: conf2
- name: adjust .user.ini
  replace:
    path: /var/www/html/nextcloud/.user.ini
    regexp: '{{ item.regexp }}'
    replace: '{{ item.replace }}'
    backup: yes
  with_items:
    - { regexp: "output_buffering=.*", replace: "output_buffering='Off'" }
  notify: [httpd_restart, php_restart]
  tags: conf2

- debug:
    msg: "{{ item }}"
  with_items:
    - "DataBase server's IP: {{ hostvars[groups['lan_db'][0]]['inventory_hostname'] }}"
    - "Redis server's IP: {{ hostvars[groups['lan_rd'][0]]['inventory_hostname'] }}"
    - "Nextcloud server's IP: {{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
  tags: ip
...
---
- name: Create ssl certificates Directory
  file:
    dest: "/etc/{{ item }}"
    owner: root
    group: root
    state: directory
  tags: cert
  with_items:
    - "{{ ansible_fqdn }}"
    - "{{ ansible_fqdn }}/ssl"

- name: Generate an OpenSSL private key
  openssl_privatekey:
    path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.key
  tags: cert

- name: Generate an OpenSSL CSR
  openssl_csr:
    path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.csr
    privatekey_path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.key
    common_name: "{{ ansible_fqdn }}"
  tags: cert

- name: Generate a Self Signed OpenSSL certificate
  openssl_certificate:
    path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.crt
    privatekey_path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.key
    csr_path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.csr
    provider: selfsigned
  tags: cert

- name: Test if dhparam pem exists
  stat: path=/etc/{{ ansible_fqdn }}/ssl/dhparams.pem
  register: dhparam_stat
  tags: cert

- name: Generate Diffie-Hellman parameters (2048 bits)
  openssl_dhparam:
    path: /etc/{{ ansible_fqdn }}/ssl/dhparams.pem
    size: 2048 # 4096 warning it's a long time...
  when: openssl_dhparam | default(false)
  tags: cert
  register: dhparam

- name: Import dhparams.pem
  template:
    src: dhparams.pem.j2
    dest: /etc/{{ ansible_fqdn }}/ssl/dhparams.pem
    owner: root
    group: root
    mode: '0600'
  when: (not dhparam_stat.stat.exists or openssl_dhparam == "false")
  tags: cert

- name: Create virtualhost
  template:
    src: nextcloud.conf.j2
    dest: /etc/httpd/conf.d/nextcloud.conf
    owner: root
    group: root
    mode: '0644'
  notify: httpd_restart

- name: Change apache configuration
  template:
    src: httpd.conf.j2
    dest: /etc/httpd/conf/httpd.conf
    owner: root
    group: root
    mode: '0644'
  notify: httpd_restart
...
---
- name: Create NextCloud database
  mysql_db:
    name: "{{ nextcloud_db }}"
    encoding: utf8mb4
    collation: utf8mb4_general_ci
    state: present

- name: Create NextCloud database user on localhost
  mysql_user:
    name: "{{ nextcloud_db_user }}"
    password: "{{ nextcloud_db_password }}"
    priv: "nextcloud.*:ALL,GRANT"
    host: "localhost"
    login_unix_socket: "/var/lib/mysql/mysql.sock"
    state: present

- name: Create NextCloud database user on all hosts
  mysql_user:
    name: "{{ nextcloud_db_user }}"
    password: "{{ nextcloud_db_password }}"
    priv: "nextcloud.*:ALL,GRANT"
    host: "%"
    state: present
    login_unix_socket: "/var/lib/mysql/mysql.sock"
  notify: restart_mariadb
...
---
- name: Change PHP conf
  template:
    src: php.ini.j2
    dest: /etc/php.ini
    owner: root
    group: root
    mode: '0644'
  notify: php_restart

- name: Change PHP opcache conf
  template:
    src: 10-opcache.ini.j2
    dest: /etc/php.d/10-opcache.ini
    owner: root
    group: root
    mode: '0644'
  notify: php_restart

- name: Change PHP www.conf
  template:
    src: www.conf.j2
    dest: /etc/php-fpm.d/www.conf
    owner: root
    group: root
    mode: '0644'
  notify: php_restart
...

et les templates des fichiers de configuration qui vont bien :

zend_extension=opcache
memory_limit = 512M
output_buffering = 'Off'
max_execution_time = 1800
max_input_time = 3600
post_max_size = 10240M
upload_max_filesize = 10240M
max_file_uploads = 100
session.cookie_secure = True
opcache.enable=1
opcache.enable_cli=1
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.memory_consumption=128
opcache.save_comments=1
opcache.revalidate_freq=1

Pour le .pem ci-dessous, uniquement pour les tests. Sinon il faut la créer.

-----BEGIN DH PARAMETERS-----
MIICCAKCAgEA8Yl4SFYf4byMREbYhLkzoFGjSshYlhc1vKeIH+7XjJD3dH7YIG2A
4F+3mKEa1HqG88WvPOqRCA+N4JDtQKHpHSjkQfBmhb9SHywOsv/DJmWKytRemp91
0PZvaMac9F7zToLLPctUjR3CFvVUWjv4qWov2eFNTNvLGmKbEz8PXQosMEEhFnQ2
N94FOPnhpdZ4nsfHLSvdXUrKUuoR3fT8C3lBCznpzSamHUPT4XnlQd32q/Lfdh5x
+IKBtf0cJLaRI4dHRgGCZUAcS1L5sjtcC4UrOb/2A1sYF7LGPUzUU6SV01o1kuaV
HqiqMiIXJBVdH1OmYv00W7fbq/U2dSbFyEeIAUlIe1G8EFntfJV+HNICe2+Wbavs
jouztf2I6OQEpHVRws51Bne1Zk7m2JWerXsv8JRkCrvgrTsYQMlFMYKAmuzBL4j/
eoWjc8UGopTw1RmbUbSzrDMlFvQ0W32qM1nm6SVOht86Huc+D6nkXra/b12WUqI3
yPwyA/RN9V3XwvWuseBXg3NAg2caHQT9A7nd8pB5fRXLVcIeBvj+L04LsR7oCaSN
RpLVPlATwQsMIG4l36Qh+w4YynAdzN0qnCjq7gMXetLtniZ2gQKKa5Ofp+ldxg2t
Fpjvx7qgiWjf+phGedOw/49suUbM5UZTQ+qOxtskEyfX/PVzgKV6aRMCAQI=
-----END DH PARAMETERS-----
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff2?|ico|jpg|jpeg)$
RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
RewriteCond %{REQUEST_FILENAME} !core/img/manifest.json$
RewriteCond %{REQUEST_FILENAME} !/remote.php
RewriteCond %{REQUEST_FILENAME} !/public.php
RewriteCond %{REQUEST_FILENAME} !/cron.php
RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php
RewriteCond %{REQUEST_FILENAME} !/status.php
RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php
RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php
RewriteCond %{REQUEST_FILENAME} !/robots.txt
RewriteCond %{REQUEST_FILENAME} !/updater/
RewriteCond %{REQUEST_FILENAME} !/ocs-provider/
RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
RewriteRule . index.php [PT,E=PATH_INFO:$1]
RewriteBase /
<IfModule mod_env.c>
SetEnv front_controller_active true
<IfModule mod_dir.c>
DirectorySlash off
</IfModule>
</IfModule>
</IfModule>
ServerRoot "/etc/httpd"
Listen 80
Include conf.modules.d/*.conf
User apache
Group apache
ServerAdmin root@localhost
ServerName {{ ansible_fqdn }}
<Directory />
    AllowOverride none
    Require all denied
</Directory>
DocumentRoot "/var/www/html"
<Directory "/var/www">
    AllowOverride None
    Require all granted
</Directory>
<Directory "/var/www/html">
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>
<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>
<Files ".ht*">
    Require all denied
</Files>
ErrorLog "logs/error_log"
LogLevel warn
<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    <IfModule logio_module>
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>
    CustomLog "logs/access_log" combined
</IfModule>
<IfModule http2_module>
    Protocols h2 h2c http/1.1
    H2Direct on
    H2StreamMaxMemSize 5120000000
</IfModule>
<IfModule prefork.c>
    StartServers 2
    MinSpareThreads 25
    MaxSpareThreads 75
    ThreadLimit 64
    ThreadsPerChild 25
    MaxRequestWorkers 150
    MaxConnectionsPerChild 1000
</IfModule>
<IfModule mpm_event_module>
    StartServers 2
    MinSpareThreads 25
    MaxSpareThreads 75
    ThreadLimit 64
    ThreadsPerChild 25
    MaxRequestWorkers 150
    MaxConnectionsPerChild 1000
</IfModule>
<IfModule alias_module>
   ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
</IfModule>
<Directory "/var/www/cgi-bin">
    AllowOverride None
    Options None
    Require all granted
</Directory>
<IfModule mime_module>
    TypesConfig /etc/mime.types
    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz
    AddType text/html .shtml
    AddOutputFilter INCLUDES .shtml
</IfModule>
AddDefaultCharset UTF-8
<IfModule mime_magic_module>
    MIMEMagicFile conf/magic
</IfModule>
EnableSendfile on
ServerTokens Prod
ServerSignature Off
TraceEnable Off
IncludeOptional conf.d/*.conf
<VirtualHost *:80>
  ServerName {{ ansible_fqdn }}
  ServerAdmin admin@{{ ansible_fqdn }}
  RewriteEngine On
  RewriteCond %{SERVER_NAME} ={{ ansible_fqdn }}
  RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<IfModule mod_ssl.c>
   <VirtualHost *:443>
     SSLEngine on
     SSLOptions +StrictRequire
     LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
     LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
     ServerName {{ ansible_fqdn }}
     ServerAdmin admin@{{ ansible_fqdn }}
     DocumentRoot /var/www/html/nextcloud
     SSLCertificateFile /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.crt
     SSLCertificateKeyFile /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.key
     <Directory /var/www/html/nextcloud/>
     Options +FollowSymlinks
     AllowOverride All
     <IfModule mod_dav.c>
     Dav off
     </IfModule>
     SetEnv HOME /var/www/html/nextcloud
     SetEnv HTTP_HOME /var/www/html/nextcloud
     </Directory>
     <IfModule mod_headers.c>
     Header always set Strict-Transport-Security "max-age=15768000; preload"
     </IfModule>
     </VirtualHost>
     SSLProtocol -all +TLSv1.3 +TLSv1.2
     SSLCipherSuite TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384
     SSLHonorCipherOrder on
     SSLCompression off
     SSLSessionTickets off
     SSLUseStapling on
     SSLStaplingResponderTimeout 5
     SSLStaplingReturnResponderErrors off
     SSLStaplingCache shmcb:/var/run/ocsp(128000)
     SSLOpenSSLConfCmd Curves X448:secp521r1:secp384r1:prime256v1
     SSLOpenSSLConfCmd ECDHParameters secp384r1
     SSLOpenSSLConfCmd DHParameters "/etc/{{ ansible_fqdn }}/ssl/dhparams.pem"
     SSLRandomSeed startup file:/dev/urandom 1024
     SSLRandomSeed connect file:/dev/urandom 1024
</IfModule>
[PHP]
engine = On
short_open_tag = Off
precision = 14
output_buffering = 'Off'
zlib.output_compression = Off
unserialize_callback_func =
serialize_precision = -1
disable_functions =
zend.enable_gc = On
expose_php = On
max_execution_time = 1800
max_input_time = 3600
post_max_size = 10240M
upload_max_filesize = 10240M
max_file_uploads = 100
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
html_errors = On
auto_globals_jit = On
auto_prepend_file =
auto_append_file =
enable_dl = Off
file_uploads = On
allow_url_fopen = On
allow_url_include = Off
cli_server.color = On
[iconv]
[intl]
[mail function]
sendmail_path = /usr/sbin/sendmail -t -i
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[Session]
session.save_handler = files
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_secure = True
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.cookie_samesite =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.sid_length = 26
session.trans_sid_tags = "a=href,area=href,frame=src,form="
session.sid_bits_per_character = 5
[Assertion]
zend.assertions = -1
[mbstring]
tidy.clean_output = Off
soap.wsdl_cache_enabled=1
ldap.max_links = -1
[openssl]
[www]
user = apache
group = apache
listen = /run/php-fpm/www.sock
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path]    = /var/lib/php/session
php_value[soap.wsdl_cache_dir]  = /var/lib/php/wsdlcache

Pour terminer cet article, le répertoire des variables, à adapter bien sûr :

nextcloud_url: "https://download.nextcloud.com/server/releases/latest.tar.bz2"
nextcloud_db: "nextcloud"
nextcloud_db_password: "pas!sD234"
nextcloud_db_user: "ncuser"
nextcloud_admin_user: "admin"
nextcloud_admin_password: "pas!sD234"
nextcloud_gateway: "192.168.1.254"
selinux_state: "enforcing"
fips: false

C’est terminé.

Bon Hacking !

3 commentaires sur « Installer Nextcloud sur Fedora Servers Cloud grâce à Terraform et Ansible, part2 »

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.