Ansible自动化部署WordPress后无法进入管理仪表盘问题求助
WordPress Ansible自动化部署后无法登录管理仪表盘
我基于Ubuntu官方指南编写了Ansible Playbook,在Linux虚拟机上自动化部署WordPress。执行Playbook后,访问http://localhost:80能正常进入WordPress安装页面,填写信息后显示安装成功,但点击登录按钮后始终停留在登录页面,没有任何错误提示。
更新1:如果跳过WordPress盐值/密钥生成的步骤,部署完成后可以正常登录进入管理仪表盘。
相关代码与配置
Ansible Playbook(SetupWordpress.yaml)
- name: "Installing wordpress dependencies" hosts: all become: True gather_facts: True vars: get_installer: 'curl -sS https://getcomposer.org/installer -o /tmp/composer-setup.php || /bin/true' get_signature: 'curl -sS https://composer.github.io/installer.sig' tasks: - name: "Update repository" apt: update_cache: "yes" - name: "Installing requirements" apt: name: - "curl" - "php" - "php-cli" - "gnupg" - "unzip" - "mysql-server" - "php-fpm" - "php-mysql" - "apache2" - "ghostscript" - "libapache2-mod-php" - "php-bcmath" - "php-curl" - "php-imagick" - "php-intl" - "php-json" - "php-mbstring" - "php-xml" - "php-zip" state: present - name: Populate service facts ansible.builtin.service_facts: - name: Print service facts ansible.builtin.debug: var: ansible_facts.services - name: "stopping nginx if running" service: name: nginx state: stopped when: "'nginx' in ansible_facts.services" - name: "remove nginx if installed" apt: name: - "nginx" state: absent - name: stop Mysql service: name: mysql state: stopped when: "'mysql' in ansible_facts.services" - name: stop apache2 service: name: apache2 state: stopped when: "'apache2' in ansible_facts.services" - name: Installing wordpress through source hosts: all become: True gather_facts: False vars: wprootdir: "/srv/www/wordpress" tasks: - name: checking if wp src dir exists stat: path: "{{ wprootdir }}" register: dir_details - name: delete existing wordpress source files become_user: www-data no_log: True file: path: "{{ wprootdir }}" state: absent - name: creating /var/www for wordpress source file: path: "/srv/www/wordpress" recurse: yes state: directory owner: www-data mode: '0755' - name: downloading and extracting wordpress source shell: cmd: "curl https://wordpress.org/latest.tar.gz | sudo -u www-data tar zx -C /srv/www" register: status - fail: msg: "Unable to download or extract wordpress source" when: (status.rc != 0) - name: Configuring apache for wordpress hosts: all become: True gather_facts: False vars: wprootdir: "/srv/www/wordpress" wpconffile: "/etc/apache2/sites-available/wordpress.conf" tasks: - name: deleting the file if it exists file: path: "{{ wpconffile }}" state: absent - name: creating wordpress conf file file: path: "{{ wpconffile }}" state: touch owner: www-data - name: populating wordpress conf file template: src: apache2.j2 dest: "{{ wpconffile }}" - name: enabling the site shell: cmd: "a2ensite wordpress" - name: enable URL rewriting shell: cmd: "a2enmod rewrite" - name: disable default "it works" site shell: cmd: "a2dissite 000-default" - name: restart apache2 service: name: apache2 state: reloaded - name: Configuring database hosts: all become: True gather_facts: True vars: mysql_port: 3306 mysql_socket: /var/run/mysqld/mysqld.sock mysql_superuser: root mysql_superuser_home: "{% if mysql_superuser == 'root' %}/root{% else %}/home/{{ mysql_superuser }}{% endif %}" mysql_superuser_password: SuperUserPwd mysql_wordpress_password: WordpressPwd http_port: 80 tasks: - name: Installing PyMySql through pip pip: name: PyMySql state: present - name: ensure mysql is running and starts on boot service: name: mysql state: started enabled: True - name: Removes anonymous user account for localhost community.mysql.mysql_user: name: '' state: absent login_user: root login_password: "" login_unix_socket: "{{ mysql_socket }}" when: ansible_local.mysqlinfo is undefined - name: adding a password for root user mysql_user: name: "{{ mysql_superuser }}" host: localhost password: "{{ mysql_superuser_password }}" priv: "*.*:ALL,GRANT" login_user: root login_password: "" login_port: "{{ mysql_port }}" login_host: localhost login_unix_socket: "{{ mysql_socket }}" check_implicit_admin: yes when: ansible_local.mysqlinfo is undefined - name: "Create custom fact directory" file: path: "/etc/ansible/facts.d" state: "directory" recurse: yes when: ansible_local.mysqlinfo is undefined - name: "record mysql info in custom fact" template: src: mysqlinfo.j2 dest: /etc/ansible/facts.d/mysqlinfo.fact mode: 0644 when: ansible_local.mysqlinfo is undefined - name: "re-run setup to use custom facts" setup: filter: ansible_local when: ansible_local.mysqlinfo is undefined - debug: msg: - "mysqlinfo is {{ ansible_local.mysqlinfo }}" when: ansible_local.mysqlinfo is defined - name: create database wordpress mysql_db: db: wordpress state: present login_user: "{{ ansible_local.mysqlinfo.mysql_superuser }}" login_password: "{{ ansible_local.mysqlinfo.mysql_superuser_password }}" login_unix_socket: "{{ mysql_socket }}" when: ansible_local.mysqlinfo is defined - name: Create database user 'wordpress' with all database privileges community.mysql.mysql_user: name: wordpress password: "{{ mysql_wordpress_password }}" login_user: "{{ ansible_local.mysqlinfo.mysql_superuser }}" login_password: "{{ ansible_local.mysqlinfo.mysql_superuser_password }}" priv: '*.*:ALL' state: present when: ansible_local.mysqlinfo is defined - name: Flush privileges mysql_query: login_db: wordpress login_user: "{{ ansible_local.mysqlinfo.mysql_superuser }}" login_password: "{{ ansible_local.mysqlinfo.mysql_superuser_password }}" login_unix_socket: "{{ mysql_socket }}" query: FLUSH PRIVILEGES # UFW Configuration - name: "UFW - Allow HTTP on port {{ http_port }}" ufw: rule: allow port: "{{ http_port }}" proto: tcp notify: - Restart Mysql tags: [ system ] handlers: - name: Restart Mysql service: name: mysql state: restarted - name: Restart Apache2 service: name: apache2 state: restarted - name: Configuring wordpress to connect to the database hosts: all gather_facts: False become: true vars: wpconfigfile: "/srv/www/wordpress/wp-config.php" tasks: - name: copy sample config to wp-config.php copy: remote_src: yes src: /srv/www/wordpress/wp-config-sample.php dest: "{{ wpconfigfile }}" owner: www-data - name: "re-run setup to use custom facts" setup: filter: ansible_local - name: set database credentials in the config file become: false command: "{{ item }}" with_items: - "sudo -u www-data sed -i s/database_name_here/wordpress/ {{ wpconfigfile }}" - "sudo -u www-data sed -i s/username_here/wordpress/ {{ wpconfigfile }}" - "sudo -u www-data sed -i s/password_here/{{ ansible_local.mysqlinfo.mysql_wordpress_password }}/ {{ wpconfigfile }}" - name: get random secret keys uri: url: https://api.wordpress.org/secret-key/1.1/salt/ return_content: yes body_format: json register: wordpress_keys - debug: var: wordpress_keys.content - name: delete existing bak file file: path: "{{ wpconfigfile }}.bak" state: absent - name: run script to remove key placeholders become_user: www-data script: chdir: /srv/www/wordpress/ cmd: replacelines.py executable: /usr/bin/python3 environment: /srv/www/wordpress/ - name: update config file become_user: www-data copy: remote_src: yes src: "{{ wpconfigfile }}.bak" dest: "{{ wpconfigfile }}" - blockinfile: path: "{{ wpconfigfile }}" marker: // {mark} ANSIBLE MANAGED BLOCK block: "{{ wordpress_keys.content }}" handlers: - name: Restart Mysql service: name: mysql state: restarted - name: Restart Apache2 service: name: apache2 state: restarted
Jinja2模板文件
apache2.j2
<VirtualHost *:80> Servername {{ ansible_hostname }} DocumentRoot "{{ wprootdir }}" <Directory "{{ wprootdir }}"> Options FollowSymLinks AllowOverride Limit Options FileInfo DirectoryIndex index.php Require all granted </Directory> <Directory "{{ wprootdir }}/wp-content"> Options FollowSymLinks Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
mysqlinfo.j2
{ "mysql_port": "{{ mysql_port }}", "mysql_socket": "{{ mysql_socket }}", "mysql_superuser": "{{ mysql_superuser }}", "mysql_superuser_password": "{{ mysql_superuser_password }}", "mysql_wordpress_password": "{{ mysql_wordpress_password }}" }
replacelines.py脚本
import re with open("wp-config.php", "r") as wpconfig, open("wp-config.php.bak", "w") as wpconfigbak: for line in wpconfig: found = re.search(r'AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|NONCE_KEY|AUTH_SALT|SECURE_AUTH_SALT|LOGGED_IN_SALT|NONCE_SALT', line.strip()); if (not found): wpconfigbak.write(line) else: continue
inventory文件
[local] localhost ansible_connection=local
执行命令
ansible-playbook -i inventory SetupWordpress.yaml
或通过仓库执行:
git clone -b WIP git@github.com:redbilledpanda/DevOpsScripts.git cd DevOpsScripts && ansible-playbook -i inventory SetupWordpress.yaml
排查方向
结合"跳过盐值生成即可正常登录"的现象,问题大概率出在盐值替换流程中:
- blockinfile标记格式错误:当前使用
// {mark} ANSIBLE MANAGED BLOCK作为标记,但wp-config.php是PHP文件,应使用PHP注释风格的标记(如/* {mark} ANSIBLE MANAGED BLOCK */),否则标记会被当作无效PHP代码,导致配置解析失败。 - replacelines.py脚本逻辑问题:脚本删除了所有包含盐值关键字的行,可能破坏了wp-config.php的代码结构(比如遗漏了盐值块的上下文注释或括号)。
- 盐值插入位置错误:blockinfile默认将内容插入到文件末尾,但WordPress要求盐值定义在特定位置(数据库配置之后、
require_once(ABSPATH . 'wp-settings.php');之前),位置错误会导致盐值不生效。
内容的提问来源于stack exchange,提问作者Skegg
相关产品推荐
相关产品推荐

