Q. I’ve FreeBSD based Apache webserver. I need to allow outgoing ftp client requests so that BSD ports collection can download from various ftp sites. How do I allow outgoing FTP connection via PF network firewall software under FreeBSD or OpenBSD operating system?

A. You need to use ftp-proxy, which is a proxy for the Internet File Transfer Protocol. ftp-proxy is installed by default along with PF firewall.

Step # 1: Turn on ftp-proxy under FreeBSD

Open /etc/rc.conf file under FreeBSD
# vi /etc/rc.conf
Append following line:
If you are using OpenBSD, type the following command to start the ftp proxy on boot:
echo 'ftpproxy_flags=""' >>/etc/rc.conf.local
By default ftp proxy listen on 8021 port bind to IP address.

Step # 2: Configure pf and ftp-proxy

Open your /etc/pf.conf file and add following into your NAT section:
To activate it, put something like this in the NAT section of pf.conf:
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"
rdr pass proto tcp from any to any port ftp -> port 8021

All three rules required, even if your setup does not use NAT. Find your filtering rule and append the following rules:
anchor "ftp-proxy/*"
Save and close the file.

Sample pf.conf rules

Here is my own working sample /etc/pf.conf file that allows outgoing ftp, along with ssh, http, dns service. It only allows incomming traffic on port 53, 80:

#### First declare a couple of variables ####
# outgoing services
tcp_services = "{ ssh, smtp, domain, www, https, ntp, 43}"
udp_services = "{ domain, ntp }"
icmp_types = "{ echoreq, unreach }"
martians = "{,,,,,,, }"
ext_if = "em1" # Internet
int_if = "em0" # vpn / lan
proxy="" # ftp proxy IP
proxyport="8021" # ftp proxy port
#### Normalization
scrub in all
#### NAT and RDR start
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"
# Redirect ftp traffic to proxy
rdr pass proto tcp from any to any port ftp -> $proxy port $proxyport
#### Start filtering 
# Drop incoming everything
block in all
# Default connection refused message to client 
block return  
# keep stats of outging connections
pass out keep state
# We need to have an anchor for ftp-proxy
anchor "ftp-proxy/*"
# Unlimited traffic for lo0 and VPN/Lan interface
set skip on {lo0, $int_if}
# activate spoofing protection for all interfaces
block in quick from urpf-failed
# Antispoof is a common special case of filtering and blocking. This mechanism protects against activity from spoofed or forged IP addresses
antispoof log for $ext_if
#Block RFC 1918 addresses
block drop in log (all)  quick on $ext_if from $martians to any
block drop out log (all) quick on $ext_if from any to $martians
# Allow outgoing via ssh, smtp, domain, www, https, whois etc
pass out on $ext_if proto tcp to any port $tcp_services
pass out on $ext_if proto udp to any port $udp_services
# Allow outgoing Trace route
pass out on $ext_if inet proto udp from any to any port 33433 >< 33626 keep state
# Allow incomming named udp / tcp 53
pass in on $ext_if proto udp from any to any port 53
# All tcp service protected using synproxy
pass in on $ext_if proto tcp from any to any port 53 flags S/SA synproxy state
# Allow http traffic
pass in on $ext_if proto tcp from any to any port 80 flags S/SA synproxy modulate state
# SSH 
pass in on $ext_if proto tcp from any to any port 22 flags S/SA synproxy modulate state
# Allow ICMP ping
pass inet proto icmp all icmp-type $icmp_types keep state

Step # 3: Restart PF firewall

Type the following command under FreeBSD:
# /etc/rc.d/pf restart
OR type the following under OpenBSD (also works under FreeBSD):
# pfctl -nf /etc/pf.conf
# pfctl -f /etc/pf.conf

Step # 4: Start ftp-proxy

Type the following command to start ftp-proxy under, FreeBSD:
# /etc/rc.d/ftp-proxy start
Under OpenBSD, you can simply type the following to start ftp-proxy:
# /usr/sbin/ftp-proxy

Test your setup

Use ftp client to test your test, enter:
$ ftp ftp.freebsd.org

Further readings:

🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 10 comments so far... add one

CategoryList of Unix and Linux commands
Disk space analyzersdf ncdu pydf
File Managementcat tree
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
10 comments… add one
  • John Dakos Jul 17, 2009 @ 13:06

    Good Job Man :) This Tutorial Help Me To Understand Ftp-Proxy and RDR. Thanks

  • John Aug 11, 2009 @ 9:57

    I’ve got ftp-proxy working on my firewall for all the clients behind it. However I can’t ftp (using Active or Passive) from the actual firewall itself, which is making installing/upgrading ports tedious.

    For example:
    #pkg_add -r ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7.2-release/Latest/ifstated.tbz
    Error: FTP Unable to get ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7.2-release/Latest/ifstated.tbz: Operation not permitted
    pkg_add: unable to fetch ‘ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7.2-release/Latest/ifstated.tbz’ by URL

    I’m guessing that this is because no redirection is being done as the request is being sent straight out the default route interface (I verified this by pausing the pkg_add command, and executing netstat -f inet | grep ftp).
    Any suggestions as to how I can get around this. Surely this is something that others have encountered.

  • 🐧 nixCraft Aug 11, 2009 @ 10:11



    pass out on $ext_if inet proto tcp from any to any port ftp
    pass out on $ext_if inet proto tcp from any to any port >1023
  • John Aug 11, 2009 @ 10:26

    Thanks, that would make sense. Unfortunately it also means that my block out rule is essentially rendered useless. A few people here use personal laptops with the BBC iPlayer installed which can eat bandwidth. By only allowing out required traffic, it makes life a lot easier.
    Any chance I can keep my cake and eat it :-)

  • SIFE Sep 28, 2009 @ 12:54

    Salamo Alikom
    @Vivek Gite
    this rules you had sets it fix my problem , thx.

  • Colin Nov 8, 2009 @ 20:26

    Hi Vivek,

    I think there is an error here:

    # pfctl -nf /etc/rc.conf
    # pfctl -f /etc/rc.conf

    Should be this:
    # pfctl -nf /etc/pf.conf
    # pfctl -f /etc/pf.conf

    In any case, thanks for a useful page and a very useful site. I keep coming back.


  • 🐧 nixCraft Nov 9, 2009 @ 5:43

    @ Colin

    Thanks for the heads up!

  • stiv Mar 31, 2010 @ 10:09

    Thank you for good article.
    But if I use the rule
    # keep stats of outging connections
    pass out keep state
    I don’t need any other rules such as
    # Allow outgoing via ssh, smtp, domain, www, https, whois etc
    pass out on $ext_if proto tcp to any port $tcp_services
    pass out on $ext_if proto udp to any port $udp_services

  • Ben Francom Nov 25, 2010 @ 12:29

    Thanks for the great article, and explanation. The comments are also very informative. It helped me recently with an instance of PF, FreeBSD and FTP.

  • Hasse Jan 7, 2012 @ 19:07

    As usual, it’s a pleasure following your tutorials. They simply works.

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum