A few common problems when setting up a stateful firewall to allow FTP traffic.

FTP needs a separate data connection for transferring files or file listings. It has two modes of operation

passive
The clients request the server to listen for a connection. The server responds with the address and port where it is listening for the data connection. The client connects.
active
The client listens on a port for the data connection. The client notifies the server about the address and port. The server connects to the client

Stateful firewalls only allow specific traffic or already established/related traffic. Since the data connection uses a separate port it cannot easily be distinguished as being related to the legitimate FTP connection. This is where the helpers come in play.

ip_conntrack_ftp is a module that monitors ftp traffic and marks a data connection as RELATED to the control connection of a FTP session. When using the module, make sure you pass the option ports=21, or it will monitor all traffic and probably be very slow. This is easily done from /etc/modules.conf.

In order to allow data connections behind a NAT, the ip_nat_ftp module can do the trick. The ip_nat_ftp module depends on the the ip_conntrack_ftp module and does not need any parameters.

If the FTP session is encrypted (TLS for example) there is no way to statefully let the data connections through. When running a FTP server behind a NAT that allows encrypted connections the only solution is to specify the ports that it will listen on for passive connections and explicitly allow those.