FTP from PHP between instances of EC2

Recently I had to configure the FTP connection between 2 instances of EC2, which can be quite complicated if we do not consider several points.

The main thing is to understand that the connection between 2 instances of EC2 is a connection that is made between 2 servers protected by a firewall, which also probably work with an internal IP, and use a public IP associated with your VPC.

Problems on FTP’s protocol

Most FTP problems are design flaws of the protocol itself (due to their age), and can not be easily solved.

When we work with FTP in this type of environment we have to take into account two important aspects:

Passive mode

To connect between machines protected by firewalls, passive mode is used, where the ports of the connection are indicated directly.

In the instance that contains the FTP server, we must create a Security Group that allows connection to a high range of ports (for example, from 10,000 to 15,000).

Also, in the FTP server that we are using, we must configure the same range of ports as ports to be used for passive connections, so that all passive connections are made against the ports we have opened.

On the client side, we must indicate that the connection is passive, and depending on how we are connecting, we may have to send a PORT command indicating the public IP.

The connection IPs

When a passive connection is made, it is the client who initiates the data connection with the server.

When the client is going to connect, and depending on the way to do it, and the type of connection or VPC that we are using, it is possible that it sends the private IP instead of the public IP, so the communication with the server will not be possible.

This can be solved by forcing the public IP address with a PORT command, just after starting passive mode.

FTP connection

Although the connection from PHP is in principle exactly the same as any other type of connection, in PHP we can do it in a simpler way with the functions that the language itself incorporates.

En el siguiente ejemplo podéis ver un script completamente funcional de conexión en PHP:

<?php
ini_set('display_errors', 1);
ini_set('track_errors', 1);

$conn_id = ftp_connect('54.54.54.54');
ftp_login($conn_id, 'username', 'password');

ftp_set_option($conn_id, FTP_USEPASVADDRESS, false);
ftp_pasv($conn_id,true);

$l = ftp_nlist($conn_id, ".");
if( ! $l ) {
        print_r(error_get_last());
}
var_dump($l);

The two important instructions in the are those that use the functions ftp_set_option and ftp_pasv , which is where we indicate the way we are going to make the connection.

The option FTP_USEPASVADDRESS what it does is ignore the IP that the server tells us (which may be incorrect) and use the IP of the connection directly (which is the correct one).

The ftp_pasv option initiates a normal passive connection.

With these two options, it is possible to connect without problems even if we are connecting between instances separated by a firewall and using NAT to connect.