Install and configure Wildfly 24 with Ansible

In this article, we will learn how to install Wildfly Application Server with Ansible. Wildfly is an application server previously known as JBoss which is now developed and maintained by Redhat. For the demonstration, we will use Centos 8 Linux box. This tutorial will work for any yum-based package manager so this can be followed for RHEL as well.

Step 1 - Create the Directory Structure

Let's start by creating the required directory structure. This structure makes it easier to maintain our Ansible playbook and do changes dynamically.

In the root directory, create the two important files - inventory and playbook.yml

mkdir ansible-jboss
cd ansible-jboss
touch inventory
touch playbook.yml

The playbook.yml defines the instruction set and the modules to be used.

vi playbook.yml

In this playbook, we are defining the host and specifying whether we need sudo privileges. YAML files are space sensitive, notice the three lines in the beginning of the document which specify that it is a YAML file. In this tutorial, we have a wildfly-install role

---
- hosts: applicationserver
  become: true
  become_user: root
  roles:
    - wildfly-install
playbook.yml

Once we are done with this, we can move to creating roles and variables.  In Ansible, roles directive has a predefined structure . We are utilizing this to create task's and var's directory. The task directory will contain all tasks for example creating user, installing modules. The var's directory contains the variables our playbook will use.

mkdir -p roles/wildfly-install/tasks
mkdir -p roles/wildfly-install/vars
touch roles/wildfly-install/tasks/main.yml
touch roles/wildfly-install/vars/main.yml

We can execute the tree command to have a folder and file-level view.

Step 2 - Add the Target Machine to the Inventory File

The default location for inventory is /etc/ansible/hosts. We can specify a different inventory file at the command line using the -i <path> option.

The server details are listed under a group named applicationserver, which will be later referenced in our ansible-playbook. we have created a user named centos which is in the sudoers list and can execute commands with sudo privileges.

vi inventory 
[applicationserver]
13.233.184.10 ansible_ssh_pass=Welcome@1122 ansible_ssh_user=centos

Step 3 - Add the Wildfly URL and Server URL in Variable File

Navigate to roles\wildfly-install\vars\main.yml. We need to add the Wildfly package download url, IP address and version details here.

---
https_uri: https://download.jboss.org/wildfly/24.0.1.Final/wildfly-24.0.1.Final.zip
wildfly_user: wildfly
server_url: enteryouriphere
wildfly_version: wildfly-24.0.1.Final
# change the https_url for latest version of wildfly , currently it is 24.X.X version. add your server url and the wildfly_version file 
main.yml
Note - as new versions of Wildfly are released we need to make changes accordingly to this main.yml file.

At the time of writing this guide, Wildfly's latest version is 24, the download link to the latest version can be found on their page: https://www.wildfly.org/downloads/

Based on the version you want to install, copy the link from their official website and update it in the above main.yml file, for https_uri variable.

As a recommended practice, this playbook will create a user named wildfly, this is specified under the wildfly_user key.

The wildfly_version key is used to uniquely identify the version that is extracted once you download the zip file from the website.

For example , when we download the zip file from the https_uri, and extract it, the folder present is: "wildfly-24.0.1.Final" , we need to mention the same folder name in our wildfly_version key.

Step 4 - Create tasks main.yml Playbook

Navigate to roles \wildfly-install\tasks\main.yml, and add the following code

This playboook utilizes different modules in ansible to perform our tasks on target machine, we will start off with creating the wildfly user and install java as it is a prerequisite.

---
- block:
    - name: create user for wildfly server
      user:
        name: "{{ wildfly_user }}"
        shell: /bin/false
        comment: "Wildfly User"
    
    - name: unzip and install java
      yum:
        name: 
          - unzip
          - java-1.8.0-openjdk
        state: latest
      
    - name: check if java is installed
      shell:
        cmd: rpm -q java-1.8.0-openjdk
      register: rpm_check
      failed_when: rpm_check.rc == 1
main.yml

Step 5 - Check for Firewalld

In this step, we will identify if firewalld is installed in your target server, if so we need to disable it. If firewalld is present in your server we can add this line of code to the task's main.yml

First verify if firewalld is enabled

$ systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2021-08-07 10:36:19 UTC; 2min 50s ago
     Docs: man:firewalld(1)
 Main PID: 8134 (firewalld)
   CGroup: /system.slice/firewalld.service
           └─8134 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid

Aug 07 10:36:19 ip-172-31-14-230.ap-south-1.compute.internal systemd[1]: Starting firewalld - dynamic firewall daemon...
Aug 07 10:36:19 ip-172-31-14-230.ap-south-1.compute.internal systemd[1]: Started firewalld - dynamic firewall daemon.
To comment in yaml - just add # for every line or you can

If Firewalld is enabled and running, add these two tasks.


    - name: check if firewall is enabled
      shell:
        cmd: rpm -q firewalld
      register: rpm_check_firewall

    - name: Disable firewall
      systemd: 
        name: firewalld
        state: stopped
        enabled: false
      when:
        - rpm_check_firewall.rc == 0 

Step 6 - Download Wildfly Zip File

In this step, we will download the zip file, extract it, modify permissions and edit the standalone.xml which contains important configurations for the server. Add this code to main.yml

    - name: Download wildfly 
      unarchive:
        src: "{{ https_uri }}"
        dest: /
        remote_src: yes
      

    - name: create link for /opt/wildfly
      file:
        src: /{{wildfly_version}}  
        dest: /opt/wildfly
        state: link
    - file: 
        path: /opt/widfly
        owner: wildfly
        group: wildfly
        recurse: yes

    - name: change owner to wildfly user
      file:
        path: /{{wildfly_version}}
        owner: wildfly
        group: wildfly
        recurse: yes

    - name: edit standalone.xml to run on server ip adress
      replace:
        path: /opt/wildfly/standalone/configuration/standalone.xml
        backup: yes
        regexp: '127\.0\.0\.1'
        replace: "{{ ansible_default_ipv4.address }}"

The last step, edit standalone.xml to run on server ip adress, uses regular expression to identify and replace the default setting to run on localhost to run wildfly server on our target's IP address, the target IP address is fetched from Ansible's ansible_default_ipv4.address

Step 7 -  Configure Username and Password for the Wildfly Server

In this step we configure the initial username and password for our Wildfly server, here we are running the add-user.sh script with our username and password arguments.

This code configures default login with username:wildfly and password as Welcome@1122, feel free to change accordingly.

Add this code snippet,

   - name: add user and password
      shell:
        cmd: JBOSS_HOME='/opt/wildfly' /bin/bash -c '/opt/wildfly/bin/add-user.sh -u wildfly -p Welcome@1122'
      register: wildfly_user
    - debug:
        msg: "{{ wildfly_user }}"

Step 8 - Enable Wildfly as a Service

In this step, we will add wildfly to init.d to enable it to run as a service and modify some parameters

- name: run wildfly server as a service
      copy:
        src: "{{ item.src }}" 
        dest: "{{ item.dest }}"
        owner: wildfly
        mode: "0744"
        remote_src: yes
      with_items:
        - { src: /opt/wildfly/docs/contrib/scripts/init.d/wildfly-init-redhat.sh , dest: /etc/init.d/wildfly } 
        - { src: /opt/wildfly/docs/contrib/scripts/init.d/wildfly.conf , dest: /etc/default } 

    - name: change service file
      replace:
        path: /etc/default/wildfly.conf
        regexp: "{{ item.regexp }}"
        replace: "{{ item.replace }}"
        backup: yes
      with_items:  
          - { regexp: '^# JBOSS_HOME\="\/opt\/wildfly"' , replace: 'JBOSS_HOME="/opt/wildfly"' }
          - { regexp: '^# JBOSS_USER\=wildfly' , replace: 'JBOSS_USER=wildfly' }
          - { regexp: '^# JBOSS_MODE\=standalone', replace: 'JBOSS_MODE=standalone' } 
          - { regexp: '^# JBOSS_CONFIG\=standalone.xml', replace: 'JBOSS_CONFIG=standalone.xml' }
          - { regexp: '^# STARTUP_WAIT\=60', replace: 'STARTUP_WAIT=60' } 
          - { regexp: '^# SHUTDOWN_WAIT\=60', replace: 'SHUTDOWN_WAIT=60' } 

    - name: add wildfly to init.d
      command: "{{ item }}"
      with_items:
        - /usr/sbin/chkconfig --add /etc/init.d/wildfly
        - /usr/sbin/chkconfig --level 2345 wildfly on
        - systemctl daemon-reload

    - name: start wildfly
      systemd: 
        name: wildfly
        state: started
        enabled: true

Step 9 - Check if Wildfly Is Running

In this step, we are utilizing the Ansible uri module to make a request to our newly created server and see if it is up and running based on the response, we also print the status code and debug message.

- name: check if server is up on 8080
      uri:
        url: http://{{  server_url }}:8080
        return_content: true
      ignore_errors: yes
      register: status_8080
  
    - debug:
        msg: "{{ status_8080 }}"

Step 10 - Run the Ansible Playbook

We have finally added all the modules required to install Wildfly in our main.yaml file. Now we can start running the playbook to complete the Wildfly installation.

We can use the following command to run the ansible-playbook from the project root folder, make sure the controller machine has ansible installed at this point

ansible-playbook -i inventory playbook.yml -kK

-k argument in the above command is used to ask for a connection password, this corresponds to the user mentioned in the inventory file

-K argument is used to ask for password for privileged escalation which is required by certain modules in the playbook.

$ ansible-playbook -i inventory playbook.yml -kK
[WARNING]: log file at /var/log/ansible.log is not writeable and we cannot create it, aborting

SSH password: 
BECOME password[defaults to SSH password]: 

Enter the password accordingly to the prompt on the screen and wait till all modules are completed, the debug task gives us the url handy where we can access the wildfly server in "url" tag in the output message.

TASK [wildfly-install : debug] ************************************************************************************
ok: [13.233.13.7] => {
    "msg": {
        "accept_ranges": "bytes",
        "changed": false,
        "connection": "close",
        "content": "<!DOCTYPE html>\n\n<html>\n<head>\n    <!-- proper charset -->\n    <meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=EmulateIE8\" />\n\n    <title>Welcome to WildFly</title>\n    <link rel=\"shortcut icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n    <link rel=\"StyleSheet\" href=\"wildfly.css\" type=\"text/css\">\n</head>\n\n<body>\n<div class=\"wrapper\">\n    <div class=\"content\">\n        <div class=\"logo\">\n                <img src=\"wildfly_logo.png\" alt=\"WildFly\" border=\"0\" />\n        </div>\n        <h1>Welcome to WildFly</h1>\n\n        <h3>Your WildFly instance is running.</h3>\n\n        <p><a href=\"https://docs.wildfly.org\">Documentation</a> | <a href=\"https://github.com/wildfly/quickstart\">Quickstarts</a> | <a href=\"/console\">Administration\n            Console</a> </p>\n\n        <p><a href=\"https://wildfly.org\">WildFly Project</a> |\n            <a href=\"https://community.jboss.org/en/wildfly\">User Forum</a> |\n            <a href=\"https://issues.jboss.org/browse/WFLY\">Report an issue</a></p>\n        <p class=\"logos\"><a href=\"https://www.jboss.org\"><img src=\"jbosscommunity_logo_hori_white.png\" alt=\"JBoss and JBoss Community\" width=\n                \"195\" height=\"37\" border=\"0\"></a></p>\n\n        <p class=\"note\">To replace this page simply deploy your own war with / as its context path.<br />\n            To disable it, remove the \"welcome-content\" handler for location / in the undertow subsystem.</p>\n    </div>\n</div>\n</body>\n</html>\n",
        "content_length": "1504",
        "content_type": "text/html",
        "cookies": {},
        "cookies_string": "",
        "date": "Sat, 07 Aug 2021 10:32:24 GMT",
        "elapsed": 0,
        "failed": false,
        "last_modified": "Tue, 27 Jul 2021 10:03:32 GMT",
        "msg": "OK (1504 bytes)",
        "redirected": false,
        "status": 200,
        "url": "http://13.233.13.7:8080"
    }
}

Step 11 - Confirm Wildfly Server Is Installed and Running

Once the installation is complete,  we can navigate to http://yourserverurl:8080 to see the ansible landing page and the console. We need to make sure both ports are open and listening on the server

The Administration console can be accessed at  http://yourserverurl:9990

As you can see from the console, the latest version of wildfly server is installed.

You can also find the GitHub project repository of debugfactor for reference or clone the below repository

https://github.com/debugfactor/ansible-jboss

Common issue while installing Wildfly through ansible

  1. Missing sudo password

When we run our playbook, if we get missing sudo password we need to make sure that our inventory file has sudo password specified. Alternatively we can bypass that by using -kK argument in ansible-playbook command. This issue also occurs if you are not specifying -i inventory param in ansible-playbook command

If you have root access to the server, the issue can be solved by adding the user through which ansible playbook is installing in sudoers list.

Run sudo visudo, add this entry.

youruser ALL=(ALL) NOPASSWD:ALL

2. Ansible playbook fails in the gathering facts

This issue occurs when the incorrect user is specified in the inventory file, as mentioned earlier in this tutorial we need to make sure the user is in sudoers list as a best practice to avoid such issues we can always use - ansible -m ping all command before we execute the playbook, the ping command should return pong if all is good

3. Ansible playbook fails at Firewalld step

If the playbook fails at Firewalld module, the target server does not have Firewalld if so we can comment the two modules as mentioned in step 5 or we can install firewalld and run the command systemctl disable firewalld

Conclusion

In this post, we have covered how to install Wildfly with Ansible. A step-by-step approach was taken with creating the file structure to configuring username and password for Wildfly. This guide can be used to install Wildfly application server on RHEL, Centos, and Amazon Linux.

Mohammed Shahbaaz Shareef

Mohammed Shahbaaz Shareef

DevOps Practitioner with interest in Automation and Modernization