Deploying Drupal 8 using Ansible Playbook: Part 3

Drupal Role

mkdir -p roles/drupal/tasks
nano roles/drupal/tasks/main.yaml
---
- name: install the latest Composer
shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer warn=False
args:
creates: /usr/local/bin/composer
- name: install git
package: name=git state=latest
- name: clone Drush repository
git:
repo: https://github.com/drush-ops/drush.git
version: "9.3.0"
dest: /opt/drush
- name: install Drush dependencies with Composer
shell: composer install
args:
chdir: "/opt/drush"
- name: create the Drush executable link
file:
src: /opt/drush/drush
dest: /usr/local/bin/drush
state: link
- name: install mysql client
package: name=mysql-client state=present
- name: create the Drupal install directory
file:
path: "{{ drupal_site_path }}"
state: directory
- name: clone Drupal repository
git:
repo: http://git.drupal.org/project/drupal.git
version: "{{ drupal_version }}"
dest: "{{ drupal_site_path }}"
- name: install Drupal dependencies with Composer
shell: composer install
args:
chdir: "{{ drupal_site_path }}"
creates: "{{ drupal_site_path }}/vendor/autoload.php"
- name: install Drupal
shell: drush si -y --site-name="{{ drupal_site_name }}" --account-name={{ drupal_admin_username }} --account-pass="{{ drupal_admin_pass }}" --db-url=mysql://{{ drupal_db_user }}:{{ drupal_db_pass }}@{{ hostvars['db-server']['ansible_default_ipv4']['address'] }}/{{ drupal_db_name }}
args:
chdir: "{{ drupal_site_path }}"
- name: set proper ownership
file:
path: "{{ drupal_site_path }}"
owner: www-data
group: www-data
recurse: yes
- name: set permissions on the settings file
file:
path: "{{ drupal_site_path }}/sites/default/settings.php"
mode: 0744
- name: set permissions on files direcotry
file:
path: "{{ drupal_site_path }}/sites/default/files"
mode: 0777
state: directory
recurse: yes
nano group_vars/all.yaml
# Drupal Variablesdrupal_version: 8.5.3
drupal_site_path: "/var/www/drupal"
drupal_site_name: "My Drupal Site"
drupal_admin_username: admin
drupal_admin_pass: StrongPass

NGINX Role

mkdir -p roles/nginx/{tasks,handlers,templates}
nano roles/nginx/tasks/main.yaml
---
- name: remove Apache web server
package: name=apache2 state=absent

- name: install nginx web server
package: name=nginx state=present
- name: add the certbot repository
apt_repository: repo='ppa:certbot/certbot' state=present update_cache=yes
when:
- letsencrypt_generate == true
- letsencrypt_domain is defined
- letsencrypt_email is defined
- name: install certbot
package: name=python-certbot-nginx state=latest update_cache=yes
when:
- letsencrypt_generate == true
- letsencrypt_domain is defined
- letsencrypt_email is defined
- name: start and enable nginx service
service: name=nginx state=started enabled=yes
- name: generate letsencrypt certificates
shell: certbot certonly --nginx -d {{ letsencrypt_domain }} -n --agree-tos -m {{ letsencrypt_email }}
args:
creates: /etc/letsencrypt/live/{{ letsencrypt_domain }}
when:
- letsencrypt_generate == true
- letsencrypt_domain is defined
- letsencrypt_email is defined
- name: remove default nginx configuration
file: name=/etc/nginx/sites-enabled/default state=absent
notify:
- restart nginx
- name: generate a new configuration for Drupal
template:
src: drupal.conf
dest: /etc/nginx/sites-enabled/drupal.conf
owner: www-data
group: www-data
notify:
- restart nginx
- name: configure the certbot cronjob
cron:
name: letsencrypt_renewal
special_time: weekly
job: /usr/bin/certbot renew --post-hook "systemctl reload nginx"
when:
- letsencrypt_generate == true
- letsencrypt_domain is defined
- letsencrypt_email is defined
- meta: flush_handlers
nano group_vars/all.yaml
# Let's Encrypt Settings# Set it to false if domain is not configured.
letsencrypt_generate: true
letsencrypt_domain: mydrupal.example.com
letsencrypt_email: me@example.com
nano roles/nginx/handlers/main.yaml
---
- name: restart nginx
service: name=nginx state=restarted
nano roles/nginx/templates/drupal.conf
{% if letsencrypt_generate and letsencrypt_domain is defined and letsencrypt_email is defined %}
server {
listen 80 default_server;
server_name {{ letsencrypt_domain }};
return 301 https://$host$request_uri;
}
server {
listen 443 default_server;
server_name {{ letsencrypt_domain }};
ssl_certificate /etc/letsencrypt/live/{{ letsencrypt_domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ letsencrypt_domain }}/privkey.pem;
ssl on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
{% endif %}
{% if not letsencrypt_generate %}
server {
listen 80 default_server;
{% endif %}
root {{ drupal_site_path }}; access_log /var/log/nginx/drupal.access.log;
error_log /var/log/nginx/drupal.error.log;
gzip on;
gzip_http_version 1.1;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript text/xml application/xml application/rss+xml application/atom+xml application/rdf+xml;
gzip_buffers 16 8k;
gzip_disable "MSIE [1-6].(?!.*SV1)";
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location ~ \..*/.*\.php$ {
return 403;
}
location ~ ^/sites/.*/private/ {
return 403;
}
location ~ (^|/)\. {
return 403;
}
location / {
try_files $uri /index.php?$query_string; # For Drupal >= 7
}
location @rewrite {
rewrite ^/(.*)$ /index.php?q=$1;
}
location ~ '\.php$|^/update.php' {
fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
include fastcgi_params;
include snippets/fastcgi-php.conf;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_intercept_errors on;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
}
location ~ ^/sites/.*/files/styles/ { # For Drpal >= 7
try_files $uri @rewrite;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
}
drupal-ansible/
├── ansible.cfg
├── group_vars
│ └── all.yaml
├── hosts
├── playbook.yaml
└── roles
├── drupal
│ └── tasks
│ └── main.yaml
├── mariadb
│ ├── handlers
│ │ └── main.yaml
│ ├── tasks
│ │ └── main.yaml
│ └── templates
│ └── my.cnf
├── nginx
│ ├── handlers
│ │ └── main.yaml
│ ├── tasks
│ │ └── main.yaml
│ └── templates
│ └── drupal.conf
└── php
└── tasks
└── main.yaml
14 directories, 12 files

Running the Playbook

ansible-playbook playbook.yaml
aliyun@ubuntu:~/drupal-ansible$ ansible-playbook playbook.yaml PLAY [all] ***************************************************************************************************TASK [Gathering Facts] ***************************************************************************************
ok: [web-server]
ok: [db-server]
TASK [update and upgrade system packages] ********************************************************************...TASK [nginx : configure the certbot cronjob] *****************************************************************
changed: [web-server]
RUNNING HANDLER [nginx : restart nginx] **********************************************************************
changed: [web-server]
PLAY RECAP ***************************************************************************************************
db-server : ok=6 changed=12 unreachable=0 failed=0
web-server : ok=18 changed=24 unreachable=0 failed=0

Conclusion

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store