All Products
Search
Document Center

Resource Orchestration Service:Deploy a LNMP environment by using Ansible ali_ros_stack

Last Updated:Feb 28, 2026

Use the Ansible ali_ros_stack module to deploy a LNMP (Linux, NGINX, MySQL, PHP) environment through Resource Orchestration Service (ROS) API operations. The Ansible playbook references a ROS template that provisions an Elastic Compute Service (ECS) instance with NGINX, MariaDB, and PHP installed and configured.

Prerequisites

Before you begin, make sure you have:

  • Ansible installed and configured on a Linux system by using pip3

  • A valid Alibaba Cloud AccessKey pair configured for Ansible

  • Basic familiarity with Ansible playbooks and ROS templates

How it works

The deployment uses two files:

FileTypePurpose
create_lnmp.ymlAnsible playbookDefines the automation task and passes parameters to the ROS template
create_lnmp_instance.jsonROS templateDefines the cloud resources (VPC, vSwitch, security group, and ECS instance) and software installation steps

When you run the playbook, Ansible calls the ROS API to create a stack based on the template. The stack provisions all required infrastructure and installs the LNMP software on the ECS instance.

Step 1: Create the Ansible playbook

  1. Create a file named create_lnmp.yml.

       vi create_lnmp.yml
  2. Add the following content to create_lnmp.yml. The following table describes the template parameters.

    Note For more information about the ali_ros_stack module parameters, see Parameters.
    ParameterDescriptionConstraints
    ZoneIdThe zone where the ECS instance is created.Must be a valid ECS availability zone ID.
    ImageIdThe image used to create the ECS instance. Only CentOS 7 is supported.Must be a valid CentOS 7 image ID.
    InstancePasswordThe login password for the ECS instance.8 to 30 characters. Must contain at least three of the following: uppercase letters, lowercase letters, digits, and special characters.
    SystemDiskCategoryThe system disk type.Valid values: cloud_ssd (standard SSD), cloud_efficiency (ultra disk). Default: cloud_ssd.
    InstanceTypeThe ECS instance type.Default: ecs.c5.large. Check the Instance families page to verify availability in your zone.
    DBNameThe name of the MySQL database.1 to 64 characters. Must start with a letter. Can contain letters, digits, periods (.), underscores (\_), and hyphens (-). Default: MyDatabase.
    DBUserThe username for MySQL database access.Up to 16 characters. Must start with a letter. Can contain lowercase letters, digits, and underscores (\_). Default: DefaultUser.
    DBRootPasswordThe root password for MySQL.6 to 32 characters. Can contain letters, digits, and underscores (\_).
    DBPasswordThe password for the MySQL database user.6 to 32 characters. Can contain letters, digits, and underscores (\_).
    NginxDownloadUrlThe download URL for the NGINX RPM package.Default: http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm.
       - hosts: localhost
         remote_user: root
         tasks:
           - name: Create LNMP Instance
             ali_ros_stack:
               state: present
               stack_name: create_lnmp_instance
               template: create_lnmp_instance.json     # Path to the ROS template file
               timeout_in_minutes: 60                   # Maximum time to wait for stack creation
               template_parameters:
                 ZoneId: <zone-id>                      # Example: cn-beijing-g
                 ImageId: <image-id>                    # Example: centos_7_03_64_20G_alibase_2017****.vhd
                 InstancePassword: <instance-password>  # ECS instance login password
                 SystemDiskCategory: cloud_ssd          # Standard SSD
                 InstanceType: ecs.c5.large             # ECS instance type
                 DBName: MyDatabase                     # MySQL database name
                 DBUser: DefaultUser                    # MySQL database username
                 DBRootPassword: <db-root-password>     # MySQL root password
                 DBPassword: <db-password>              # MySQL user password
                 NginxDownloadUrl: http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
  3. Save the file and exit the text editor.

Step 2: Create the ROS template

  1. Create a file named create_lnmp_instance.json.

       vi create_lnmp_instance.json
  2. Add the following ROS template content to create_lnmp_instance.json. The template creates the following resources: The ECS instance UserData script installs and configures the following software:

    • NGINX (downloaded and installed via yum)

    • PHP and PHP-FPM with extensions (php-mysql, php-gd, php-ldap, php-odbc, php-pear, php-xml, php-xmlrpc, php-mbstring, php-bcmath, php-mhash, php-mcrypt, and libjpeg)

    • MariaDB (a MySQL-compatible database server)

    • A test.php page that verifies the MySQL connection and displays PHP configuration

    Warning

    The security group in this template opens all ports to all IP addresses (0.0.0.0/0). This configuration is intended for testing purposes only. For production environments, restrict security group rules to allow only the ports and source IP addresses that your application requires.

    ResourceTypeDetails
    VPCALIYUN::ECS::VPCCIDR block: 192.168.0.0/16
    vSwitchALIYUN::ECS::VSwitchCIDR block: 192.168.1.0/24
    Security groupALIYUN::ECS::SecurityGroupAllows all inbound and outbound traffic
    ECS instanceALIYUN::ECS::InstanceI/O optimized, maximum outbound Internet bandwidth: 80 Mbps
    Wait conditionALIYUN::ROS::WaitConditionTimeout: 1,800 seconds. Confirms that software installation is complete.
       {
         "Description": "Deploy LNMP(Linux+Nginx+MySQL+PHP) stack on 1 ECS instance. *** WARNING *** Only support CentOS-7.",
         "Parameters": {
           "NginxDownloadUrl": {
             "Type": "String",
             "Description": {
               "en": "The download path of nginx-*.rpm",
               "en-us": "The download path of nginx-*.rpm."
             },
             "Label": "Nginx Download Url",
             "Default": "http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm"
           },
           "DBPassword": {
             "NoEcho": true,
             "Type": "String",
             "Description": {
               "en": "The MySQL password, consisting of letters, numbers, and underline(_), 6 to 32 characters in length",
               "en-us": "The MySQL password, consisting of letters, numbers, and underline(_), 6 to 32 characters in length"
             },
             "Label": "DB Password",
             "ConstraintDescription": "Consisting of letters, numbers, and underline(_), 6 to 32 characters in length",
             "MinLength": 6,
             "MaxLength": 32
           },
           "ZoneId": {
             "Type": "String",
             "AssociationProperty": "ALIYUN::ECS::Instance:ZoneId",
             "Description": {
               "en": "ECS Available Zone ID,</font><a href='https://www.alibabacloud.com/help/doc-detail/123712.html' target='_blank'><b> View region and zone info</b><font color='blue'></a>",
               "en-us": "ECS Available Zone ID,</font><a href='https://www.alibabacloud.com/help/doc-detail/123712.htm?spm=a2c63.l28256.b99.10.19347453Kki9VF' target='_blank'><b> Regions and zones</b><font color='blue'></a>"
             },
             "Label": "Available Zone ID"
           },
           "ImageId": {
             "Type": "String",
             "Description": {
               "en": "Image ID, represents the image resource to startup one ECS instance, <font><a href='https://www.alibabacloud.com/help/doc-detail/112977.html' target='_blank'><b>View image resources</b></font color='blue'></a>",
               "en-us": "Image ID, represents the image resource to startup one ECS instance, <font><a href='https://www.alibabacloud.com/help/doc-detail/112977.html' target='_blank'><b>Find an image</b></font color='blue'></a>"
             },
             "Label": "Image ID",
             "Default": "cent****"
           },
           "DBName": {
             "Type": "String",
             "Description": {
               "en": "MySQL database name, [1, 64] English or Chinese characters, must start with a letter or Chinese in size, can contain numbers, '_' or '.', '-'.",
               "en-us": "The name of the MySQL database. It must be 1 to 64 characters in length and can contain letters, digits, periods (.), underscores (_), and hyphens (-). It must start with a letter."
             },
             "Label": "DB Name",
             "ConstraintDescription": "Must begin with a letter and contain only alphanumeric characters.",
             "MinLength": 1,
             "MaxLength": 64,
             "Default": "MyDatabase"
           },
           "DBUser": {
             "Type": "String",
             "Description": {
               "en": "Username for MySQL database access. It consists of lowercase letters, numbers and underscores (_), and begins with a letter. Not longer than 16 characters.",
               "en-us": "The username used to access the MySQL database. The name can be up to 16 characters in length and can contain letters, digits and underscores (_). It must start with a letter."
             },
             "Label": "DB Username",
             "ConstraintDescription": "Must begin with a letter and contain only alphanumeric characters.",
             "MinLength": 1,
             "MaxLength": 16,
             "Default": "DefaultUser"
           },
           "DBRootPassword": {
             "NoEcho": true,
             "Type": "String",
             "Description": {
               "en": "Root password for MySQL, consisting of letters, numbers, and underline(_), 6 to 32 characters in length",
               "en-us": "The root password used to access the MySQL database. The password can be 6-32 characters in length and can contain letters, digits and underscores (_)."
             },
             "Label": "DB Root Password",
             "ConstraintDescription": "Consisting of letters, numbers, and underline(_), 6 to 32 characters in length",
             "MinLength": 6,
             "MaxLength": 32
           },
           "InstanceType": {
             "Type": "String",
             "Description": {
               "en": "The ECS instance type, go to the product console to ensure the current instance is available, <font><a href='https://www.alibabacloud.com/help/doc-detail/25378.html' target='_blank'><b>View instance types</b></font color='blue'></a>",
               "en-us": "The ECS instance type, go to the product console to ensure the current instance is available, <font><a href='https://www.alibabacloud.com/help/doc-detail/25378.html' target='_blank'><b>Instance families</b></font color='blue'></a>"
             },
             "Label": "Instance Type",
             "Default": "ecs.c5.large"
           },
           "SystemDiskCategory": {
             "Type": "String",
             "Description": {
               "en": "System disk category: standard SSD (cloud_ssd) or ultra disk (cloud_efficiency)",
               "en-us": "The type of the system disk, which can be ultra disk (cloud_efficiency) or standard SSD (cloud_ssd)."
             },
             "AllowedValues": [
               "cloud_efficiency",
               "cloud_ssd"
             ],
             "Label": "System Disk Category",
             "Default": "cloud_ssd"
           },
           "InstancePassword": {
             "NoEcho": true,
             "Type": "String",
             "Description": {
               "en": "The 8-30 long login password of instance, consists of the uppercase, lowercase letter and number. <br> special characters include ( ) ` ~ ! @ # $ % ^ & * _ - + = | { } [ ] : ; ' < > , . ? / ",
               "en-us": "It must be 8 to 30 characters in length and contain at least three of the following character types: uppercase letters, lowercase letters, digits, and special characters. Special characters include ( ) ` ~ ! @ # $ % ^ & * _ - + = | { } [ ] : ; ' < > , . ? /"
             },
             "AllowedPattern": "[0-9A-Za-z\\_\\-&:;'<>,=%`~! @#\\(\\)\\$\\^\\*\\+\\|\\{\\}\\[\\]\\. \\? \\/]+$",
             "Label": "Instance Password",
             "ConstraintDescription": "Length 8-30, must contain upper case letters, lower case letters, Numbers, special symbols three; special characters include: ( ) ` ~ ! @ # $ % ^ & * _ - + = | { } [ ] : ; ' < > , . ? /",
             "MinLength": "8",
             "MaxLength": "30"
           }
         },
         "ROSTemplateFormatVersion": "2015-09-01",
         "Metadata": {
           "ALIYUN::ROS::Interface": {
             "ParameterGroups": [
               {
                 "Parameters": [
                   "ZoneId",
                   "ImageId",
                   "InstanceType",
                   "SystemDiskCategory",
                   "InstancePassword"
                 ],
                 "Label": {
                   "default": "ECS"
                 }
               },
               {
                 "Parameters": [
                   "DBName",
                   "DBUser",
                   "DBPassword",
                   "DBRootPassword"
                 ],
                 "Label": {
                   "default": "DATABASE"
                 }
               },
               {
                 "Parameters": [
                   "NginxDownloadUrl"
                 ],
                 "Label": {
                   "default": "Nginx"
                 }
               }
             ],
             "TemplateTags": [
               "Deploy LNMP(Linux+Nginx+MySQL+PHP) stack on 1 ECS instance."
             ]
           }
         },
         "Outputs": {
           "NginxWebsiteURL": {
             "Description": "URL for newly created Nginx home page.",
             "Value": {
               "Fn::Join": [
                 "",
                 [
                   "http://",
                   {
                     "Fn::GetAtt": [
                       "WebServer",
                       "PublicIp"
                     ]
                   },
                   ":80/test.php"
                 ]
               ]
             }
           }
         },
         "Resources": {
           "VSwitch": {
             "Type": "ALIYUN::ECS::VSwitch",
             "Properties": {
               "VpcId": {
                 "Fn::GetAtt": [
                   "Vpc",
                   "VpcId"
                 ]
               },
               "ZoneId": {
                 "Ref": "ZoneId"
               },
               "CidrBlock": "192.168.1.0/24"
             }
           },
           "WebServerConditionHandle": {
             "Type": "ALIYUN::ROS::WaitConditionHandle"
           },
           "WebServer": {
             "Type": "ALIYUN::ECS::Instance",
             "Properties": {
               "InternetMaxBandwidthOut": 80,
               "IoOptimized": "optimized",
               "VpcId": {
                 "Fn::GetAtt": [
                   "Vpc",
                   "VpcId"
                 ]
               },
               "UserData": {
                 "Fn::Replace": [
                   {
                     "ros-notify": {
                       "Fn::GetAtt": [
                         "WebServerConditionHandle",
                         "CurlCli"
                       ]
                     }
                   },
                   {
                     "Fn::Join": [
                       "",
                       [
                         "#! /bin/bash \n",
                         "NginxUrl=",
                         {
                           "Ref": "NginxDownloadUrl"
                         },
                         "\n",
                         "dbname=",
                         {
                           "Ref": "DBName"
                         },
                         "\n",
                         "dbuser=",
                         {
                           "Ref": "DBUser"
                         },
                         "\n",
                         "dbpassword=",
                         {
                           "Ref": "DBPassword"
                         },
                         "\n",
                         "dbrootpassword=",
                         {
                           "Ref": "DBRootPassword"
                         },
                         "\n",
                         "export HOME=/root \n",
                         "export HOSTNAME=`hostname` \n",
                         "systemctl stop firewalld.service \n",
                         "systemctl disable firewalld.service \n",
                         "sed -i 's/^SELINUX=/# SELINUX=/' /etc/selinux/config \n",
                         "sed -i '/# SELINUX=/a SELINUX=disabled' /etc/selinux/config \n",
                         "setenforce 0 \n",
                         "yum install yum-priorities -y \n",
                         "yum -y install aria2 \n",
                         "aria2c $NginxUrl \n",
                         "rpm -ivh nginx-*.rpm \n",
                         "yum -y install nginx \n",
                         "systemctl start nginx.service \n",
                         "systemctl enable nginx.service \n",
                         "yum -y install php-fpm \n",
                         "systemctl start php-fpm.service \n",
                         "systemctl enable php-fpm.service \n",
                         "sed -i '/FastCGI/,/htaccess/s/    #/    /' /etc/nginx/conf.d/default.conf \n",
                         "sed -i '/FastCGI/s/^    /    #/' /etc/nginx/conf.d/default.conf \n",
                         "sed -i '/htaccess/s/^    /    #/' /etc/nginx/conf.d/default.conf \n",
                         "sed -i '/SCRIPT_FILENAME/s/\\/scripts/\\/usr\\/share\\/nginx\\/html\\//' /etc/nginx/conf.d/default.conf \n",
                         "yum -y install mariadb mariadb-server \n",
                         "systemctl start mariadb.service \n",
                         "systemctl enable mariadb.service \n",
                         "yum -y install php php-mysql php-gd libjpeg* php-ldap php-odbc php-pear php-xml php-xmlrpc php-mbstring php-bcmath php-mhash php-mcrypt \n",
                         "MDSRING=`find / -name mbstring.so` \n",
                         "echo extension=$MDSRING >> /etc/php.ini \n",
                         "systemctl restart mariadb.service \n",
                         "mysqladmin -u root password \"$dbrootpassword\" \n",
                         "$(mysql $dbname -u root --password=\"$dbrootpassword\" >/dev/null 2>&1 </dev/null); (( $?!=0 )) \n",
                         "echo CREATE DATABASE $dbname \\; > /tmp/setup.mysql \n",
                         "echo GRANT ALL ON $dbname. * TO \"$dbuser\"@\"localhost\" IDENTIFIED BY \"'$dbpassword'\" \\; >> /tmp/setup.mysql \n",
                         "mysql -u root --password=\"$dbrootpassword\" < /tmp/setup.mysql \n",
                         "$(mysql $dbname -u root --password=\"$dbrootpassword\" >/dev/null 2>&1 </dev/null); (( $?!=0 )) \n",
                         "cd /root \n",
                         "systemctl restart php-fpm.service \n",
                         "systemctl restart nginx.service \n",
                         "echo \\<? php >  /usr/share/nginx/html/test.php \n",
                         "echo \\$conn=mysql_connect\\(\"'127.0.0.1'\", \"'$dbuser'\", \"'$dbpassword'\"\\)\\; >>  /usr/share/nginx/html/test.php \n",
                         "echo if \\(\\$conn\\){ >>  /usr/share/nginx/html/test.php \n",
                         "echo   echo \\\"LNMP platform connect to mysql is successful\\! \\\"\\; >>  /usr/share/nginx/html/test.php \n",
                         "echo   }else{  >>  /usr/share/nginx/html/test.php \n",
                         "echo echo \\\"LNMP platform connect to mysql is failed\\! \\\"\\;  >>  /usr/share/nginx/html/test.php \n",
                         "echo }  >>  /usr/share/nginx/html/test.php \n",
                         "echo  phpinfo\\(\\)\\;  >>  /usr/share/nginx/html/test.php \n",
                         "echo \\? \\>  >>  /usr/share/nginx/html/test.php \n",
                         "ros-notify -d '{\"data\" : \"Install LNMP stack.\"}'\n"
                       ]
                     ]
                   }
                 ]
               },
               "SecurityGroupId": {
                 "Ref": "SecurityGroup"
               },
               "VSwitchId": {
                 "Ref": "VSwitch"
               },
               "ImageId": {
                 "Ref": "ImageId"
               },
               "InstanceType": {
                 "Ref": "InstanceType"
               },
               "SystemDiskCategory": {
                 "Ref": "SystemDiskCategory"
               },
               "Password": {
                 "Ref": "InstancePassword"
               }
             }
           },
           "WebServerWaitCondition": {
             "Type": "ALIYUN::ROS::WaitCondition",
             "DependsOn": "WebServer",
             "Properties": {
               "Timeout": 1800,
               "Count": 1,
               "Handle": {
                 "Ref": "WebServerConditionHandle"
               }
             }
           },
           "Vpc": {
             "Type": "ALIYUN::ECS::VPC",
             "Properties": {
               "CidrBlock": "192.168.0.0/16"
             }
           },
           "SecurityGroup": {
             "Type": "ALIYUN::ECS::SecurityGroup",
             "Properties": {
               "VpcId": {
                 "Ref": "Vpc"
               },
               "SecurityGroupIngress": [
                 {
                   "PortRange": "-1/-1",
                   "Priority": 1,
                   "SourceCidrIp": "0.0.0.0/0",
                   "IpProtocol": "all",
                   "NicType": "intranet"
                 }
               ],
               "SecurityGroupEgress": [
                 {
                   "PortRange": "-1/-1",
                   "Priority": 1,
                   "IpProtocol": "all",
                   "DestCidrIp": "0.0.0.0/0",
                   "NicType": "intranet"
                 }
               ]
             }
           }
         }
       }
  3. Save the file and exit the text editor.

Step 3: Run the playbook

Run the Ansible playbook to deploy the LNMP environment.

ansible-playbook create_lnmp.yml

The deployment may take several minutes. Ansible calls the ROS API to create a stack, which provisions the VPC, vSwitch, security group, and ECS instance. After the ECS instance starts, the UserData script installs and configures NGINX, MariaDB, and PHP.

Verify the deployment

After the stack is created, verify that the LNMP environment is running:

  1. Log in to the ROS console and find the stack named create_lnmp_instance.

  2. On the Outputs tab of the stack details page, find the NginxWebsiteURL value. The URL format is http://<ECS-public-IP>:80/test.php.

  3. Open the URL in a web browser. If the deployment is successful, the page displays a message confirming the MySQL connection and the PHP configuration information.

Clean up resources

To avoid ongoing charges, delete the ROS stack when you no longer need the LNMP environment. Delete the stack from the ROS console or modify the playbook to set state: absent:

- hosts: localhost
  remote_user: root
  tasks:
    - name: Delete LNMP Instance
      ali_ros_stack:
        state: absent
        stack_name: create_lnmp_instance

Run the updated playbook:

ansible-playbook create_lnmp.yml

Deleting the stack removes all resources that the template created, including the VPC, vSwitch, security group, and ECS instance.

References