title: Uploading a file to testcontainer FTP server fails with Connection refused after being connected
body: <p>I'm working with <a href="https://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html" rel="nofollow noreferrer">FTPClient</a> against an FTP server using <code>Testcontainers</code>.</p>
  <p>A reproducible code sample is here:</p>
  <pre><code>import org.apache.commons.net.PrintCommandListener;
  import org.apache.commons.net.ftp.FTP;
  import org.apache.commons.net.ftp.FTPClient;
  import org.apache.commons.net.ftp.FTPReply;
  import org.junit.jupiter.api.AfterAll;
  import org.junit.jupiter.api.BeforeAll;
  import org.junit.jupiter.api.Test;
  import org.testcontainers.containers.GenericContainer;
  import org.testcontainers.images.builder.ImageFromDockerfile;
  import org.testcontainers.junit.jupiter.Testcontainers;
  
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.PrintWriter;
  
  import static org.assertj.core.api.Assertions.assertThat;
  
  @Testcontainers
  class FtpUtilsTest {
  
      private static final int PORT = 21;
      private static final String USER = &quot;user&quot;;
      private static final String PASSWORD = &quot;password&quot;;
      private static final int FTP_TIMEOUT_IN_MILLISECONDS = 1000 * 60;
  
      private static final GenericContainer ftp = new GenericContainer(
          new ImageFromDockerfile()
              .withDockerfileFromBuilder(builder -&gt;
                  builder
                      .from(&quot;delfer/alpine-ftp-server:latest&quot;)
                      .build()
              )
      )
          .withExposedPorts(PORT)
          .withEnv(&quot;USERS&quot;, USER + &quot;|&quot; + PASSWORD);
  
  
      @BeforeAll
      public static void staticSetup() throws IOException {
          ftp.start();
      }
  
      @AfterAll
      static void afterAll() {
          ftp.stop();
      }
  
      @Test
      void test() throws IOException {
          FTPClient ftpClient = new FTPClient();
          ftpClient.setDataTimeout(FTP_TIMEOUT_IN_MILLISECONDS);
          ftpClient.setConnectTimeout(FTP_TIMEOUT_IN_MILLISECONDS);
          ftpClient.setDefaultTimeout(FTP_TIMEOUT_IN_MILLISECONDS);
  
          // Log
          ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
  
          // Connect
          try {
              ftpClient.connect(&quot;localhost&quot;, ftp.getMappedPort(PORT));
              ftpClient.setSoTimeout(FTP_TIMEOUT_IN_MILLISECONDS);
  
              int reply = ftpClient.getReplyCode();
              if (!FTPReply.isPositiveCompletion(reply)) {
                  ftpClient.disconnect();
                  throw new AssertionError();
              }
  
              // Login
              boolean loginSuccess = ftpClient.login(USER, PASSWORD);
              if (!loginSuccess) {
                  throw new AssertionError();
              }
  
              ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
              ftpClient.enterLocalPassiveMode();
  
          } catch (IOException e) {
              throw new AssertionError(e);
          }
  
          String remoteFile = &quot;fileonftp&quot;;
          try (InputStream targetStream = new ByteArrayInputStream(&quot;Hello FTP&quot;.getBytes())) {
              assertThat(ftpClient.isConnected()).isTrue();
              ftpClient.storeFile(remoteFile, targetStream);
          }
      }
  }
  </code></pre>
  <p>This prints:</p>
  <pre class="lang-none prettyprint-override"><code>220 Welcome Alpine ftp server https://hub.docker.com/r/delfer/alpine-ftp-server/
  USER *******
  331 Please specify the password.
  PASS *******
  230 Login successful.
  TYPE I
  200 Switching to Binary mode.
  PASV
  227 Entering Passive Mode (172,17,0,3,82,15).
  [Replacing PASV mode reply address 172.17.0.3 with 127.0.0.1]
  </code></pre>
  <p>then fails with:</p>
  <pre class="lang-none prettyprint-override"><code>Connection refused (Connection refused)
  java.net.ConnectException: Connection refused (Connection refused)
      ...
      at java.base/java.net.Socket.connect(Socket.java:609)
      at org.apache.commons.net.ftp.FTPClient._openDataConnection_(FTPClient.java:866)
      at org.apache.commons.net.ftp.FTPClient._storeFile(FTPClient.java:1053)
      at org.apache.commons.net.ftp.FTPClient.storeFile(FTPClient.java:3816)
      at org.apache.commons.net.ftp.FTPClient.storeFile(FTPClient.java:3846)
  </code></pre>
  <p>What I don't understand is that it fails after successfully connecting and logging in, and returning <code>true</code> for <code>isConnected</code>.</p>
  <hr />
  <p>Turns out that when removing the <code>ftpClient.enterLocalPassiveMode();</code> it works, but I need it to work with the passive mode.</p>
  <p>I guess the failure is related when switching to a different port for the passive call.</p>
  <p>but when trying to add the ports to the <code>withExposedPorts</code> the container fails to start with:</p>
  <pre class="lang-none prettyprint-override"><code>Caused by: org.testcontainers.containers.ContainerLaunchException: Timed out waiting for container port to open (localhost ports: [55600, 55601, 55602, 55603, 55604, 55605, 55606, 55607, 55608, 55609, 55598, 55599] should be listening)
  </code></pre>
  <hr />
  <p>Running against a docker (<code>docker run -d -p 21:21 -p 21000-21010:21000-21010 -e USERS=&quot;user|password&quot; delfer/alpine-ftp-server</code>) works.</p>
  <p>Local docker versions:</p>
  <ul>
  <li>Docker version 20.10.11, build dea9396</li>
  <li>Docker Desktop 4.3.1</li>
  </ul>
  <p>Testcontainers - appears to behave the same both on 1.16.2 and 1.15.3</p>
  <p>Link to testcontainers <a href="https://github.com/testcontainers/testcontainers-java/discussions/4787" rel="nofollow noreferrer">discussion</a></p>