Configure Linux As Bastion Host

What is bastion host? How do I configure bastion host under Linux? How do I create a firewall for a bastion host under any Linux distribution?

A bastion host is high risk host on your network. It can be a dedicated Linux running netfilter or OpenBSD box running PF or a Cisco PIX device. This device is designed to protect your network from external threats.

The Internet 
Bastion Host
Your Network

Usually bastion host placed outside your corporate firewall or in the DMZ itself.

The Internet
| Bastion Host  |  <--- Outside firewall
|    DMZ         | <---- Inside firewall
| LAN1 LAN2    |

In most cases it has access from the Internet or untrusted parties / computers. In some case a bastion host can be a:

  1. Web server
  2. DNS Server
  3. FTP Server
  4. Proxy Server
  5. Honey pots
  6. Email Server etc
WARNING! These examples needs a dedicated Linux box.You MUST know how to install programs on your computer, how to navigate file system, list open ports, configure iptables, write a firewall script and other advanced admin tasks.

Bastion Host and Screened Subnet

Bastion host adds an extra layer of security to the screened host architecture. It isolate your internal network form the Internet. The end result is that your bastion host is the primary target of Internet attacks. If someone beaks into the bastion host, your internal hosts are safe as the bastion host is isolated by the perimeter network. The bastion host firewall configuration has more security. Usually following is done on bastion hosts:

  1. Firewall works in close all ports and opened required port mode only.
  2. Intrusion detection system (IDS/IPS) such as as snort.
  3. Security settings to avoid Denial of Service (DoS), spoofing, and flood attacks.
  4. Undergo regular auditing.
  5. Runs upto date software.
  6. May run special kernel security patches.
  7. All user accounts are locked down except admin account.
  8. Encryption used for logging (ssh) or disk storage.
  9. Remove all end user software and other network servers such as Apache, MySQL and so on.
  10. TCP/IP stack tuned for network traffic including network buffers.
  11. /etc/sysctl.conf customized to improve server security

Usually, the bastion host does act as proxy server. It allows and denies connection as created by your security policy.

How Do I Build Linux As a Bastion Host?

A Linux based bastion host can be build using the following steps:

  1. Grab Debian / CentOS CD or your favorite Linux distribution.
  2. Install minimum operating system. Avoid installing desktop software or other apps such as MySQL, Apache and other software.
  3. Reboot the server.
  4. Patch server.
  5. Install grsecurity kernel patch and reboot the system.
  6. Install additional software such as snort IDS and configure it.
  7. Install Advanced Intrusion Detection Environment (AIDE) Software.
  8. Make sure all security patches are installed.
  9. Disable all network services except ssh.
  10. Disable all other daemons.
  11. Network tuning vis sysctl.conf
  12. Configure firewall (see sample script below).
  13. Remove centralized authentication such as LDAP.
  14. Remove as many utilities and system configuration tools as is practical for your setup. No need to have gcc compilers and other unwanted tools. Use rpm/yum and dpkg command to list all packages.
  15. Logging of all security related events and turn on auditing.
  16. Write protect all log files and only allow them in append only mode using chattr command (e.g. chattr +a /var/log/messages or chattr +i /etc/shadow).
  17. Encrypt all database passwords including file systems if possible.
  18. Create system recovery DVD or tape.

Above all are generic and recommended steps to configure bastion host.

Sample Linux Iptables Bastion Host Rules

You need at least two network interface one is connected to the Internet via public IP and another private to your Lan.

# The bastion host firewall for
# The bastion host is also:
# (a) Mail server to relay mail to 
# (b) DNS server send zone trasfer to  and 
# (c) Allow incoming ssh / http / https to from LAN SUBNET sothat
#     we can manage via ssh, and read snort stats via ACID web interface.
### Set vars ###
### Set interfaces ###
EXT_IF="eth0" 		# The Internet
LAN_IF="eth1"		# Lan
### Block RFC 1918 private address space range ###
### Block reserved Class D and E IP  ###
### Block the unallocated address range et all ###
### Set Lan Subnet ###
### Set DNS Server IPs  ###
### Set Postfix Server IP ###
### Set port numbers ###
### Clean out old fw ###
$IPT -t nat -F
$IPT -t nat -X
$IPT -t mangle -F
$IPT -t mangle -X
### Turn on SYN flooding protection ###
$SYSCTL -w net/ipv4/tcp_syncookies=1
### Block out eveything ###
### Allow full access to loopback ###
### Block the RFC 1918 private address space ranges ###
for rfc in $SPOOFDIP
	$IPT -A INPUT -i ${EXT_IF} -s ${rfc} -j LOG --log-prefix " SPOOF DROP "
	$IPT -A INPUT -i ${EXT_IF} -s ${rfc} -j DROP
### Drop bad stuff ###
$IPT -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
$IPT -A INPUT -p tcp --tcp-flags SYN,FIN,PSH SYN,FIN,PSH -j DROP
$IPT -A INPUT -p tcp --tcp-flags SYN,FIN,RST SYN,FIN,RST -j DROP
# FIN-Only
$IPT -A INPUT -p tcp --tcp-flags FIN FIN -j DROP
$IPT -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
$IPT -A INPUT -p tcp --tcp-flags ALL SYN -j DROP
$IPT -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
$IPT -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
# FIN 
$IPT  -A INPUT -p tcp --tcp-flags FIN,ACK FIN -j DROP
# NULL packets
$IPT -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
$IPT -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
# Fragments
# sync
$IPT -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
### Allows the bastion host to query remote DNS servers  ###
$IPT -A INPUT -i ${EXT_IF} -p udp --dport ${DNS_PORT} -m state --state  NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -i ${EXT_IF} -p tcp --dport ${DNS_PORT} -m state --state  NEW,ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o ${EXT_IF} -p udp --sport ${DNS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o ${EXT_IF} -p tcp --sport ${DNS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
### Allow internal DNS i.e. zone trasfer between the bastion and 2 LAN ns1 & ns2 ###
$IPT -A INPUT -i ${EXT_IF} -p udp -s ${NS1_SERVER_IP} --dport ${DNS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -i ${EXT_IF} -p udp -s ${NS2_SERVER_IP} --dport ${DNS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT                                        
$IPT -A INPUT -i ${EXT_IF} -p tcp -s ${NS1_SERVER_IP} --dport ${DNS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT                                            
$IPT -A INPUT -i ${EXT_IF} -p tcp -s ${NS2_SERVER_IP} --dport ${DNS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
### Allow outgoing DNS and Zone transfers btw the bastion host and two 2 LAN ns1 & ns2 ###
$IPT -A OUTPUT -o ${EXT_IF} -p udp -d ${NS1_SERVER_IP} --sport ${DNS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT                                             
$IPT -A OUTPUT -o ${EXT_IF} -p udp -d ${NS2_SERVER_IP} --sport ${DNS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT                                             
$IPT -A OUTPUT -o ${EXT_IF} -p tcp -d ${NS1_SERVER_IP} --sport ${DNS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT                                             
$IPT -A OUTPUT -o ${EXT_IF} -p tcp -d ${NS2_SERVER_IP} --sport ${DNS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
### Allow LAN workstation to get into the bastion host via SSH but no access from the Internet ###
$IPT -A INPUT -i ${LAN_IF} -p tcp -s ${LAN_SUBNET} --dport ${SSH_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o ${LAN_IF} -p tcp -d ${LAN_SUBNET} --sport ${SSH_PORT} -m state --state ESTABLISHED -j ACCEPT
### Allow LAN workstation to get into the bastion host via HTTP to read SNORT stuff via web interface but no access from the Internet ###
### Read ACID stats ###
$IPT -A INPUT -i ${LAN_IF} -p tcp -s ${LAN_SUBNET} --dport ${HTTP_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o ${LAN_IF} -p tcp -d ${LAN_SUBNET} --sport ${HTTP_PORT} -m state --state ESTABLISHED -j ACCEPT
$IPT -A INPUT -i ${LAN_IF} -p tcp -s ${LAN_SUBNET} --dport ${HTTPS_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o ${LAN_IF} -p tcp -d ${LAN_SUBNET} --sport ${HTTPS_PORT} -m state --state ESTABLISHED -j ACCEPT
### External SMTP Rules ### 
$IPT -A INPUT -i ${EXT_IF} -p tcp --dport ${SMTP_PORT} -m state --state NEW,ESTABLISHED - j ACCEPT
$IPT -A OUTPUT -o ${EXT_IF} -p tcp --sport ${SMTP_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
### Internal SMTP Rules ###
$IPT -A INPUT -i ${LAN_IF} -p tcp -s ${SMTP_SERVER_IP} --sport ${SMTP_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o ${LAN_IF} -p tcp -d ${SMTP_SERVER_IP} --dport ${SMTP_PORT} -m state --state NEW,ESTABLISHED -j ACCEPT
### Add your other rules below ###
### End no editing below ###
### Log ###
$IPT -A INPUT -m state --state INVALID -j LOG --log-prefix " INVAID DROP "
$IPT -A INPUT -m state --state INVALID -j DROP
$IPT -A INPUT -i ${EXT_IF} -j LOG --log-prefix " INPUT DROP " 
$IPT -A OUTPUT -o ${EXT_IF} -j LOG --log-prefix " OUTPUT DROP "

Above script is basic and can be modified as per your requirements. You can also use firewall distributions such as pFsense or IPcop to automate lost of stuff.

Fig.01: pFsense in Action

Fig.01: pFsense in Action (click to enlarge)


  1. Thinking about firewalls
  2. An overview of network Firewall
  3. Linux DMZ tutorial using iptables
  4. Snort - A free lightweight network intrusion detection system for UNIX and Windows.
  5. Refer your Linux distribution documentations to perform required steps.
  6. man page sysctl, and iptables

🐧 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 analyzersncdu pydf
File Managementcat
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
  • kaosmonk Jun 27, 2009 @ 10:14

    Great article! Keep up the good work!

  • json Jun 27, 2009 @ 13:43

    Simple, Easy-to-follow procedures, thank you.
    typo: Cicso PIX device ==> Cisco PIX device

  • yoander (sedlav) Jun 29, 2009 @ 14:09

    Hi Vivek, could you write this for OpenBSD?

  • 🐧 nixCraft Jul 1, 2009 @ 9:17

    @yoander, You want only pf script or entire tutorial?

    @json, thanks for the heads-up!

  • yoander (sedlav) Jul 1, 2009 @ 13:23

    Vivek only pf scripts

  • max Jul 9, 2009 @ 9:22

    also, dont forget to jail your ssh and any other service accessible from outside to minimize compromise.
    1 0day will be enough.

  • liljedahl Jul 14, 2009 @ 6:33

    @Vivek Gite, I guess yoander wahts the rules for pf.

    • 🐧 nixCraft Jul 14, 2009 @ 7:59


      Sometime later I will write another FAQ using FreeBSD / OpenBSD pf firewall, but no ETA.

  • Nabin Jul 30, 2009 @ 10:46

    Dear sir,

    I want to build firewall on my dns server ip address. Only my allowed user can browse internet using my dns. Unauthorized user can’t use browse internet using my dns server address. how i will make firewall plz help me.

  • dwarez Feb 25, 2010 @ 11:40

    Can you make one more Article for OPENBSD as

    ####Configure OPENBSD As Bastion Host ####

    Thats would be great .Many users like to learn OpenBSD and this 8nix platform wildly using as a Bastion Host

    Thanks in Advance

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