Recently, I have begun to experiment with using Ansible to automate some of the tasks related to my website hosting and building tasks.
I have only just begun to dig in, but I am really digging the process and can see how using it will help save a lot of time in the future. There is, of course, an initial time cost, especially as I am learning, but over time, I think that cost will be worth it. When you compare how long it would take(for me anyway) to create a bash script that does everything a 30-40 line Ansible playbook does, it is hands down a better system. And, even if I were to get the shell script working, it wouldn’t handle errors or templating as well as Ansible does. So, going forward, I can really see myself using this and automating some of my development and server management tasks.
As one of my first playbooks, I setup a Ansible task to create a new hosting account, configure HTTPD, as well as other hosting related services, download a new copy of wordpress, and configure the wp-config.php file.
While I’m not going to share the tasks for configuring my hosting servers, as they are specific to my server setup, I will share a basic playbook for generating a WordPress configuration file, securely setting the various hash and passwords securely using randomly generated strings. I’m sure there is a better way to do this, but this seems to work quite well for my purposes.
This assummes some basic knowledge of Ansible, specifically how to setup a working playbook, utilizing an ansible.cfg and hosts file. If you haven’t gotten this far yet, you should probably start with a hello world playbook. I have been working through some of the chapters in the O’Reily Ansible Up & Running book and think it is a good starting place for learning Ansible.
Your hosts file might look something like the below, with of course the XXX being replaced with your remote server’s IP Address and Port
webserver ansible_host=XXX.XXX.XX.XXX ansible_port=XXXX
Your ansible.cfg might look something like the following, where ‘remote_user_name’ is the shell username you use to connect to your remote server:
[defaults] inventory = hosts remote_user = remote_user_name
The playbook used for generating the wp-config.php file is below:
- name: Create WordPress WP-CONFIG.PHP File hosts: webserver become: True vars: user_name: "shell_user_name" db_name: "wordpress_db_name" db_user: "wordpress_db_user" db_password: "{{ lookup('password', 'tmp/pass1.txt length=45 chars=ascii_letters,digits,!,,,,@,#,$,%,^,&,*,(,),_,-,:,.,?,:.;,|,},{,],[') }}" AUTH_KEY: "{{ lookup('password', 'tmp/pass2.txt length=60 chars=ascii_letters,digits,!,,,,@,#,$,%,^,&,*,(,),_,-,:,.,?,:.;,|,},{,],[') }}" SECURE_AUTH_KEY: "{{ lookup('password', 'tmp/pass3.txt length=60 chars=ascii_letters,digits,!,,,,@,#,$,%,^,&,*,(,),_,-,:,.,?,:.;,|,},{,],[') }}" LOGGED_IN_KEY: "{{ lookup('password', 'tmp/pass4.txt length=60 chars=ascii_letters,digits,!,,,,@,#,$,%,^,&,*,(,),_,-,:,.,?,:.;,|,},{,],[') }}" NONCE_KEY: "{{ lookup('password', 'tmp/pass5.txt length=60 chars=ascii_letters,digits,!,,,,@,#,$,%,^,&,*,(,),_,-,:,.,?,:.;,|,},{,],[') }}" AUTH_SALT: "{{ lookup('password', 'tmp/pass6.txt length=60 chars=ascii_letters,digits,!,,,,@,#,$,%,^,&,*,(,),_,-,:,.,?,:.;,|,},{,],[') }}" SECURE_AUTH_SALT: "{{ lookup('password', 'tmp/pass7.txt length=60 chars=ascii_letters,digits,!,,,,@,#,$,%,^,&,*,(,),_,-,:,.,?,:.;,|,},{,],[') }}" LOGGED_IN_SALT: "{{ lookup('password', 'tmp/pass8.txt length=60 chars=ascii_letters,digits,!,,,,@,#,$,%,^,&,*,(,),_,-,:,.,?,:.;,|,},{,],[') }}" NONCE_SALT: "{{ lookup('password', 'tmp/pass9.txt length=60 chars=ascii_letters,digits,!,,,,@,#,$,%,^,&,*,(,),_,-,:,.,?,:.;,|,},{,],[') }}" tasks: - name: Create wp-config.php file template: src: templates/wp-config.php.j2 dest: "/home/{{ user_name }}/public_html/wp-config.php" owner: "{{ user_name }}" group: "{{ user_name }}" - name: Delete Temp Pass Files become: False connection: local file: path: "{{ item }}" state: absent loop: - "tmp/pass1.txt" - "tmp/pass2.txt" - "tmp/pass3.txt" - "tmp/pass4.txt" - "tmp/pass5.txt" - "tmp/pass6.txt" - "tmp/pass7.txt" - "tmp/pass8.txt" - "tmp/pass9.txt"
vars
There are some vars that you will need to setup, specifically user_name, db_name, and db_user.
This assumes your web root is located at /home/{{ user_name }}/public_html/, but if that is not the case, you may need to adjust the Create wp-config.php file task to use the correct directly of your worpdress installation.
Passwords are generated randomly using ansible’s lookup feature. I had initially used /dev/null, but the passwords were the same for each variable, so I used temporary files, which are deleted afterwards.
If you wanted to save a copy of the db_password, you could change that line to something like the below and it would not be deleted:
db_password: "{{ lookup('password', 'credentials/{{ db_user }}.txt length=45 chars=ascii_letters,digits,!,,,,@,#,$,%,^,&,*,(,),_,-,:,.,?,:.;,|,},{,],[') }}"
Rather than using ansible’s ascii_letters,digits,punctuation character set, I pass my own string of special characters. This is because otherwise, single quotes, double quotes, or escape characters(\) might be used, which can throw off PHP files.
You will notice the above references a template file called templates/wp-config.php.j2 in the Create wp-config.php file task. This is just a copy of the default wordpress file, with the variables referenced in the vars section added, as so:
[...] /** The name of the database for WordPress */ define('DB_NAME', '{{ db_name }}'); /** MySQL database username */ define('DB_USER', '{{ db_user }}'); /** MySQL database password */ define('DB_PASSWORD', '{{ db_password }}'); [...] define('AUTH_KEY', '{{ AUTH_KEY }}'); define('SECURE_AUTH_KEY', '{{ SECURE_AUTH_KEY }}'); define('LOGGED_IN_KEY', '{{ LOGGED_IN_KEY }}'); define('NONCE_KEY', '{{ NONCE_KEY }}'); define('AUTH_SALT', '{{ AUTH_SALT }}'); define('SECURE_AUTH_SALT', '{{ SECURE_AUTH_SALT }}'); define('LOGGED_IN_SALT', '{{ LOGGED_IN_SALT }}'); define('NONCE_SALT', '{{ NONCE_SALT }}');
After you have the playbook and template created, you can run it as follows. I’m using become to switch to root while preforming the tasks on the web server, as otherwise I would need to be logging in as the web-server user.
So, calling the playbook looks something like this for me:
ansible-playbook create_wpconfig.yml -K --become-method=su
I think there may be a better way to generate a password, rather than using lookup. My goal was to avoid using shell commands, like < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo;, but it is kind of clunky. The one advantage of using the lookup is if you wanted to save the db credentials in a file for later reference. Of course, if you were to do that, you would want to save it as a secret, so it is not stored in plain text.
My next workbook is going to be to create the wordpress database and user, so when I do that, I may update this to save the password.
Add a Comment