From 5f8f23065ee48aa11ec13dac95ddd51a83bcb4e5 Mon Sep 17 00:00:00 2001 From: Daniel Berteaud Date: Mon, 15 Mar 2021 10:00:06 +0100 Subject: [PATCH] Update to 2021-03-15 10:00 --- roles/bookstack/defaults/main.yml | 58 +++++++++++++++++++++ roles/bookstack/meta/main.yml | 8 +++ roles/bookstack/tasks/archive_post.yml | 10 ++++ roles/bookstack/tasks/archive_pre.yml | 31 ++++++++++++ roles/bookstack/tasks/cleanup.yml | 9 ++++ roles/bookstack/tasks/conf.yml | 43 ++++++++++++++++ roles/bookstack/tasks/directories.yml | 23 +++++++++ roles/bookstack/tasks/facts.yml | 20 ++++++++ roles/bookstack/tasks/install.yml | 86 ++++++++++++++++++++++++++++++++ roles/bookstack/tasks/main.yml | 13 +++++ roles/bookstack/tasks/user.yml | 5 ++ roles/bookstack/tasks/write_version.yml | 5 ++ roles/bookstack/templates/env.j2 | 20 ++++++++ roles/bookstack/templates/httpd.conf.j2 | 39 +++++++++++++++ roles/bookstack/templates/perms.sh.j2 | 19 +++++++ roles/bookstack/templates/php.conf.j2 | 35 +++++++++++++ roles/bookstack/templates/post-backup.j2 | 3 ++ roles/bookstack/templates/pre-backup.j2 | 12 +++++ 18 files changed, 439 insertions(+) create mode 100644 roles/bookstack/defaults/main.yml create mode 100644 roles/bookstack/meta/main.yml create mode 100644 roles/bookstack/tasks/archive_post.yml create mode 100644 roles/bookstack/tasks/archive_pre.yml create mode 100644 roles/bookstack/tasks/cleanup.yml create mode 100644 roles/bookstack/tasks/conf.yml create mode 100644 roles/bookstack/tasks/directories.yml create mode 100644 roles/bookstack/tasks/facts.yml create mode 100644 roles/bookstack/tasks/install.yml create mode 100644 roles/bookstack/tasks/main.yml create mode 100644 roles/bookstack/tasks/user.yml create mode 100644 roles/bookstack/tasks/write_version.yml create mode 100644 roles/bookstack/templates/env.j2 create mode 100644 roles/bookstack/templates/httpd.conf.j2 create mode 100644 roles/bookstack/templates/perms.sh.j2 create mode 100644 roles/bookstack/templates/php.conf.j2 create mode 100644 roles/bookstack/templates/post-backup.j2 create mode 100644 roles/bookstack/templates/pre-backup.j2 diff --git a/roles/bookstack/defaults/main.yml b/roles/bookstack/defaults/main.yml new file mode 100644 index 0000000..8126dac --- /dev/null +++ b/roles/bookstack/defaults/main.yml @@ -0,0 +1,58 @@ +--- + +# Version to deploy +bookstack_version: 0.31.8 +# URL of the arhive +bookstack_archive_url: https://github.com/BookStackApp/BookStack/archive/v{{ bookstack_version }}.tar.gz +# Expected sha1 of the archive +bookstack_archive_sha1: 0d6990a6c2b196f4e4ec2e4e06fb75ffba3c96ff + +# Should ansible handle bookstack upgrades or just the inintial install +bookstack_manage_upgrade: True + +# We can deploy several bookstack instance on a single host +# each one can have a different ID which can be a simple number +# or a short string +bookstack_id: 1 +# Where to install bookstack +bookstack_root_dir: /opt/bookstack_{{ bookstack_id }} +# User under which the app will be executed +bookstack_php_user: php-bookstack_{{ bookstack_id }} +# Version of PHP used +bookstack_php_version: 74 +# Or you can specify here the name of a custom PHP FPM pool. See the httpd_php role +# bookstack_php_fpm_pool: custom_bookstack + +# If defined, an alias will be added in httpd's config to access bookstack +# Else, you'll have to defined a vhost to make bookstack accessible. See httpd_common role +bookstack_web_alias: /bookstack_{{ bookstack_id }} + +# You can restrict access to bookstack. If not defined or empty, +# no restriction will be made +bookstack_src_ip: [] + +# MySQL Database +bookstack_db_server: "{{ mysql_server | default('locaclhost') }}" +bookstack_db_port: 3306 +bookstack_db_user: bookstack_{{ bookstack_id }} +bookstack_db_name: bookstack_{{ bookstack_id }} +# If no pass is defined, a random one will be created and stored in meta/ansible_dbpass +# bookstack_db_pass: S3cr3t. + +# Application key. If not defined, a random one will be generated and store in meta/ansible_app_key +# bookstack_app_key: base64:H/zDPBqtK2BjOkgCrMMGGH+sSjOBrBs/ibcD4ozQc90= + +# Public URL of the app +bookstack_public_url: http://{{ inventory_hostname }}/bookstack_{{ bookstack_id }} + +# Email settings. Default will use local postfix installation +bookstack_email_name: BookStack +bookstack_email_from: no-reply@{{ ansible_domain }} +bookstack_email_server: localhost +bookstack_email_port: 25 +# You can set user and pass if needed +# bookstack_email_user: user@example.org +# bookstack_email_pass: S3cR3t. +# Encryption can be tls, ssl or null +bookstack_email_encryption: 'null' + diff --git a/roles/bookstack/meta/main.yml b/roles/bookstack/meta/main.yml new file mode 100644 index 0000000..9391075 --- /dev/null +++ b/roles/bookstack/meta/main.yml @@ -0,0 +1,8 @@ +--- + +allow_duplicates: True +dependencies: + - role: mkdir + - role: mysql_server + when: bookstack_db_server in ['localhost','127.0.0.1'] + - role: composer diff --git a/roles/bookstack/tasks/archive_post.yml b/roles/bookstack/tasks/archive_post.yml new file mode 100644 index 0000000..a4e7284 --- /dev/null +++ b/roles/bookstack/tasks/archive_post.yml @@ -0,0 +1,10 @@ +--- + +- name: Compress previous version + command: tar cf {{ bookstack_root_dir }}/archives/{{ bookstack_current_version }}.tar.zst ./ --use-compress-program=zstd + args: + chdir: "{{ bookstack_root_dir }}/archives/{{ bookstack_current_version }}" + warn: False + environment: + ZSTD_CLEVEL: 10 + tags: bookstack diff --git a/roles/bookstack/tasks/archive_pre.yml b/roles/bookstack/tasks/archive_pre.yml new file mode 100644 index 0000000..4597df7 --- /dev/null +++ b/roles/bookstack/tasks/archive_pre.yml @@ -0,0 +1,31 @@ +--- + +- name: Create the archive dir + file: path={{ bookstack_root_dir }}/archives/{{ bookstack_current_version }} state=directory + tags: bookstack + +- name: Archive current version + synchronize: + src: "{{ root_dir }}/app" + dest: "{{ root_dir }}/archives/{{ version }}/" + compress: False + delete: True + rsync_opts: + - '--exclude=/storage/' + delegate_to: "{{ inventory_hostname }}" + tags: bookstack + +- name: Dump the database + mysql_db: + state: dump + name: "{{ bookstack_db_name }}" + target: "{{ bookstack_root_dir }}/archives/{{ current_version }}/{{ bookstack_db_name }}.sql.xz" + login_host: "{{ bookstack_db_server }}" + login_user: "{{ bookstack_db_user }}" + login_password: "{{ bookstack_db_pass }}" + quick: True + single_transaction: True + environment: + XZ_OPT: -T0 + tags: bookstack + diff --git a/roles/bookstack/tasks/cleanup.yml b/roles/bookstack/tasks/cleanup.yml new file mode 100644 index 0000000..63642a9 --- /dev/null +++ b/roles/bookstack/tasks/cleanup.yml @@ -0,0 +1,9 @@ +--- + +- name: Remove tmp and obsolete files + file: path={{ item }} state=absent + loop: + - "{{ bookstack_root_dir }}/archives/{{ bookstack_current_version }}" + - "{{ bookstack_root_dir }}/tmp/BookStack-{{ bookstack_version }}" + - "{{ bookstack_root_dir }}/tmp/BookStack-{{ bookstack_version }}.tar.gz" + tags: bookstack diff --git a/roles/bookstack/tasks/conf.yml b/roles/bookstack/tasks/conf.yml new file mode 100644 index 0000000..b72f8ed --- /dev/null +++ b/roles/bookstack/tasks/conf.yml @@ -0,0 +1,43 @@ +--- + +- import_tasks: ../includes/webapps_webconf.yml + vars: + - app_id: bookstack_{{ bookstack_id }} + - php_version: "{{ bookstack_php_version }}" + - php_fpm_pool: "{{ bookstack_php_fpm_pool | default('') }}" + tags: bookstack + +- when: bookstack_app_key is not defined + block: + - name: Generate a uniq application key + shell: /bin/php{{ bookstack_php_version }} {{ bookstack_root_dir }}/app/artisan key:generate --show > {{ bookstack_root_dir }}/meta/ansible_app_key + args: + creates: "{{ bookstack_root_dir }}/meta/ansible_app_key" + + - name: Read application key + slurp: src={{ bookstack_root_dir }}/meta/ansible_app_key + register: bookstack_rand_app_key + + - set_fact: bookstack_app_key={{ bookstack_rand_app_key.content | b64decode | trim }} + + tags: bookstack + +- name: Deploy BookStack configuration + template: src=env.j2 dest={{ bookstack_root_dir }}/app/.env group={{ bookstack_php_user }} mode=640 + tags: bookstack + +- name: Migrate the database + shell: echo yes | /bin/php{{ bookstack_php_version }} artisan migrate + args: + chdir: "{{ bookstack_root_dir }}/app" + become_user: "{{ bookstack_php_user }}" + when: bookstack_install_mode != 'none' + tags: bookstack + +- name: Deploy permission script + template: src=perms.sh.j2 dest={{ bookstack_root_dir }}/perms.sh mode=755 + tags: bookstack + +- name: Apply permissions + command: "{{ bookstack_root_dir }}/perms.sh" + tags: bookstack diff --git a/roles/bookstack/tasks/directories.yml b/roles/bookstack/tasks/directories.yml new file mode 100644 index 0000000..3e97b06 --- /dev/null +++ b/roles/bookstack/tasks/directories.yml @@ -0,0 +1,23 @@ +--- + +- name: Create required directories + file: path={{ item.dir }} state=directory owner={{ item.owner | default(omit) }} group={{ item.group | default(omit) }} mode={{ item.mode | default(omit) }} + loop: + - dir: "{{ bookstack_root_dir }}" + - dir: "{{ bookstack_root_dir }}/meta" + mode: 700 + - dir: "{{ bookstack_root_dir }}/backup" + mode: 700 + - dir: "{{ bookstack_root_dir }}/archives" + mode: 700 + - dir: "{{ bookstack_root_dir }}/app" + - dir: "{{ bookstack_root_dir }}/sessions" + group: "{{ bookstack_php_user }}" + mod: 770 + - dir: "{{ bookstack_root_dir }}/tmp" + group: "{{ bookstack_php_user }}" + mod: 770 + - dir: "{{ bookstack_root_dir }}/data" + group: "{{ bookstack_php_user }}" + mod: 700 + tags: bookstack diff --git a/roles/bookstack/tasks/facts.yml b/roles/bookstack/tasks/facts.yml new file mode 100644 index 0000000..cb53ed8 --- /dev/null +++ b/roles/bookstack/tasks/facts.yml @@ -0,0 +1,20 @@ +--- + +# Detect installed version (if any) +- block: + - import_tasks: ../includes/webapps_set_install_mode.yml + vars: + - root_dir: "{{ bookstack_root_dir }}" + - version: "{{ bookstack_version }}" + - set_fact: bookstack_install_mode={{ (install_mode == 'upgrade' and not bookstack_manage_upgrade) | ternary('none',install_mode) }} + - set_fact: bookstack_current_version={{ current_version | default('') }} + tags: bookstack + +# Create a random pass for the DB if needed +- block: + - import_tasks: ../includes/get_rand_pass.yml + vars: + - pass_file: "{{ bookstack_root_dir }}/meta/ansible_dbpass" + - set_fact: bookstack_db_pass={{ rand_pass }} + when: bookstack_db_pass is not defined + tags: bookstack diff --git a/roles/bookstack/tasks/install.yml b/roles/bookstack/tasks/install.yml new file mode 100644 index 0000000..792b978 --- /dev/null +++ b/roles/bookstack/tasks/install.yml @@ -0,0 +1,86 @@ +--- + +- name: Install needed tools + package: + name: + - acl + - tar + - zstd + - mariadb + tags: bookstack + +- when: bookstack_install_mode != 'none' + block: + - name: Download bookstack + get_url: + url: "{{ bookstack_archive_url }}" + dest: "{{ bookstack_root_dir }}/tmp" + checksum: sha1:{{ bookstack_archive_sha1 }} + + - name: Extract the archive + unarchive: + src: "{{ bookstack_root_dir }}/tmp/BookStack-{{ bookstack_version }}.tar.gz" + dest: "{{ bookstack_root_dir }}/tmp" + remote_src: True + + - name: Move BookStack to its final dir + synchronize: + src: "{{ bookstack_root_dir }}/tmp/BookStack-{{ bookstack_version }}/" + dest: "{{ bookstack_root_dir }}/app/" + delete: True + compress: False + rsync_opts: + - '--exclude=/storage/' + - '--exclude=/public/uploads/' + delegate_to: "{{ inventory_hostname }}" + + - name: Populate data directories + synchronize: + src: "{{ bookstack_root_dir }}/tmp/BookStack-{{ bookstack_version }}/{{ item }}" + dest: "{{ bookstack_root_dir }}/data/" + compress: False + delegate_to: "{{ inventory_hostname }}" + loop: + - storage + - public/uploads + + - name: Link data directories + file: src={{ item.src }} dest={{ item.dest }} state=link + loop: + - src: "{{ bookstack_root_dir }}/data/storage" + dest: "{{ bookstack_root_dir }}/app/storage" + - src: "{{ bookstack_root_dir }}/data/uploads" + dest: "{{ bookstack_root_dir }}/app/public/uploads" + + - name: Install PHP libs with composer + composer: + command: install + working_dir: "{{ bookstack_root_dir }}/app" + executable: /bin/php{{ bookstack_php_version }} + environment: + php: /bin/php{{ bookstack_php_version }} + + tags: bookstack + +- import_tasks: ../includes/webapps_create_mysql_db.yml + vars: + - db_name: "{{ bookstack_db_name }}" + - db_user: "{{ bookstack_db_user }}" + - db_server: "{{ bookstack_db_server }}" + - db_pass: "{{ bookstack_db_pass }}" + tags: bookstack + +- name: Set correct SELinux context + sefcontext: + target: "{{ bookstack_root_dir }}(/.*)?" + setype: httpd_sys_content_t + state: present + when: ansible_selinux.status == 'enabled' + tags: bookstack + +- name: Install pre/post backup hooks + template: src={{ item }}-backup.j2 dest=/etc/backup/{{ item }}.d/bookstack_{{ bookstack_id }} mode=700 + loop: + - pre + - post + tags: bookstack diff --git a/roles/bookstack/tasks/main.yml b/roles/bookstack/tasks/main.yml new file mode 100644 index 0000000..57f4c85 --- /dev/null +++ b/roles/bookstack/tasks/main.yml @@ -0,0 +1,13 @@ +--- + +- include: user.yml +- include: directories.yml +- include: facts.yml +- include: archive_pre.yml + when: bookstack_install_mode == 'upgrade' +- include: install.yml +- include: conf.yml +- include: write_version.yml +- include: archive_post.yml + when: bookstack_install_mode == 'upgrade' +- include: cleanup.yml diff --git a/roles/bookstack/tasks/user.yml b/roles/bookstack/tasks/user.yml new file mode 100644 index 0000000..ccec17e --- /dev/null +++ b/roles/bookstack/tasks/user.yml @@ -0,0 +1,5 @@ +--- + +- name: Create user account + user: name={{ bookstack_php_user }} system=True shell=/sbin/nologin home={{ bookstack_root_dir }} + tags: bookstack diff --git a/roles/bookstack/tasks/write_version.yml b/roles/bookstack/tasks/write_version.yml new file mode 100644 index 0000000..d7e8744 --- /dev/null +++ b/roles/bookstack/tasks/write_version.yml @@ -0,0 +1,5 @@ +--- + +- name: Write current version + copy: content={{ bookstack_version }} dest={{ bookstack_root_dir }}/meta/ansible_version + tags: bookstack diff --git a/roles/bookstack/templates/env.j2 b/roles/bookstack/templates/env.j2 new file mode 100644 index 0000000..76597fc --- /dev/null +++ b/roles/bookstack/templates/env.j2 @@ -0,0 +1,20 @@ +APP_KEY={{ bookstack_app_key }} +APP_URL={{ bookstack_public_url }} +DB_HOST={{ bookstack_db_server }} +DB_DATABASE={{ bookstack_db_name }} +DB_USERNAME={{ bookstack_db_user }} +DB_PASSWORD={{ bookstack_db_pass | quote }} +MAIL_DRIVER=smtp +MAIL_FROM_NAME="{{ bookstack_email_name }}" +MAIL_FROM={{ bookstack_email_from }} +MAIL_HOST={{ bookstack_email_server }} +MAIL_PORT={{ bookstack_email_port }} +{% if bookstack_email_user is defined and bookstack_email_pass is defined %} +MAIL_USERNAME={{ bookstack_email_user }} +MAIL_PASSWORD={{ bookstack_email_pass | quote }} +{% endif %} +MAIL_ENCRYPTION={{ bookstack_email_encryption }} +APP_TIMEZONE={{ system_tz | default('UTC') }} +SESSION_COOKIE_NAME=bookstack_{{ bookstack_id }}_session +CACHE_PREFIX=bookstack_{{ bookstack_id }} +#STORAGE_TYPE=local_secure diff --git a/roles/bookstack/templates/httpd.conf.j2 b/roles/bookstack/templates/httpd.conf.j2 new file mode 100644 index 0000000..d42fa33 --- /dev/null +++ b/roles/bookstack/templates/httpd.conf.j2 @@ -0,0 +1,39 @@ +{% if bookstack_web_alias is defined and bookstack_web_alias != False %} +Alias /{{ bookstack_web_alias | regex_replace('^/','') }} {{ bookstack_root_dir }}/app/public +{% else %} +# No alias defined, create a vhost to access it +{% endif %} + + + AllowOverride All + Options FollowSymLinks +{% if bookstack_src_ip is defined and bookstack_src_ip | length > 0 %} + Require ip {{ bookstack_src_ip | join(' ') }} +{% else %} + Require all granted +{% endif %} + + SetHandler "proxy:unix:/run/php-fpm/{{ bookstack_php_fpm_pool | default('bookstack_' + bookstack_id | string) }}.sock|fcgi://localhost" + + + RewriteEngine On + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Send Requests To Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + + + Require all denied + + + diff --git a/roles/bookstack/templates/perms.sh.j2 b/roles/bookstack/templates/perms.sh.j2 new file mode 100644 index 0000000..0dab99c --- /dev/null +++ b/roles/bookstack/templates/perms.sh.j2 @@ -0,0 +1,19 @@ +#!/bin/bash + +restorecon -R {{ bookstack_root_dir }} +chown root:root {{ bookstack_root_dir }} +chmod 700 {{ bookstack_root_dir }} +setfacl -k -b {{ bookstack_root_dir }} +setfacl -m u:{{ bookstack_php_user | default('apache') }}:rx,u:{{ httpd_user | default('apache') }}:x {{ bookstack_root_dir }} +find {{ bookstack_root_dir }}/app -type f -exec chmod 644 "{}" \; +find {{ bookstack_root_dir }}/app -type d -exec chmod 755 "{}" \; +chown root:{{ bookstack_php_user }} {{ bookstack_root_dir }}/app/.env +chmod 640 {{ bookstack_root_dir }}/app/.env +chown -R {{ bookstack_php_user }} {{ bookstack_root_dir }}/app/bootstrap/cache +chmod 700 {{ bookstack_root_dir }}/app/bootstrap/cache +chown -R {{ bookstack_php_user }} {{ bookstack_root_dir }}/data +chmod 700 {{ bookstack_root_dir }}/data +setfacl -m u:{{ httpd_user | default('apache') }}:rx {{ bookstack_root_dir }} {{ bookstack_root_dir }}/app/public +setfacl -m u:{{ httpd_user | default('apache') }}:x {{ bookstack_root_dir }} {{ bookstack_root_dir }}/data/ +setfacl -R -m u:{{ httpd_user | default('apache') }}:rx {{ bookstack_root_dir }} {{ bookstack_root_dir }}/data/uploads +find {{ bookstack_root_dir }} -name .htaccess -exec chmod 644 "{}" \; diff --git a/roles/bookstack/templates/php.conf.j2 b/roles/bookstack/templates/php.conf.j2 new file mode 100644 index 0000000..51a3b4b --- /dev/null +++ b/roles/bookstack/templates/php.conf.j2 @@ -0,0 +1,35 @@ +[bookstack_{{ bookstack_id }}] + +listen.owner = root +listen.group = apache +listen.mode = 0660 +listen = /run/php-fpm/bookstack_{{ bookstack_id }}.sock +user = {{ bookstack_php_user }} +group = {{ bookstack_php_user }} +catch_workers_output = yes + +pm = dynamic +pm.max_children = 15 +pm.start_servers = 3 +pm.min_spare_servers = 3 +pm.max_spare_servers = 6 +pm.max_requests = 5000 +request_terminate_timeout = 5m + +php_flag[display_errors] = off +php_admin_flag[log_errors] = on +php_admin_value[error_log] = syslog +php_admin_value[memory_limit] = 256M +php_admin_value[session.save_path] = {{ bookstack_root_dir }}/sessions +php_admin_value[upload_tmp_dir] = {{ bookstack_root_dir }}/tmp +php_admin_value[sys_temp_dir] = {{ bookstack_root_dir }}/tmp +php_admin_value[post_max_size] = 100M +php_admin_value[upload_max_filesize] = 100M +php_admin_value[disable_functions] = system, show_source, symlink, exec, dl, shell_exec, passthru, phpinfo, escapeshellarg, escapeshellcmd +php_admin_value[open_basedir] = {{ bookstack_root_dir }}:/usr/share/pear/:/usr/share/php/ +php_admin_value[max_execution_time] = 60 +php_admin_value[max_input_time] = 60 +php_admin_flag[allow_url_include] = off +php_admin_flag[allow_url_fopen] = off +php_admin_flag[file_uploads] = on +php_admin_flag[session.cookie_httponly] = on diff --git a/roles/bookstack/templates/post-backup.j2 b/roles/bookstack/templates/post-backup.j2 new file mode 100644 index 0000000..4813cc1 --- /dev/null +++ b/roles/bookstack/templates/post-backup.j2 @@ -0,0 +1,3 @@ +#!/bin/bash -e + +rm -f {{ bookstack_root_dir }}/backup/*.sql.zst diff --git a/roles/bookstack/templates/pre-backup.j2 b/roles/bookstack/templates/pre-backup.j2 new file mode 100644 index 0000000..599f019 --- /dev/null +++ b/roles/bookstack/templates/pre-backup.j2 @@ -0,0 +1,12 @@ +#!/bin/bash -e + +/usr/bin/mysqldump \ +{% if bookstack_db_server not in ['localhost','127.0.0.1'] %} + --user={{ bookstack_db_user | quote }} \ + --password={{ bookstack_db_pass | quote }} \ + --host={{ bookstack_db_server | quote }} \ + --port={{ bookstack_db_port | quote }} \ +{% endif %} + --quick --single-transaction \ + --add-drop-table {{ bookstack_db_name | quote }} | zstd -c > {{ bookstack_root_dir }}/backup/{{ bookstack_db_name }}.sql.zst +