From 8f97af7cc033f4c2b995d5d9f24ecc2494b9a335 Mon Sep 17 00:00:00 2001 From: Hamatoma Date: Thu, 25 Sep 2025 19:48:54 +0200 Subject: [PATCH] wordpress_latest.yaml works --- docu/de/61_wordpress.md | 17 ++++ playbooks.templates/wordpress_create.yaml | 62 ++++++++++++ playbooks.templates/wordpress_latest.yaml | 38 +++++++ templates.fix/nginx/wordpress.j2 | 115 ++++++++++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 docu/de/61_wordpress.md create mode 100644 playbooks.templates/wordpress_create.yaml create mode 100644 playbooks.templates/wordpress_latest.yaml create mode 100644 templates.fix/nginx/wordpress.j2 diff --git a/docu/de/61_wordpress.md b/docu/de/61_wordpress.md new file mode 100644 index 0000000..e8baddc --- /dev/null +++ b/docu/de/61_wordpress.md @@ -0,0 +1,17 @@ +# Wordpress-Installation + +## Installation +``` +ansible-playbook playbooks/wordpress_create -e domain=www.example.de -e wp_version=6.8.2 +ansible-playbook playbooks/webapp_create -e webapp_name=www.example.de \ + -e db_name=wpexample -e db_user=example -e db_password=TopSecret +ansible-playbook playbooks/ssl_mult_cert.yaml domains=example.de,www.example.de +# ODER (wenn kein zusätzliches www.*) +ansible-playbook playbooks/ssl_create_certificate.yaml domain=example.de +``` +- Kontrolle von /etc/nginx/sites-available/www.example.de +- Wenn Domäne erreichbar: +``` +ansible-playbook playbooks/lets_multi_cert.yaml domains=example.de,www.example.de +# ODER (wenn kein zusätzliches www.*) +ansible-playbook playbooks/lets_create.yaml domain=example.de diff --git a/playbooks.templates/wordpress_create.yaml b/playbooks.templates/wordpress_create.yaml new file mode 100644 index 0000000..ca5b92b --- /dev/null +++ b/playbooks.templates/wordpress_create.yaml @@ -0,0 +1,62 @@ +--- +# Creates a wordpress website for a domain +# needed facts (variables) from commandline: (e.g. -e domain=example.com +# domain: the site domain name +# wp_version: the version of the wordpress to install +# wp_shortname: the short name of the wordpress site. Used for log file names. +# optional: +# wp_php_version: the php version to use. Default: 8.3 +- hosts: all + vars_files: + - ../vars/common.yaml + - ../vars/ssl-certificate.yaml + tasks: + - name: Check pre-requisites + fail: + msg: "The variable 'domain', 'wp_version' and 'wp_shortname' must be defined: use -e domain=mydomain.com" + when: domain is not defined or domain == "" or wp_version is not defined or wp_version == "" or wp_shortname is not defined or wp_shortname == "" + - name: Is the zip file available? + ansible.builtin.stat: + path: "{{ remote_www_directory }}/packages/wordpress-{{ wp_version }}.zip" + register: wp_zip_file + - name: Fail if the zip file is not available + ansible.builtin.fail: + msg: "The wordpress zip file {{ remote_www_directory }}/packages/wordpress-{{ wp_version }}.zip is not available. Please download it first." + when: not wp_zip_file.stat + - name: Check whether the target directory already exists + ansible.builtin.stat: + path: "{{ remote_www_directory }}/{{ domain }}" + register: target_directory + - name: "Unarchive wordpress. Note: there is a wordpress subdirectory in the zip file" + ansible.builtin.unarchive: + src: "{{ remote_www_directory }}/packages/wordpress-{{ wp_version }}.zip" + dest: "{{ remote_www_directory }}" + remote_src: true + owner: www-data + group: www-data + mode: '0775' + when: not target_directory.stat.exists + - name: Rename the directory to the domain name + ansible.builtin.command: + cmd: mv {{ remote_www_directory }}/wordpress {{ remote_www_directory }}/{{ domain }} + when: not target_directory.stat.exists + - name: Create nginx site configuration + ansible.builtin.template: + src: ../templates.fix/nginx/wordpress.j2 + dest: /etc/nginx/sites-available/{{ domain }} + owner: root + group: root + mode: '0644' + vars: + domain: "{{ domain }}" + shortname: "{{ wp_shortname }}" + php_version: "{{ wp_php_version | default('8.3') }}" + + - name: Create symlink to sites-enabled + ansible.builtin.file: + src: "../sites-available/{{ domain }}" + dest: "/etc/nginx/sites-enabled/{{ domain }}" + state: link + force: true + follow: false + diff --git a/playbooks.templates/wordpress_latest.yaml b/playbooks.templates/wordpress_latest.yaml new file mode 100644 index 0000000..f5f7053 --- /dev/null +++ b/playbooks.templates/wordpress_latest.yaml @@ -0,0 +1,38 @@ +--- +- name: Download WordPress page and extract version + hosts: all + gather_facts: false + + tasks: + - name: Define the package directory + ansible.builtin.set_fact: + package_dir: "/srv/www/packages" + url_zip: "https://de.wordpress.org/latest-de_DE.zip" + url_page: "https://de.wordpress.org/download" + - name: Download the wordpress.org download page + ansible.builtin.uri: + url: "{{ url_page }}" + return_content: true + register: wordpress_page_content + delegate_to: localhost + + - name: Extract the version number + ansible.builtin.set_fact: + wp_version: "{{ wordpress_page_content.content | regex_search('WordPress (\\d+\\.\\d+\\.\\d+) herunterladen') | regex_replace('[^.0-9]', '') }}" + - name: Display the extracted version + ansible.builtin.debug: + msg: "The latest WordPress version is {{ wp_version }}" + - name: Test wether the zip file is available + ansible.builtin.stat: + path: "{{ package_dir }}/wordpress-{{ wp_version }}.zip" + register: wp_zip_stat + - name: log the result of the stat + ansible.builtin.debug: + msg: "The file already exists: {{ package_dir }}/wordpress-{{ wp_version }}.zip" + when : wp_zip_stat.stat.exists + - name: Download the WordPress zip file if not already present + ansible.builtin.get_url: + url: "{{ url_zip }}" + dest: "{{ package_dir }}/wordpress-{{ wp_version }}.zip" + when: not wp_zip_stat.stat.exists + diff --git a/templates.fix/nginx/wordpress.j2 b/templates.fix/nginx/wordpress.j2 new file mode 100644 index 0000000..d8b69ac --- /dev/null +++ b/templates.fix/nginx/wordpress.j2 @@ -0,0 +1,115 @@ +server { + listen 80; + server_name {{ domain }} www.{{ domain }}; + include snippets/letsencrypt.conf; + location / { + return 301 https://{{ domain }}$request_uri; # enforce https + } +} +server { + listen 443 ssl; + http2 on; + ssl_certificate /etc/letsencrypt/live/{{ domain }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ domain }}/privkey.pem; +# ssl_certificate /etc/ssl/certs/{{ domain }}.pem; +# ssl_certificate_key /etc/ssl/private/{{ domain }}.key; + + server_name {{ domain }}; + location / { + return 301 https://www.{{ domain }}$request_uri; + } +} +server { + listen 443 ssl; + http2 on; + ssl_certificate /etc/letsencrypt/live/{{ domain }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ domain }}/privkey.pem; +# ssl_certificate /etc/ssl/certs/{{ domain }}.pem; +# ssl_certificate_key /etc/ssl/private/{{ domain }}.key; + + server_name www.{{ domain }}; + root /srv/www/{{ domain }}/; + + + access_log /var/log/nginx/a_{{ shortname }}.log; + error_log /var/log/nginx/e_{{ shortname }}.log; + + index index.php; + client_max_body_size 1G; + autoindex on; + + # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac). + # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban) + + location ^~ /.well-known { + allow all; + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain; charset=utf-8'; + add_header 'Content-Length' 0; + return 204; + } + if ($request_method = 'POST') { + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; + } + if ($request_method = 'GET') { + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; + } + + } + #location ~ /\. { + # deny all; + #} + + + # Deny access to any files with a .php extension in the uploads directory + # Works in sub-directory installs and also in multisite network + # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban) + location ~* /(?:uploads|files)/.*\.php$ { + deny all; + } + + location = /favicon.ico { + log_not_found off; + access_log off; + } + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + } + + location / { + # This is cool because no php is touched for static content. + # include the "?$args" part so non-default permalinks doesn't break when using query string + try_files $uri $uri/ /index.php?$args; + } + + location ~ \.php$ { + #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini + include fastcgi.conf; + fastcgi_intercept_errors on; + fastcgi_pass unix:/var/run/php/php{{ php_version }}-fpm.sock; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTPS $fastcgi_https; + fastcgi_param HTTP_AUTHORIZATION $http_authorization; + + fastcgi_buffers 16 16k; + fastcgi_buffer_size 32k; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { + expires max; + log_not_found off; + } +} -- 2.47.2