Setup Email Server From Scratch On FreeBSD #2 - 01 Server Setup
We believe in data independence, and support others who want data independence.
This tutorial is complete 2025-08-14 except there is no page for setting up postscreen.
This is version 2 and everthing works.
################ # Server Setup # ################
Go to your prefered registrar or use an existing domainname and choose a hostname something like mail.domain.com or mx.domain.com. DNS and MX records setup will be done after determining the new mail servers IP addresses.
The following assumes the domain name is okbsd.com so change it to your domain name and change the IPV4 and IPV6 addresses to your own IP addresses. Also change 'user' to your username where needed.
Setup a server with a hosting provider of choice. I have used IBM, One Provider, Kamatera,, MS Azure, and OVHcloud - Vint Hill and Hillsboro. I recommend a vps or dedicated server with OVH at Hillsboro. I only recently started using them but they are the cheapest and the chat support has always been prompt and helpful. Even if they couldn't add FreeBSD to their list of OS's for vps range of servers.
An important issue is that sometimes hosting providers have IP address ranges which are on a blacklist and some email servers may reject mail from servers using these ranges. In particular check with a dns checker like dnschecker.org to to see if the IP you get assigned is on UCEPROTECTL3. It is pretty difficult to get off a IP range blacklist and the best solution is to ask the hosting provider to give you a different IP ... and ask them to monitor their customers email habits more rigorously. That being said even if you are on one of these IP range spam lists it may not be a big issue. I tested with okbsd.com which was on such one such list and google accepted the email while outlook accepted it but put it in the junk folder. Listing it as not junk will improve your domain's reputation as long as you're not doing mass mailing campaigns or sending spam.
I previously setup a Debian 12 server on Kamatera in Dallas with 2 availability cores 4GB RAM and 40GB disk space and network speed and performance are good for $19 a month. I changed to OVH in Hillsboro and setup my second Debian mail server VPS instance for $11 month.
If you find initial ssh connection to FreeBSD to be slightly slower, enable packet reassembly in ipfw.
This is the second setup and 2nd version of this howto for FreeBSD. For this mail stack setup we installed on OVH Cloud, KS-5, with 4 cores 8 threads 32GB RAM 2TB GB Raid 1 SSD's. This has more than enough resources to run mail and other services. Hosting cost is $20 for setup, plus $20 plus tax per month. I asked the chat support to allow install of FreeBSD with their vps service and they said not possible so and they setup an invoice that waived the setup fee for a dedicated server where installing a custom image is allowed. During install I botched the network configuration (don't configure the second network interface) and lost Serial Over LAN and had to re-install, it went smoothly the second time.
Install on OVH was a little more tricky since they don't support FreeBSD by default. You can try installing from the Java KVM console or use the BYOI option.
Use the OVH installer with the bring your own custom image option. Usually I use the DVD image since includes ports but download would be faster if using the disk1 image.
Installation from an OVHcloud template
Type of OS: Custom
CUSTOM(2): Bring Your Own Image
-> Next
Image URL: https://download.freebsd.org/releases/amd64/amd64/ISO-IMAGES/14.3/FreeBSD-14.3-RELEASE-amd64-disc1.iso
Image Type: raw
Path of the EFI bootloader from the OS installed on the server: /boot/efi/efi/boot/bootx64.efi
It takes a few minutes for the machine to provision then switch to the IPMI/KVM tab. You can use the java applet if you have that installed but it is simpler to choose Serial Over LAN.
Setup Java on a local FreeBSD, Debian, or Windows machine for KVM access. For FreeBSD the proceedure is similar to Debian but uses linux compatability. Newer IPMI versions need jdk1.8.0_451. For complete FreeBSD, Debian, and Windows instructions see . . .
Java KVM Console Windows/FreeBSD/Debian
Java KVM on FreeBSD Client
Download jdk-8u451-linux-x64.tar.gz from oracle
Setup linux compatability on FreeBSD
mkdir /compat/ubuntu/usr/java
tar xfzv jdk-8u451-linux-x64.tar.gz -C /compat/ubuntu/usr/java/
chroot /compat/ubuntu /bin/bash
nano /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
# JAVA_HOME="/usr/java/jdk1.7.0_80"
JAVA_HOME="/usr/java/jdk1.8.0_451"
source /etc/environment
nano ~/.bashrc
export JAVA_HOME="/usr/java/jdk1.8.0_451"
export PATH="$PATH:/usr/java/jdk1.8.0_451/bin"
update-alternatives --install "/usr/bin/java" "java" "/usr/java/jdk1.8.0_451/bin/java" 1
update-alternatives --config java
Selection Path Priority Status
------------------------------------------------------------
0 /usr/java/jdk1.8.0_451/bin/java 1 auto mode
1 /usr/java/jdk1.7.0_80/bin/java 1 manual mode
* 2 /usr/java/jdk1.8.0_451/bin/java 1 manual mode
java -version
exit chroot
exit
Allow all connections to X Windows
xhost +
chroot /compat/ubuntu /bin/bash /usr/java/jdk1.8.0_451/bin/ControlPanel
Security High (the lowest setting allowed)
Advanced enable all versions of TLS
/compat/ubuntu/usr/java/jdk1.8.0_451/bin/javaws /root/Downloads/nsxxxxx-ip-xxx-xxx-xx-us_.jnlp
Choose Don't Update - Later -> Run -> console will open
Java KVM on Debian Client
Download jdk-8u451-linux-x64.tar.gz from oracle
mkdir /usr/java
tar xfzv jdk-8u451-linux-x64.tar.gz -C /usr/java
nano /etc/environment
# JAVA_HOME="/usr/java/jdk1.7.0_80"
JAVA_HOME="/usr/java/jdk1.8.0_451"
source/etc/environment
nano ~/.bashrc
#export JAVA_HOME="/usr/java/jdk1.7.0_80"
#export PATH="$PATH:/usr/java/jdk1.7.0_80/bin"
export JAVA_HOME="/usr/java/jdk1.8.0_451"
export PATH="$PATH:/usr/java/jdk1.8.0_451/bin"
update-alternatives --install "/usr/bin/java" "java" "/usr/java/jdk1.8.0_451/bin/java" 1
update-alternatives --config java
Select the correct version
0 /usr/java/jdk1.8.0_451/bin/java 1 auto mode
1 /usr/java/jdk1.7.0_80/bin/java 1 manual mode
* 2 /usr/java/jdk1.8.0_451/bin/java 1 manual mode
java -version
/usr/java/jdk1.8.0_451/bin/ControlPanel
Security -> Select Lowest Security Possible -> High
OVHCloud Dedicated Server -> Select Server -> IPMI/KVM -> From Java Applet KVM This will download a jnlp file, run it.
/usr/java/jdk1.8.0_451/bin/javaws /root/Downloads/nsxxxxxx-ip-xxx-xxx-xx-us_.jnlp
Choose Don't Update - Later -> Run -> console will open
OVHCloud does not allow Java KVM on all machines, usually not available for vps. There is an option to use Java KVM and boot with an iso and potentially reinstall the OS without the OVH control panel, but only for Dedicated Servers.
################### # Install FreeBSD # ###################
We'll use hostname okbsd.com and the IP addresses assigned by OVH, change your setup accordingly.
Select Install
Continue with Default Keymap
Set Hostname : okbsd.com
Distribution Select: Use the defaults plus src and ports.
If you need kernel sources and ports can be installed later.
Manual paritioning isn't needed since with ZFS you can change the partitions later but I bumped the swap size to 4g. Another option is to choose UFS with or without separate partitions if you never plan to try and increase the disk size.
Partitioning: Auto (ZFS)
Pool Type: default stripe
ZFS Configuration: you can change swap to 4G if you want
Select disks to create zfs pool "zroot" on "ada1"
>>> Install
It is very important to confirm you know the root password before leaving the installer.
Change password for root
New Password:
For Networking configure the first interface only, do not configure the second interface. On first install I lost network after running configure on the second interface during install and lost SOLAN access (no network no LAN) and had to restart the install from the beginning.
IPv4: DHCP
Enter valued from OVH Server Page - there is little point to configure ipv6 yet
IPv6 Address: 2604:2dc0:200:187::1
IPv6 Gateway: 2604:2dc0:200:1ff:ff:ff:ff:ff
Search: okbsd.com
DNS1: 9.9.9.9
DNS2: 1.1.1.1
Select Timezone ...
Enable: unbound sshd ntp ntp_sync_on_start
System Hardening: I skip all of these though random pid might be an idea
The IPMI/KVM or SOL are poor and it is almost impossible to cut and paste any command into the IPMI console. While you can get in later with IPMI if you know the root password it is better to setup a user account in group wheel or sudo, and confirm root access before leaving the installer.
Add User Accounts: jack
Full Name: Jack Pumpkin
Set user password: ***
It is important to invite the user 'jack' to group 'wheel' which allows su access to the root account. Initially ssh access to root is denied, so you will need to login as jack then su - root to get root access.
Invite to other groups: wheel
At this point you have an option to drop to shell and use chroot to change root or jack's passwords. Make sure you know your passwords.
Choose EXIT THE INSTALLER
<Continue and Reboot>
Stay logged in to the web console (SOL) or KVM and wait for reboot and login as the user jack with the jack's password.
You may also be able to login directly with ssh
ssh jack@147.135.37.135
<jacks password>
SOL console access is poor at best. If the network configuration is broken SOL may not work, and the simplest fix is restart the installation in OVH Cloud control panel.
Use terminal or cmd shell to ssh to the server
homeuser@homebox:~ $ ssh jack@147.135.37.135
<password>
jack@okbsd:~$ su - root
<rootpassword>
root@okbsd.com:~# ssh-keygen
<enter>
<enter>
<enter>
pkg update
pkg upgrade
pkg install bash bind-tools sudo nano lsblk bind920
Configure sudo access, to use nano set nano as your editor or use builtin vi.
For vi use 'x' to remove and <esc> <esc> 'wq' to write and quit
pw group add sudo -g 995
pw group mod sudo -m jack
export EDITOR='/usr/local/bin/nano'
visudo
--- uncomment these lines ---
%wheel ALL=(ALL:ALL) ALL
%sudo ALL=(ALL:ALL) ALL
Test sudo
root@okbsd.com:~# su - jack
jack@okbsd.com:~$ pkg install nano
pkg: Insufficient privileges to install packages
jack@okbsd.com:~$ sudo pkg install nano
Password: <jacks_password>
The most recent versions of packages are already installed
Exit jack user shell and continue as root.
jack@okbsd.com:~$ exit
root@okbsd.com:~#
Setup ssh key pair access to your server
Open a console on your local machine and get or create a ssh key pair.
FreeBSD, Linux, or Mac - open a console on your local machine and create a key pair if none, from terminal.
jill@home:~ $ ssh-keygen
<enter>
<enter>
<enter>
FreeBSD, Linux, or Mac - get a copy of the public key.
jill@homebox:~ $ cat ~/.ssh/id_rsa.pub
Windows - open a cmd shell and type ssh-keygen -t rsa -b 2048.
DOS> ssh-keygen -t rsa -b 2048
Windows - get a copy of the public key.
DOS> more .ssh\id_rsa.pub
DOS> cd .ssh
DOS> more id_rsa.pub
Install the authorized public key copied above, for nano '^' means control key so <ctrl>-o to write and <ctrl>-x to exit. Command list is at the bottom.
nano ~/.ssh/authorized_keys
<paste the public ssh key all as one line>
Configure ssh to allow root login only with ssh key pair
nano /etc/ssh/sshd_config
--- change the line PermitRootLogin ---
# PermitRootLogin no
PermitRootLogin prohibit-password
# PermitRootLogin yes
service sshd restart
Open another terminal or command shell and try passwordless root access.
Leave the first terminal open, so if the you can't get access you can fix it and restart sshd without getting locked out. Test root ssh access with the key pair from the local machine with terminal cmd shell or Putty. If using Putty use puttygen to import the ~/.ssh/id_rsa file and save it as a ppk file and configure Putty under ssh -> auth -> keyfile, and save your putty configuration.
You can also ssh directly from cmd shell on Windows.
DOS> ssh root@147.135.37.135
<no password required>
root@okbsd:~#
SV - To change root password if needed
root@okbsd.com:~# passwd
SV - To reset jacks password if needed
root@okbsd.com:~# passwd jack
root@okbsd:~ # exit
Setup the jack's ssh key pairs
jack@okbsd:~ $ ssh-keygen
<enter>
<enter>
<enter>
jack@okbsd:~ $ nano ~/.ssh/authorized_keys
<paste the public ssh key all as one line>
SV - To change root password from the jack account with sudo
jack@okbsd:~ $ sudo passwd root
jack@okbsd:~ $ exit
I'll leave off the prompt from now on to facilitate cut and pasting commands.
If you want to add another user use...
adduser
or use pw to add a user
pw adduser -n jack -s /usr/local/bin/bash -m
Delete a user and home directory, you may need to umount the zfs dataset
pw userdel -n jack
umount zroot/home/jack
rm -rf /home/jack
To change groupid, change sudo gid to 995
pw groupmod -n sudo -g 995
Change your shell with chsh but this is a vi editor so move around with the
arrow keys, use x to delete in command mode, use i to insert before the cursor,
x to delete a character
i insert text before the cursor
a append text after the cursor
Escape to exit insert or append mode
Escape Escape :wq to write quit
Excape Escape :q! to quit without saving and start over
Or use export EDITOR='/usr/local/bin/nano'
Change shell for root
Get as list of shells
export EDITOR='/usr/local/bin/nano'
cat /etc/shells
chsh
Shell: /usr/local/bin/bash
Change shell for user also
chsh jack
Shell: /usr/local/bin/bash
Modify bash settings and create a personal binary 'bin' directory
mkdir -p ~/bin
If PATH doesn't have ~/bin eg /root/bin or /home/user/bin add ONE of the following lines to .profile on FreeBSD or to .bashrc on Debian as below, change user as appropriate. If your PATH already includes ~/bin don't add it again!
nano ~/.profile
--- ADD ONLY ONE IF NEEDED ---
export PATH="$PATH:~/bin"
export PATH="$PATH:$HOME/bin"
LSCOLORS is almost unreadable with some terminal programs but comes out nicely with Xterm or Xterm-color.
If you manage many servers which may by default have same short hostname like 'pbx.domain.com' change PS1 so as to easily identify the server with the full hostname, PS1='\u@$(hostname -f):\w\$ '
Get rid of cookie hints!
nano ~/.profile
--- add or modify these lines ---
export EDITOR=/usr/local/bin/nano
export PS1='\u@$(hostname -f):\w\$ '
export LSCOLORS="ExGxFxdxCxegDxabagacad"
export XTERM_LOCALE="en_US.UTF-8"
export LANG="en_US.UTF-8"
# Display a random cookie on each login.
# if [ -x /usr/bin/fortune ] ; then /usr/bin/fortune freebsd-tips ; fi
# my aliases
alias rm='rm -i'
alias ls-a='/bin/ls -aGF'
alias ls-l='/bin/ls -lhGF'
alias lsl='/bin/ls -lhIGF'
alias ls='/bin/ls -IGF'
alias pine='alpine'
Test your colors
cd
mkdir -p ~/Downloads ~/bin
ls ~/Downloads ~/bin
Make nano pretty on FreeBSD, syntax highlighting
nano ~/.nanorc
include /usr/local/share/nano/default.nanorc
include /usr/local/share/nano/php.nanorc
include /usr/local/share/nano/perl.nanorc
include /usr/local/share/nano/html.nanorc
include /usr/local/share/nano/python.nanorc
include /usr/local/share/nano/c.nanorc
include /usr/local/share/nano/sh.nanorc
Repeat the above .profile setup as the user and comment out the fortune line
su - jack
nano .profile
.....
################################# # Setup Hostname and Networking # #################################
Change autoboot delay - default is 10 seconds
nano /boot/loader.conf
autoboot_delay="2"
Edit rc.conf and setup hostname and network interfaces
The last number provided by OVH :1 but using :2 or :10 also work. I use the chat support in OVH frequently and was told you can chnage the ipv6 address in the OVH panel it's easier to just leave it.
Set a Reverse PTR in OVH. Choose a hostname like mx mail smtp imap mx1 mx2 ... or any of your choice, we'll use something short like mx here... change as needed. Set the reverse path to the main mail server hostname. Do the same for both ipv4 and ipv6 addresses.
Bare Metal Cloud -> Dedicated Servers -> select server -> General Information ->
Network -> select 3 dots -> Manage -> 3 dots to far right -> Modify Reverse Path
-> mail.okbsd.com
Add the static IPV6 from OVH but a prefixlen of 64 will put the router address provided by OVH on a different subnet which won't work. IPv6 addresses have 4 bits per hexidecimal character. Expand the part of the address that is shared with the router which is 2604:2dc0:0200:01... and count the bits to get the mask, 14 char x 4 bits = 56 bits.
<--- 64 bits ---->
2604:2dc0:200:0187::1
2604:2dc0:200:01ff:ff:ff:ff:ff
<--- 56 bits -->
nano /etc/rc.conf
--- comment out the default inet6 line and add the OVH ipv6 address and router ---
hostname="okbsd.com"
ifconfig_igb0="DHCP"
# ifconfig_igb0_ipv6="inet6 accept_rtadv"
ifconfig_igb0_ipv6="inet6 2604:2dc0:200:187::1 prefixlen 56"
ipv6_defaultrouter="2604:2dc0:200:1ff:ff:ff:ff:ff"
sshd_enable="YES"
ntpd_enable="YES"
ntpd_sync_on_start="YES"
moused_nondefault_enable="NO"
# Set dumpdev to "AUTO" to enable crash dumps, "NO" to disable
dumpdev="AUTO"
zfs_enable="YES"
# dns server choices
# local_unbound_enable="NO"
named_enable="YES"
Edit the hosts file
nano /etc/hosts
# External WAN Interface
147.135.37.135 okbsd.com mail.okbsd.com smtp.okbsd.com imap.okbsd.com autoconfig.okbsd.com autodiscover.okbsd.com
2604:2dc0:200:187::1 okbsd.com mail.okbsd.com smtp.okbsd.com imap.okbsd.com autoconfig.okbsd.com autodiscover.okbsd.com
Check dns your resolver. For a web, dns, or mail server updating nameserver entries dynamically is probably not necessary and could lead to complications so disable the resolvconf service.
nano /etc/resovlconf.conf
resolvconf=NO
Make sure /etc/resolv.conf is not a symbolic link, if it is remove it.
rm /etc/resolv.conf
Update your nameservers as you like, if you are going to run your own dns server the first entry here should be nameserver 127.0.0.1. But until we get bind running leave it with valid external nameserver entries or you won't be able to download packages.
nano /etc/resolv.conf
nameserver 9.9.9.9
nameserver 1.1.1.1
search okbsd.com
I use Namecheap as my registar and DNS is free so I don't run my own master zone. name servers. Add some A records and mx records to Namecheap's DNS. The following assumes the domain is okbsd.com and the IP ADDRESS for my OVH Cloud Dedicated Servers so change to your own domain name and IP addresses.
Add DNS Records with Namecheap
Namecheap -> Account -> Domains -> DNS -> Advanced DNS
Remove the redirect record.
Remove the www CNAME record.
Add New Records
A @ 147.135.37.135
AAAA @ 2604:2dc0:200:187::1
A mail 147.135.37.135
AAAA mail 2604:2dc0:200:187::1
A imap 147.135.37.135
AAAA imap 2604:2dc0:200:187::1
A smtp 147.135.37.135
AAAA smtp 2604:2dc0:200:187::1
Add the www CNAME record ...
CNAME www okbsd.com
Add the autoconfig and autodiscover CNAME records ...
CNAME autoconfig mail.okbsd.com
CNAME autodiscover mail.okbsd.com
Type Service Protocol Priority Weight Port Target
SRV Record _autodiscover _tcp 5 0 443 mail.okbsd.com
Do not use CNAME, use A and AAAA records for mx, mail exchange hosts. You could have added another ipv6 address in rc.conf as an alias and then use one for mx and one for mail but this isn't necessary. We can add dmarc and spf and dmarc records now and will create admin@147.135.37.135 later.
Please do not add the following 4 records unless you are setting up a mail server with the mailbox specified. Use any valid email address for the rua and ruf records but RFC guidelines require a postmaster@domain.tld mailbox or alias so it is a logical choice.
ADD MX Records - scroll down in namecheap - change mx forwarding to custom mx
MX @ smtp.okbsd.com 0
MX @ mail.okbsd.com 10
ADD DMARC and SPF TXT Records
TXT @ v=spf1 ip4:147.135.37.135 ip6:2604:2dc0:200:187::1/112 mx ~all
TXT _dmarc v=DMARC1; p=quarantine; rua=mailto:postmaster@okbsd.com; ruf=mailto:postmaster@okbsd.com; sp=quarantine
Make sure to enable DNSSEC in Namecheap or your own provider. The toggle is invisible just click on the area next to DNSSEC till it appears.
Namecheap -> Account -> Domains -> DNS -> Advanced DNS -> Below Host Records -> DNS Sec
Setup a local caching nameserver to speed up dns requests. Unbound, dnsmasq, and bind all have strengths and weaknesses. Dnsmasq is good with DHCP clients but doesn't support DNSSEC. Both bind and unbound are dnssec capable and one of them should be used if running your own nameserver with dkim certs. A local full caching DNS resolver is needed if using real time blacklists DNSRBL so choose either unbound or bind. Bind supports master/slave zones transfer, NAPTR records, and it is fast. Basic bind configuration isn't difficult.
pkg install bind920
Enable bind in /etc/rc.conf
sysrc named_enable="YES"
service named start
service named status
rndc reload
Check bind setup, you want to enable recursion for the server itself and any networks you trust. Also enable DNSSEC.
cd /usr/local/etc/namedb
nano /usr/local/etc/namedb/named.conf
options {
// All file and path names are relative to the chroot directory,
// if any, and should be fully qualified.
directory "/usr/local/etc/namedb/working";
pid-file "/var/run/named/pid";
dump-file "/var/dump/named_dump.db";
statistics-file "/var/stats/named.stats";
// DNSSEC
dnssec-validation auto;
// RECURSION
recursion yes;
allow-recursion {
127.0.0.1;
::1;
// okbsd external
147.135.37.135;
2604:2dc0:200:187::1;
// okdeb slave
15.204.113.148;
2604:2dc0:202:300::3645;
// my trusted home network(s)
trusted_net/cidr;
};
allow-query { any; };
// ...
listen-on {
127.0.0.1;
147.135.37.135;
};
listen-on-v6 {
::1;
2604:2dc0:200:187::1;
};
// if this is master, define slaves here
//allow-notify { 15.204.113.148; };
//allow-transfer { localhost; 15.204.113.148; };
//notify yes;
};
Do not define any master zones unless you plan to run your own DNS, it's not needed for mail server setup.
rndc reload
Test Bind
nslookup google.com 127.0.0.1
Server: 127.0.0.1
Address: 127.0.0.1#53
Non-authoritative answer:
Name: google.com
Address: 142.250.217.110
Name: google.com
Address: 2607:f8b0:400a:80b::200e
nslookup okbsd.com 127.0.0.1
Server: 127.0.0.1
Address: 127.0.0.1#53
Name: okbsd.com
Address: 147.135.37.135
Name: okbsd.com
Address: 2604:2dc0:200:187::1
Make sure resolv.conf isn't a symbolic link, if it is remove it and recreate it.
ls -l /etc/resolv.conf
-rw-r--r-- 1 root wheel 91 Aug 1 12:03 /etc/resolv.conf
Modify /etc/resolv.conf to point to your local bind server.
nano /etc/resolv.conf
nameserver 127.0.0.1
nameserver 1.1.1.1
nameserver 9.9.9.9
options edns0 trust-ad
search .
Check if DNSSEC works, look for for 'ad' flag.
dig @8.8.8.8 okbsd.com +dnssec +multiline
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
Bind on the server itself will display the 'aa' flag.
dig @127.0.0.1 okbsd.com +dnssec +multiline
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
Firewall Setup - Once you start enabing services and adding DNS entries random addresses will start hitting your server trying to find a way in for nefarious purposes, so you will need a firewall. On FreeBSD I recommend a kernel based firewall called ipfw. I set ipfw default to accept so I won't get locked out if there is a script error. The last rule in the script is a global deny all. I have used ipfw for nat so I usually enable it. When making changes copy the script to a temporary file and test that first before copying it to the active script used at boot.
nano /boot/loader.conf
--- add these lines to end ---
ipfw_load="YES"
ipfw_nat_load="YES"
net.inet.ip.fw.default_to_accept="1"
nano /etc/rc.conf
--- add these lines ---
# ipfw firewall
firewall_type="open" # Firewall type (see /etc/rc.firewall)
firewall_script="/etc/ipfw.rules"
firewall_enable="YES"
firewall_logging="YES" # Set to YES to enable events logging
# gateway_enable="YES"
# firewall_nat_enable="YES"
# firewall_nat_interface="igb0"
ipv6_firewall_enable="YES"
ipv6_firewall_type="open" # see rc.firewall6 for what goes here
ipv6_firewall_quiet="NO"
ipv6_firewall_logging="YES"
ipv6_firewall_script=""
Double check your default gateway
netstat -r
Destination Gateway Flags Netif Expire
default 147.135.37.254 UGS igb0
Make your live firewall rules, completely open for testing
nano /etc/ipfw.rules
#!/bin/sh
ipfw -q -f flush
fwcmd="ipfw -q"
# Global Allow
${fwcmd} add allow all from any to any
Make your test firewall rules, to test manually. If you get locked out reboot your server and it will run the file above and allow access to modify the test file again. Run the test, if not locked out copy to the live file.
nano /etc/ipfw.testrules
--- change your addresses and interface ---
#!/bin/sh
ipfw -q -f flush
fwcmd="ipfw -q"
oif="igb0"
ip="147.135.37.135"
net="147.135.37.0/24"
gateway="147.135.37.254"
mask="255.255.255.0"
ip6="2604:2dc0:200:187::1"
net6="2604:2dc0:200:187::1/56"
gateway6="2604:2dc0:200:1ff:ff:ff:ff:ff"
${fwcmd} add allow ip from any to any via lo0
${fwcmd} add allow ipv6 from any to any via lo0
${fwcmd} add deny log ip from any to 127.0.0.0/8
${fwcmd} add deny log ip from 127.0.0.0/8 to any
# deny ipv6 to local if not lo0 above
${fwcmd} add deny log ipv6 from any to ::1
${fwcmd} add deny log ipv6 from ::1 to any
# Test - Global Allow
# ${fwcmd} add allow all from any to any
# Test - SSH TEMP
# ${fwcmd} add allow tcp from any to me 22 in via ${oif}
# You need the link-local addresses for IPv6's equivalent of ARP, which is
# done with ICMP and uses link-local addresses. Removing the link-local
# addresses would be similar to blocking ARP on IPv4, it's going to stop
# all communication.
${fwcmd} add allow ipv6-icmp from :: to ff02::/16
${fwcmd} add allow ipv6-icmp from fe80::/10 to fe80::/10
${fwcmd} add allow ipv6-icmp from any to any icmp6types 128,133,134,135,136,137
# deny all other ipv6 link local connections
${fwcmd} add deny log ipv6 from fe80::/10 to any
${fwcmd} add deny log ipv6 from any to fe80::/10
# Allow limited broadcast traffic from my own net.
${fwcmd} add pass all from ${net} to 255.255.255.255
# Allow IP fragments / Reassemble inbound packets
# ${fwcmd} add allow all from any to any frag in via ${oif}
# Reassemble packets - initial ssh connections will be faster is allow reassemble
${fwcmd} add reass all from any to any in via ${oif}
#${fwcmd} add deny all from any to any frag in via ${oif}
# PING6 - allow all ipv6 ping
${fwcmd} add allow ipv6-icmp from any to any
${fwcmd} add allow icmp from any to any
# Stateful Outbound DNS - only keep state for these
# Stateful rules are needed to resolve ipv6 mail server hostname
# For better preformance use as few stateful rules as possible
${fwcmd} add allow ip from me to any proto udp dst-port 53 keep-state
${fwcmd} add allow ip from me to any proto udp src-port 53 keep-state
# Stateful Outbound Rules - OUT IPV4:IPV6
# Enable these instead if if the stateless rules below don't work
# ${fwcmd} add allow tcp from me to any setup keep-state
# ${fwcmd} add allow udp from me to any keep-state
# ${fwcmd} add allow icmp from me to any keep-state
# Stateless Inbound Rule - for high performance servers
${fwcmd} add allow tcp from any to me 25,80,143,443,465,587,993 in via ${oif}
# Stateless Inbound DNS authoritative server
${fwcmd} add allow udp from any to me 53
${fwcmd} add allow tcp from any to me 53
# openvpn all allow / this is not needed / allow only trusted nets
# ${fwcmd} add pass tcp from any to me 1194 in via ${oif}
# IPv6 Rules
# Other Server
${fwcmd} add allow ipv6 from ff75:a791:abcd:dcba:1234::1 to me6 in via ${oif}
# Home
${fwcmd} add allow ipv6 from ff87:a5ab:27bd:15::/64 to me6 22 in via ${oif}
${fwcmd} add allow ipv6 from ff87:a790:b700::/40 to me6 22 in via ${oif}
${fwcmd} add allow ipv6 from ff87:a7e2::/32 to me6 22 in via ${oif}
# Stateless Outbound Rule - for high performance servers
${fwcmd} add allow tcp from me to any out via ${oif}
# Reassemble inbound packets
${fwcmd} add reass all from any to any in via ${oif}
# Deny IP fragments
${fwcmd} add deny all from any to any frag in via ${oif}
# Stateful Allow Established - IN IPV4:IPV6 - including DNS
${fwcmd} add allow ip from any to any established
# LAN6 - deny ssh allow other
${fwcmd} add deny log tcp from ${net6} to ${net6} 22 in via ${oif}
${fwcmd} add allow tcp from ${net6} to ${net6}
# IPv4 Rules
# LAN4 - deny ssh allow other
${fwcmd} add deny log tcp from ${net} to ${net} 22 in via ${oif}
${fwcmd} add allow tcp from ${net} to ${net}
# Other Server
${fwcmd} add pass all from 192.168.77.77 to me in via ${oif}
# Home Internet Example
${fwcmd} add pass tcp from 178.25.25.10:255.255.0.0 to me 22 in via ${oif}
# Office Network SSH PING TRACEROUTE - no ipv6
${fwcmd} add pass tcp from 10.77.21.0/24 to me 22 in via ${oif}
${fwcmd} add pass icmp from 10.77.21.0/24 to me
${fwcmd} add pass udp from 10.77.21.0/24 to me
# Trusted Location SSH PING TRACEROUTE - single ip
${fwcmd} add pass tcp from 172.16.17.18 to me 22 in via ${oif}
${fwcmd} add pass icmp from 172.16.17.18 to me
${fwcmd} add pass udp from 172.16.17.18 to me
# deny and log all other SSH requests
${fwcmd} add deny log tcp from any to me 22 in via ${oif}
# Global Deny - with logging
# ${fwcmd} add deny log ip from any to any
# Global Deny - without logging
${fwcmd} add deny ip from any to any
<reboot>
shutdown -r now
The server should come back up and run /etc/ipfw.rules which doesn't block anything. Run the test rules.
ipfw list
sh /etc/ipfw.testrules
ipfw list
Confirm you still have access to the server.
ssh root@147.135.37.135
After access is confirmed copy the test file to the live file which will be used on reboots.
cp /etc/ipfw.testrules /etc/ipfw.rules
To make changes edit /etc/ipfw.testrules.
nano /etc/ipfw.testrules
<make changes>
sh /etc/ipfw.test.rules
Test and if not working, reboot from OVH console to use the last working ipfw.rules. If ok...
cp /etc/ipfw.testrules /etc/ipfw.rules
Some of the keep-state rules may be redundant but the keep-state 53 rules was needed for IPv6 DNS issues.
Check your active rules with ...
ipfw list
############################ # Continue with FAMP setup # ############################