This tutorial will show you how to protect your FreeBSD server using OpenBSD PF firewall. We will assume that you have a clean FreeBSD installation deployed by AKLWEB Host with no users added. We will do some other things beside Firewall configuration which will also harden the security of our FreeBSD server. Before firewall configuration, we will install some packages since the default FreeBSD installation comes with a minimal set of tools and packages (which is correct), to make it easier for us to work.<\/p>\n
The default shell in FreeBSD is\u00a0 First, install these packages:<\/p>\n GNULS is the\u00a0 Add a normal user to the system: (replace john with your username and don’t forget to add user to the wheel group)<\/p>\n Create zsh config file:<\/p>\n Copy this to your .zshrc file:<\/p>\n Run this command: (replace john with your username)<\/p>\n Now, login to the FreeBSD server with your username and change the default root password:<\/p>\n We don’t need sendmail. Stop and disable this service:<\/p>\n Next, we will change our rc.conf file to look more natural:<\/p>\n Change it to look like this:<\/p>\n Edit\u00a0 Add your IP address and hostname:<\/p>\n Set timezone:<\/p>\n Whenever you can, disable remote access for the root user. Most attacks on SSH will try to access through the root user account. Always connect with your username and then\u00a0 Disable root login:<\/p>\n Uncomment this line:<\/p>\n Reboot:<\/p>\n After the reboot finishes, you will see a message like this in the AKWLEB Host console:<\/p>\n That’s why we need to correct the clock manually. Follow these commands, first\u00a0 Now, we are going to configure the firewall. OpenBSD PF is included in the FreeBSD kernel, so you don’t have to install any packages.<\/p>\n With\u00a0 Insert this: (replace any IP addresses with yours)<\/p>\n Create\u00a0 Add some IP’s:<\/p>\n Now some explanation. Junk ports and junk IPs are just some ports\/IPs that we don’t want to see in logs. We have done this with this rule:<\/p>\n These are just defaults and you don’t have to worry about it:<\/p>\n This rule blocks outgoing SMTP traffic from your server (which is the default on AKLWEB Host).<\/p>\n Except\u00a0 Bruteforcers just says: Allow from <trusted> IPs to port 22 but only 10 concurrent connections can be made from one source IP. If it’s more than 10, block this IP and put it in table bruteforcers. The same goes for 20\/60 rule. It means a max of 20 connections in 60 seconds.<\/p>\n Enable firewall:<\/p>\n Uncomment these lines:<\/p>\n Reboot:<\/p>\n If you have done everything right, then you will be able to login and the firewall will be enabled. You don’t have to reboot every time you change the\u00a0 See who is trying to connect to your server in real-time:<\/p>\n Show history:<\/p>\n See if you have someone in bruteforcers table:<\/p>\n And that’s it. You have successfully implemented PF firewall on FreeBSD server!<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"closed","template":"","format":"standard","manualknowledgebasecat":[230],"manual_kb_tag":[437],"_links":{"self":[{"href":"https:\/\/support.aklwebhost.com\/wp-json\/wp\/v2\/manual_kb\/2866"}],"collection":[{"href":"https:\/\/support.aklwebhost.com\/wp-json\/wp\/v2\/manual_kb"}],"about":[{"href":"https:\/\/support.aklwebhost.com\/wp-json\/wp\/v2\/types\/manual_kb"}],"author":[{"embeddable":true,"href":"https:\/\/support.aklwebhost.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/support.aklwebhost.com\/wp-json\/wp\/v2\/comments?post=2866"}],"version-history":[{"count":3,"href":"https:\/\/support.aklwebhost.com\/wp-json\/wp\/v2\/manual_kb\/2866\/revisions"}],"predecessor-version":[{"id":2872,"href":"https:\/\/support.aklwebhost.com\/wp-json\/wp\/v2\/manual_kb\/2866\/revisions\/2872"}],"wp:attachment":[{"href":"https:\/\/support.aklwebhost.com\/wp-json\/wp\/v2\/media?parent=2866"}],"wp:term":[{"taxonomy":"manualknowledgebasecat","embeddable":true,"href":"https:\/\/support.aklwebhost.com\/wp-json\/wp\/v2\/manualknowledgebasecat?post=2866"},{"taxonomy":"manual_kb_tag","embeddable":true,"href":"https:\/\/support.aklwebhost.com\/wp-json\/wp\/v2\/manual_kb_tag?post=2866"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}\/bin\/sh<\/code>. This is a basic shell with no auto-complete functions. We will use something better. We will install\u00a0
zsh<\/code>.<\/p>\n
# pkg install zsh gnuls\r\nThe package management tool is not yet installed on your system.\r\nDo you want to fetch and install it now? [y\/N]: y\r\nBootstrapping pkg from pkg+http:\/\/pkg.FreeBSD.org\/freebsd:10:x86:64\/latest, please wait...\r\n...\r\n<\/code><\/pre>\n
ls<\/code>\u00a0program from Linux. We just want to have the same\u00a0
ls<\/code>\u00a0command in Linux and FreeBSD.<\/p>\n
# adduser\r\nUsername: john\r\nFull name: John Doe\r\nUid (Leave empty for default): \r\nLogin group [john]: \r\nLogin group is john. Invite john into other groups? []: wheel\r\nLogin class [default]: \r\nShell (sh csh tcsh zsh rzsh nologin) [sh]: zsh\r\nHome directory [\/home\/john]: \r\nHome directory permissions (Leave empty for default): \r\nUse password-based authentication? [yes]: \r\nUse an empty password? (yes\/no) [no]: \r\nUse a random password? (yes\/no) [no]: \r\nEnter password: \r\nEnter password again: \r\nLock out the account after creation? [no]: \r\nUsername : john\r\nPassword : *****\r\nFull Name : John Doe\r\nUid : 1001\r\nClass : \r\nGroups : john wheel\r\nHome : \/home\/john\r\nHome Mode : \r\nShell : \/usr\/local\/bin\/zsh\r\nLocked : no\r\nOK? (yes\/no): yes\r\nadduser: INFO: Successfully added (john) to the user database.\r\nAdd another user? (yes\/no): no\r\nGoodbye!\r\n<\/code><\/pre>\n
# ee \/home\/your-username\/.zshrc\r\n<\/code><\/pre>\n
PS1=\"<%U%m%u>$[%B%1~%b]%(#.#.$) \"\r\n\r\nbindkey -e\r\nalias su='su -m'\r\nalias du='du -h -d0'\r\nalias df='df -h'\r\nalias l=less\r\nalias ll='gnuls --color=always -l'\r\nalias ls='gnuls --color=always'\r\nalias pkg_ver='pkg version -v -l \"<\" | > upgrade'\r\n\r\nexport EDITOR=ee\r\n\r\nautoload -U colors && colors\r\nautoload -U promptinit && promptinit\r\nautoload -U compinit && compinit\r\n\r\n# History settings\r\nSAVEHIST=1000\r\nHISTSIZE=1000\r\nHISTFILE=~\/.history\r\nsetopt histignoredups appendhistory\r\n<\/code><\/pre>\n
chown john:john \/home\/john\/.zshrc\r\n<\/code><\/pre>\n
<aklwebhost>[~]$ su\r\nPassword:\r\n<aklwebhost>[~]# passwd \r\nChanging local password for root\r\nNew Password:\r\nRetype New Password:\r\n<aklwebhost>[~]# \r\n<\/code><\/pre>\n
<aklwebhost>[~]# \/etc\/rc.d\/sendmail stop\r\nStopping sendmail.\r\nWaiting for PIDS: 7843.\r\nsendmail_submit not running? (check \/var\/run\/sendmail.pid).\r\nStopping sendmail_msp_queue.\r\nWaiting for PIDS: 7846.\r\n<\/code><\/pre>\n
# ee \/etc\/rc.conf\r\n<\/code><\/pre>\n
#----------- NETWORKING ------------------------------------------------#\r\nhostname=\"ceph.domain1.com\" # replace ceph.domain1.com with your domain\r\nifconfig_vtnet0=\"dhcp\"\r\nstatic_routes=linklocal\r\nroute_linklocal=\"-net 169.254.0.0\/16 -interface vtnet0\"\r\n\r\n#--------- SERVICES BSD LOCAL ----------------------------------------#\r\nsshd_enable=\"YES\"\r\nntpd_enable=\"YES\"\r\n\r\n#pf_enable=\"YES\"\r\n#pf_rules=\"\/etc\/firewall\"\r\n#pf_flags=\"\"\r\n#pflog_enable=\"YES\" \r\n#pflog_logfile=\"\/var\/log\/pflog\" \r\n#pflog_flags=\"\" \r\n\r\nsendmail_enable=\"NONE\"\r\nsendmail_submit_enable=\"NO\"\r\nsendmail_outbound_enable=\"NO\"\r\nsendmail_msp_queue_enable=\"NO\"\r\n<\/code><\/pre>\n
\/etc\/hosts<\/code>\u00a0file:<\/p>\n
# ee \/etc\/hosts\r\n<\/code><\/pre>\n
::1 localhost localhost.ceph ceph\r\n127.0.0.1 localhost localhost.ceph ceph\r\n108.61.178.110 ceph.domain1.com ceph\r\n<\/code><\/pre>\n
# bsdconfig\r\n<\/code><\/pre>\n
su<\/code>\u00a0to root. Only users from the\u00a0
wheel<\/code>\u00a0group can\u00a0
su<\/code>\u00a0to root. That’s why we added our user to the wheel group.<\/p>\n
# ee \/etc\/ssh\/sshd_config\r\n<\/code><\/pre>\n
PermitRootLogin no\r\n<\/code><\/pre>\n
# reboot\r\n<\/code><\/pre>\n
time correction of 3600 seconds exceeds sanity limit (1000); set clock manually to\r\ncorrect UTC time.\r\n<\/code><\/pre>\n
su<\/code>\u00a0to root:<\/p>\n
$ su\r\nPassword:\r\n# ntpdate 0.europe.pool.ntp.org\r\n<\/code><\/pre>\n
ee<\/code>\u00a0editor, create file\u00a0
\/etc\/firewall<\/code>:<\/p>\n
# ee \/etc\/firewall\r\n<\/code><\/pre>\n
#######################################################################\r\nme=\"vtnet0\" \r\ntable <bruteforcers> persist \r\ntable <trusted> persist file \"\/etc\/trusted\"\r\nicmp_types = \"echoreq\" \r\njunk_ports=\"{ 135,137,138,139,445,68,67,3222 }\"\r\njunk_ip=\"224.0.0.0\/4\" \r\n\r\nset loginterface vtnet0 \r\nscrub on vtnet0 reassemble tcp no-df random-id\r\n\r\n# ---- First rule obligatory \"Pass all on loopback\"\r\npass quick on lo0 all \r\n\r\n# ---- Block junk logs\r\nblock quick proto { tcp, udp } from any to $junk_ip \r\nblock quick proto { tcp, udp } from any to any port $junk_ports\r\n\r\n# ---- Second rule \"Block all in and pass all out\"\r\nblock in log all \r\npass out all keep state \r\n\r\n############### FIREWALL ###############################################\r\n# ---- Allow all traffic from my Home\r\npass quick proto {tcp, udp} from 1.2.3.4 to $me keep state\r\n\r\n# ---- block SMTP out \r\nblock quick proto tcp from $me to any port 25\r\n\r\n# ---- Allow incoming Web traffic\r\npass quick proto tcp from any to $me port { 80, 443 } flags S\/SA keep state\r\n\r\n# ---- Allow my team member SSH access \r\npass quick proto tcp from 1.2.3.5 to $me port ssh flags S\/SA keep state\r\n\r\n# ---- Block bruteforcers\r\nblock log quick from <bruteforcers>\r\n\r\n# ---- Allow SSH from trusted sources, but block bruteforcers\r\npass quick proto tcp from <trusted> to $me port ssh \\\r\nflags S\/SA keep state \\\r\n(max-src-conn 10, max-src-conn-rate 20\/60, \\\r\noverload <bruteforcers> flush global)\r\n\r\n# ---- Allow ICMP \r\npass in inet proto icmp all icmp-type $icmp_types keep state\r\npass out inet proto icmp all icmp-type $icmp_types keep state\r\n<\/code><\/pre>\n
\/etc\/trusted<\/code>\u00a0file. In this file, we will put IPs that we “trust”.<\/p>\n
# ee \/etc\/trusted\r\n<\/code><\/pre>\n
# Hosting\r\n1.2.0.0\/16\r\n\r\n# My friends\r\n1.2.4.0\/24\r\n<\/code><\/pre>\n
# ---- Block junk logs\r\nblock quick proto { tcp, udp } from any to $junk_ip \r\nblock quick proto { tcp, udp } from any to any port $junk_ports\r\n<\/code><\/pre>\n
icmp_types = \"echoreq\" \r\nset loginterface vtnet0 \r\nscrub on vtnet0 reassemble tcp no-df random-id\r\npass quick on lo0 all\r\nblock in log all \r\npass out all keep state\r\n<\/code><\/pre>\n
# ---- block SMTP out \r\nblock quick proto tcp from $me to any port 25\r\n<\/code><\/pre>\n
bruteforcers<\/code>\u00a0the rest is pretty straight forward.<\/p>\n
# ---- Allow SSH from trusted sources, but block bruteforcers\r\npass quick proto tcp from <trusted> to $me port ssh \\\r\nflags S\/SA keep state \\\r\n(max-src-conn 10, max-src-conn-rate 20\/60, \\\r\noverload <bruteforcers> flush global)\r\n<\/code><\/pre>\n
# ee \/etc\/rc.conf\r\n<\/code><\/pre>\n
pf_enable=\"YES\"\r\npf_rules=\"\/etc\/firewall\"\r\npf_flags=\"\"\r\npflog_enable=\"YES\"\r\npflog_logfile=\"\/var\/log\/pflog\"\r\npflog_flags=\"\"\r\n<\/code><\/pre>\n
# reboot \r\n<\/code><\/pre>\n
\/etc\/firewall<\/code>\u00a0file. Just do:<\/p>\n
# \/etc\/rc.d\/pf reload\r\n<\/code><\/pre>\n
# tcpdump -n -e -ttt -i pflog0\r\n<\/code><\/pre>\n
# tcpdump -n -e -ttt -r \/var\/log\/pflog\r\n<\/code><\/pre>\n
# pfctl -t bruteforcers -T show\r\n<\/code><\/pre>\n