Setting up a FTP in passive mode: private vs public IP address

Hi there,

I recently deployed a FTP server on Fly using GitHub - gregmsanderson/fly-ftp-server: A simple public FTP server for Fly.io from @greg (cf. Setting up a public FTP server on Fly.io - #6 by greg).

However, after trying to configure the project, I ended up being able to FTP access the server through FileZilla, but not in my Elixir project (I’m using the :ftp module).

Here is my code:

url = "ftp://user:password@888.888.888.888/ftp"

%URI{
  host: host,
  scheme: "ftp",
  port: port,
  userinfo: userinfo,
  path: path
} = URI.parse(url)

{:ok, client_pid} =
  :ftp.open(host |> String.to_charlist(),
    verbose: true,
    timeout: 3_000,
    dtimeout: 3_000
  )

if userinfo do
  [user, pass] = userinfo |> String.split(":")
  :ok = :ftp.user(client_pid, ~c(#{user}), ~c(#{pass}))
end

IO.puts("FTP: OK 1 ")
:ok = :ftp.ls(client_pid)
IO.puts("FTP: OK 2")

And I get:

"Receiving: 220 Welcome"
"Sending: USER admin"
"Receiving: 331 Please specify the password."
"Sending: PASS ADMIN.EI.2022"
"Receiving: 230 Login successful."
"FTP: OK 1"
"Sending: PASV"
"Receiving: 227 Entering Passive Mode (172,19,0,242,82,8)."
** (MatchError) no match of right hand side value: {:error, :timeout}

I’ve never seen this 172.19... IP address, but I guess it’s the server’s private one, which mixes things up when trying to communicate to the outer world (no idea how FileZilla manages to get around this).

So I set the ADDRESS to the IP of my Fly server using fly secrets set ADDRESS="XX.XX.XX.XX"). And then I get:

"Receiving: 227 Entering Passive Mode (0,0,0,0,82,8)."
** (MatchError) no match of right hand side value: {:error, :econnrefused}

So it did change the IP address, but it set it to 0.0.0.0. What am I doing wrong here? I tried using IPv6 but couldn’t get it to work either.

Strange. Like you, I tried it using Filezilla and that seemed happy. But clearly its innards are different.

I think you are on the right lines. Looks like to make it work, the FTP server would need to report back to the client its public IP. But it doesn’t know that. Since it’s behind Fly’s proxy. So yes, I’m thinking you would need to use the ADDRESS (that I didn’t document) to set that. And yet you say it doesn’t use that, weird.

It may be worth experimenting with toggling IPv4 and IPv6, swapping these values over in the conf (seems like you can only listen on one or the other, one YES). See if that helps:

Total guess but can’t hurt!

Though … if Fly’s proxy connects to the vm using IPv6, which I suspect it does, doing that would break that connection. But we shall see.

1 Like

Hey @greg, thanks for your response!

I finally managed to make it work :slight_smile: I just had to write this in the conf file:

listen=YES
listen_ipv6=NO
pasv_address=my public address

It’s all fine now, thank you again for your help!

No problem!

I think I was originally experimenting with using Fly’s own TLS termination and so used the IPv6 option. But given that does not work. I’ve updated the repo to also have that switch. Since Filezilla doesn’t seem to care either way :slight_smile:

And I documented that ADDRESS env value. Since (as you’ve found) some applications care about that.