Every freshly installed FreeBSD network server gets the same tuning list dropped into /etc/sysctl.conf. It isn’t a blob copy-pasted from some forum thread — each line is there either to raise throughput or to tighten the attack surface, and a few depend on kernel build options. This post lists that file as-is and explains why the categories that actually matter are there, and which lines deserve caution.
One premise up front: these values suit a machine with plenty of bandwidth that mostly terminates server-side connections. If yours sits on a lossy link or faces dial-up/weak-network clients, a couple of these (named below) will hurt rather than help — don’t copy them blindly.
Send/receive buffers
Growing the TCP/UDP send and receive buffers past the defaults is what lets a high-bandwidth link fill its bandwidth-delay product. Too-small buffers cap the window, and single-connection throughput stalls.
# max TCP send buffer
net.inet.tcp.sendspace=65536
# max TCP receive buffer
net.inet.tcp.recvspace=65536
# max UDP receive buffer
net.inet.udp.sendspace=65535
# max UDP send datagram size
net.inet.udp.maxdgram=65535
# local socket send space
net.local.stream.sendspace=65535
# max socket buffer
kern.ipc.maxsockbuf=2097152
kern.ipc.maxsockbuf is the hard ceiling on any socket buffer — it has to be large enough for the per-socket values above to take effect; 2MB leaves room for window autoscaling.
RFC switches for network performance
net.inet.tcp.rfc1323=1
net.inet.tcp.rfc1644=1
net.inet.tcp.rfc3042=1
net.inet.tcp.rfc3390=1
The one that matters most is rfc1323 (window scaling and timestamps) — without it, the TCP window is stuck at 64KB and no amount of sendspace helps on a high-BDP link. rfc3390 enlarges the initial congestion window so short connections ramp up faster. rfc1644 (T/TCP) is old and barely relevant on modern networks; harmless to leave on, but don’t count on it.
File descriptors
High-concurrency services open a lot of sockets and files, and the default descriptor limits run out quickly:
# system-wide max open files
kern.maxfiles=65536
# max open files per process
kern.maxfilesperproc=32768
TCP behavior and ICMP hardening
# disable delayed ACK: a small speedup on fast, lightly loaded links.
# but on a poor link the peer never sees the ack, keeps reconnecting, and it backfires
# -- leave it at the default on weak networks.
net.inet.tcp.delayed_ack=0
# drop ICMP redirects
net.inet.icmp.drop_redirect=1
net.inet.icmp.log_redirect=1
net.inet.ip.redirect=0
net.inet6.ip6.redirect=0
# prevent ICMP broadcast storms
net.inet.icmp.bmcastecho=0
net.inet.icmp.maskrepl=0
# rate-limit outbound ICMP
net.inet.icmp.icmplim=100
delayed_ack=0 is a double-edged knob, which is why it’s flagged: it saves a bit of latency on a clean datacenter LAN, but it amplifies retransmits toward weak-network clients on the public internet. We only disable it on internal high-speed links.
Dropping ICMP redirects and broadcast echoes is baseline hardening — it stops an attacker from rewriting routes via redirects or using broadcast echo for amplification.
Security parameters that need a kernel option
The next two only work if the kernel was built with options TCP_DROP_SYNFIN; otherwise setting them does nothing:
net.inet.icmp.icmplim_output=0
net.inet.tcp.drop_synfin=1
drop_synfin=1 discards malformed packets carrying both SYN and FIN, a pattern commonly used for OS fingerprinting; dropping them gives scanners less to work with.
Reaping dead connections and queues
# clean up TCP connections that were never closed properly. Costs a little bandwidth,
# but dead connections eventually get identified and reaped -- a known problem with
# dial-up users who drop the modem without closing active connections.
net.inet.tcp.always_keepalive=1
# if net.inet.ip.intr_queue_drops keeps climbing, raise this; the goal is drops at 0
net.inet.ip.intr_queue_maxlen=1000
intr_queue_maxlen is one of the few you should tune by watching a metric: leave it alone until net.inet.ip.intr_queue_drops starts rising in monitoring — that means the network interrupt queue is overflowing — then raise it.
Anti-DoS and port blackholes
# anti-DoS: shorten msl, default 30000
net.inet.tcp.msl=7500
# drop any packet to a closed port; 2 = TCP and UDP, 1 = TCP only
net.inet.tcp.blackhole=2
# drop any UDP packet to a closed port
net.inet.udp.blackhole=1
# buffering for network connections (inflight limiting)
net.inet.tcp.inflight.enable=1
# anti-DoS
net.inet.tcp.syncookies=1
blackhole is well worth enabling: by default, hitting a closed port returns an RST, which both confirms the port’s state to a scanner and wastes resources under a SYN flood. Setting it to 2 makes the kernel silently drop instead, so a port scan sees “no response” rather than “closed.” syncookies=1 lets the box keep accepting legitimate connections when the half-open queue fills up — standard kit against SYN floods.
Forwarding, polling, and concurrency
# when on, each successful forward records the destination in the route and arp tables,
# saving route computation but eating a lot of kernel memory for the route table.
# we keep it off.
net.inet.ip.fastforwarding=0
## needs options POLLING in the kernel; use under high load, not recommended at low load
## SMP cannot be used with polling
#kern.polling.enable=1
# listen backlog ceiling, default 128, recommended 1024-4096, more = more memory
kern.ipc.somaxconn=32768
We keep fastforwarding off by default — it’s a pure-router optimization with no payoff on a storage/service node, and it just wastes memory. The whole polling block stays commented out: with modern multicore plus interrupt coalescing (NICs like Mellanox), polling is a relic, and it conflicts with SMP anyway; it’s kept here only as a historical note. We raise somaxconn so the accept queue of a high-concurrency, short-connection service doesn’t fill up.
Process and kernel security
# hide other users' processes
security.bsd.see_other_uids=0
# kernel secure level
kern.securelevel=0
# log any TCP / UDP connection attempt
net.inet.tcp.log_in_vain=1
net.inet.udp.log_in_vain=1
# checksum UDP packets to guard against malformed UDP attacks
net.inet.udp.checksum=1
# no core dump on crash
kern.coredump=0
log_in_vain=1 records connection attempts to ports with no listener, which is useful for spotting scans and probes; under a sustained scan the log fills fast, so pair it with log rotation in production. kern.coredump=0 turns off core dumps, keeping sensitive memory off disk and saving space.
Shared memory (IPC)
# back shared memory with physical memory; needs 256MB+ RAM
kern.ipc.shm_use_phys=1
# max shared memory per thread
kern.ipc.shmmax=67108864
# max number of threads
kern.ipc.shmall=32768
These are mainly for services that use shared memory (databases, say). shm_use_phys=1 pins shared memory in physical RAM so it never swaps out, a real win for database-style workloads.
Local sockets and MSS
# lo local stream recv/send space
net.local.stream.recvspace=65536
net.local.dgram.maxdgram=16384
net.local.dgram.recvspace=65536
# default packet segment size, 1452 for ADSL
net.inet.tcp.mssdflt=1460
# buffering for network connections
net.inet.tcp.inflight_enable=1
# minimum packet segment size, 1452 for ADSL
net.inet.tcp.minmss=1460
# max local raw datagram size
net.inet.raw.maxdgram=65536
# local raw recv space
net.inet.raw.recvspace=65536
mssdflt=1460 matches a standard 1500-byte Ethernet MTU; if your link is PPPoE/ADSL, use 1452 instead or you’ll trigger fragmentation. Our machines are all on an Ethernet internal network, so 1460 it is.
Firewall dynamic rules
# ipfw dynamic rule count, default 4096; raising it stops some worms from filling the
# table with floods of TCP connections
net.inet.ip.fw.dyn_max=65535
# ipf TCP connection idle timeout, default 8640000 (120 hours)
net.inet.ipf.fr_tcpidletimeout=864000
How to use this list
We don’t recommend pasting every line above into /etc/sysctl.conf and calling it done. The right approach: the buffers, RFC switches, file descriptors, somaxconn, blackholes, and syncookies are safe and general — use them. The conditional ones — delayed_ack=0, fastforwarding, polling, and the kernel-option-dependent drop_synfin — need a judgment call against your own environment. And intr_queue_maxlen plus the firewall dynamic rules should be tuned while watching a metric. After changes, confirm with sysctl -a and then watch for drops or anomalies under real traffic — tuning is a data-driven loop, not a one-time paste.
