Provision an Amazon EC2 Instance with PHP

Amazon EC2 is a powerful AWS service that includes the ability to provision on-demand servers. While you can easily do this through the AWS Management Console, in this post, I want show you how to use the AWS SDK for PHP to do it programmatically by interacting with the Amazon EC2 API.

Let's create a single PHP script, piece by piece, that uses the SDK to do the following:

  1. Create and configure an Amazon EC2 client.
  2. Create an EC2 key pair and store the private key.
  3. Create and configure an EC2 security group.
  4. Launch an EC2 instance of an Amazon Machine Image (AMI) and retrieve its public DNS name so we can access it via SSH.

Create an EC2 client

First, let's bootstrap the SDK and create an EC2 client object. Make sure to replace the placeholder values in the following code with your AWS credentials and desired region.

<?php

require 'vendor/autoload.php';

use Aws\Ec2\Ec2Client;

$ec2Client = Ec2Client::factory(array(
    'key'    => '[aws access key]',
    'secret' => '[aws secret key]',
    'region' => '[aws region]' // (e.g., us-east-1)
));

Create a key pair

Next, we'll create a key pair that will provide SSH access to our server once it is running. We need to create the key pair first so we can specify it when we launch the EC2 instance. Creating the key pair is simple.

// Create the key pair
$keyPairName = 'my-keypair';
$result = $ec2Client->createKeyPair(array(
    'KeyName' => $keyPairName
));

In order to use the key pair later, we will need to save the private key locally. We can do this by extracting the key material from the response and using some of PHP's file handling functions to save it to a file. We also need to adjust the file permissions so that the key can be used for SSH access.

// Save the private key
$saveKeyLocation = getenv('HOME') . "/.ssh/{$keyPairName}.pem";
file_put_contents($saveKeyLocation, $result['keyMaterial']);

// Update the key's permissions so it can be used with SSH
chmod($saveKeyLocation, 0600);

Create and configure a security group

Next, let's create and configure a security group which will allow the server to be accessed via HTTP (port 80) and SSH (port 22). By default, access to an EC2 instance is completely locked down. Security groups allow you to whitelist access to ports on an EC2 instance. Creating a security group requires only a name and description.

// Create the security group
$securityGroupName = 'my-security-group';
$result = $ec2Client->createSecurityGroup(array(
    'GroupName'   => $securityGroupName,
    'Description' => 'Basic web server security'
));

// Get the security group ID (optional)
$securityGroupId = $result->get('GroupId');

After creating the security group, you can then configure its rules. To open up ports 22 and 80 we will use the AuthorizeSecurityGroupIngress operation and specify the security group name.

// Set ingress rules for the security group
$ec2Client->authorizeSecurityGroupIngress(array(
    'GroupName'     => $securityGroupName,
    'IpPermissions' => array(
        array(
            'IpProtocol' => 'tcp',
            'FromPort'   => 80,
            'ToPort'     => 80,
            'IpRanges'   => array(
                array('CidrIp' => '0.0.0.0/0')
            ),
        ),
        array(
            'IpProtocol' => 'tcp',
            'FromPort'   => 22,
            'ToPort'     => 22,
            'IpRanges'   => array(
                array('CidrIp' => '0.0.0.0/0')
            ),
        )
    )
));

Note: In this simple example, we are granting all IP addresses access to these two ports, but in a production setting you should consider limiting the access to certain IP addresses or ranges as appropriate. Also, you may need to open additional ports for MySQL or HTTPS traffic.

Launch an instance

Now that we have a key pair and security group set up, we are ready to launch an EC2 instance (our server) with these settings. To launch an EC2 instance, you also need to specify the ImageId parameter, which is a reference to the AMI that the EC2 instance should be created from. In this example, we are going to use an Amazon Linux AMI. Use the EC2 RunInstances operation to launch the instance.

// Launch an instance with the key pair and security group
$result = $ec2Client->runInstances(array(
    'ImageId'        => 'ami-570f603e',
    'MinCount'       => 1,
    'MaxCount'       => 1,
    'InstanceType'   => 'm1.small',
    'KeyName'        => $keyPairName,
    'SecurityGroups' => array($securityGroupName),
));

From the result, we must get the ID of the instance. We do this using the getPath method available on the result object. This allows us to pull data out of the result that is deep within the result's structure. The following line of code retrieves an array of instance IDs from the result. In this case, where we have launched only a single instance, the array contains only one value.

$instanceIds = $result->getPath('Instances/*/InstanceId');

Now that the launch has been triggered, we must wait for the instance to become available. The AWS SDK for PHP provides a feature called Waiters, which allow you to poll a resource until it is in a desired state. We will use the waitUntilInstanceRunning method of the EC2 client to wait until the instance that we have just launched is in the "Running" state.

// Wait until the instance is launched
$ec2Client->waitUntilInstanceRunning(array(
    'InstanceIds' => $instanceIds,
));

Once the instance is running, we can use the DescribeInstances operation to retrieve information about the instance, including its public DNS name. We'll use the getPath method again on the result to extract the PublicDnsName value.

// Describe the now-running instance to get the public URL
$result = $ec2Client->describeInstances(array(
    'InstanceIds' => $instanceIds,
));
echo current($result->getPath('Reservations/*/Instances/*/PublicDnsName'));

Using the public DNS name and the private key that you downloaded, you can SSH into the server. You can do this (from Linux/Unix and Mac devices) by using the ssh command from your CLI.

ssh -i <path to key> ec2-user@<public dns name>

Once you are logged in, you can install software (e.g., yum install php) and deploy your application. Good work! Hopefully, this tutorial helps you with your next PHP-related DevOps project.

Comments