{"id":285,"date":"2025-02-19T18:15:25","date_gmt":"2025-02-20T02:15:25","guid":{"rendered":"https:\/\/www.cmsws.com\/blog\/?p=285"},"modified":"2025-02-19T18:15:47","modified_gmt":"2025-02-20T02:15:47","slug":"fail2ban-on-openbsd-6-0","status":"publish","type":"post","link":"https:\/\/www.cmsws.com\/blog\/fail2ban-on-openbsd-6-0\/","title":{"rendered":"Fail2ban on OpenBSD 6.0"},"content":{"rendered":"\n<p>This is not my article.  I found a link to the original article on a Reddit post: https:\/\/www.reddit.com\/r\/openbsd\/comments\/5e6u61\/fail2ban_on_openbsd_60\/    The page no-longer exists.  I dug up an old copy of the page from the <a href=\"http:\/\/web.archive.org\/\" title=\"\">Internet Archive Wayback Machine<\/a>.  The original article was found here: https:\/\/blog.gordonturner.com\/2016\/11\/20\/fail2ban-on-openbsd-6-0\/  Gordon, if this is your article, please forgive the reprint.<\/p><div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 ez-toc-wrap-right counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<span class=\"ez-toc-title-toggle\"><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.cmsws.com\/blog\/fail2ban-on-openbsd-6-0\/#Installing_Fail2ban\" >Installing Fail2ban<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.cmsws.com\/blog\/fail2ban-on-openbsd-6-0\/#Configure_Fail2ban\" >Configure Fail2ban<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.cmsws.com\/blog\/fail2ban-on-openbsd-6-0\/#Manage_Fail2ban\" >Manage Fail2ban<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.cmsws.com\/blog\/fail2ban-on-openbsd-6-0\/#Conclusion\" >Conclusion<\/a><\/li><\/ul><\/nav><\/div>\n\n\n\n\n<p>If you have ever had a server exposed to the Internet, you will often see attempts to login to ssh on port 22.<\/p>\n\n\n\n<p>After improving my log monitoring, these login attempts annoyed me enough to take action. So I installed Fail2ban.<\/p>\n\n\n\n<p>Fail2ban monitors logs and will add ip addresses to your firewall to block based on rules. Fail2ban is written in Python and available for several platforms and can monitor different logs (not just ssh).<\/p>\n\n\n\n<p>I have setup Fail2ban to watch for 3 failed logins (one failed login will allow 3 password attempts) and then block that IP address for 1 day.<\/p>\n\n\n\n<p>The following instructions are for:<\/p>\n\n\n\n<p>OpenBSD 6.0<br>Fail2ban 0.9.5<\/p>\n\n\n\n<p>The instructions also assume that you have an OpenBSD server running with ssh port 22 exposed to the Internet and use Packet Filter (PF) for your firewall.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Installing_Fail2ban\"><\/span>Installing Fail2ban<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Install Python, when asked for version, select 3.5:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo pkg_add python\n<\/pre>\n\n\n\n<p>Download fail2ban-0.9.1.tar.bz2, uncompress and install:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cd ~\/Downloads\nwget https:\/\/github.com\/fail2ban\/fail2ban\/archive\/0.9.5.tar.gz\nmv 0.9.5.tar.gz fail2ban-0.9.5.tar.gz \ntar -zvxf fail2ban-0.9.5.tar.gz\ncd fail2ban-0.9.5\nsudo python3.5 setup.py install\nsudo mkdir \/var\/run\/fail2ban\n<\/pre>\n\n\n\n<p>Next create a new rc file for Fail2ban. This will manage starting, stoping and checking for the status of Fail2ban. It is based on the rc.template, sabnzbd.rc and filebeat.rc.<\/p>\n\n\n\n<p><a href=\"http:\/\/cvsweb.openbsd.org\/cgi-bin\/cvsweb\/~checkout~\/ports\/infrastructure\/templates\/rc.template\" title=\"\">http:\/\/cvsweb.openbsd.org\/cgi-bin\/cvsweb\/~checkout~\/ports\/infrastructure\/templates\/rc.template<\/a><br><a href=\"http:\/\/web.archive.org\/web\/20220926005751\/http:\/\/cvsweb.openbsd.org\/cgi-bin\/cvsweb\/~checkout~\/ports\/news\/sabnzbd\/pkg\/sabnzbd.rc\">http:\/\/cvsweb.openbsd.org\/cgi-bin\/cvsweb\/~checkout~\/ports\/news\/sabnzbd\/pkg\/sabnzbd.rc<\/a><br><a href=\"http:\/\/web.archive.org\/web\/20220926005751\/http:\/\/cvsweb.openbsd.org\/cgi-bin\/cvsweb\/~checkout~\/ports\/sysutils\/beats\/filebeat\/pkg\/filebeat.rc?rev=1.1.1.1&amp;content-type=text\/plain\">http:\/\/cvsweb.openbsd.org\/cgi-bin\/cvsweb\/~checkout~\/ports\/sysutils\/beats\/filebeat\/pkg\/filebeat.rc?rev=1.1.1.1&amp;content-type=text\/plain<\/a><\/p>\n\n\n\n<p>It is worth noting that the rc file is a little non-traditional, because Fail2ban has two components, a client and a server. Normally rc files will start a daemon, check to see if the process is active and kill that process to stop. The `check` logic could probably be improved, but it works.<\/p>\n\n\n\n<p>Create the rc file and paste in the content:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo vi \/etc\/rc.d\/fail2ban\n<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">#!\/bin\/sh\n#\n# As the fail2ban-client is used to start the fail2ban-server, this rc is a little non-traditional.\n#\n# The rc_check looks for the fail2ban-server python thread (fail2ban-server as a parameter)\n#\n# The rc_stop can kill the fail2ban-server (The Nuclear Option) or the fail2ban-client (Polite Option).\n#\n#  pkill -f \"fail2ban-server\"\n#\n# Avoiding The Nuclear Option.\n\ndaemon=\"\/usr\/local\/bin\/fail2ban-client\"\n\n. \/etc\/rc.d\/rc.subr\n\nrc_bg=YES\nrc_reload=NO\n#pexp=fail2ban-server\n\nrc_pre() {\n\tinstall -d -o root -m 0700 \/var\/run\/fail2ban\n}\n\nrc_start() {\n\t$${rcexec} \"${daemon} start ${daemon_flags} ${_bg}\"\n}\n\nrc_check() {\n\tpgrep -q -f \"fail2ban-server\"\n}\n\nrc_stop() {\n\t${rcexec} \"${daemon} stop\"\n}\n\nrc_cmd $1\n<\/pre>\n\n\n\n<p>Set permissions:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo chmod 555 \/etc\/rc.d\/fail2ban\n<\/pre>\n\n\n\n<p>Edit `\/etc\/rc.conf.local` to add the Fail2ban rc file:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo vi \/etc\/rc.conf.local\n<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\"># ADDED \npkg_scripts=\"fail2ban\"\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Configure_Fail2ban\"><\/span>Configure Fail2ban<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Need to configure fail2ban what an ssh login failure looks like. Please update `192.168.0.10` to your local server ip address.<\/p>\n\n\n\n<p>A few comments here:<br>\u2013 Fail2ban is monitoring `\/var\/log\/authlog`<br>\u2013 After an IP has 3 failed logins, the IP will be blocked<br>\u2013 The IP will be blocked for 1 day (86400 seconds)<br>\u2013 Exclude localhost IP<\/p>\n\n\n\n<p>Create a new file `ssh-pf.local`:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo vi \/etc\/fail2ban\/jail.d\/ssh-pf.local\n<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\"># NOTE: 192.168.0.10 is local ip\n# NOTE:  3600 = 1 hr\n# NOTE: 86400 = 1 day\n<\/pre>\n\n\n<p>[ssh-pf]<\/p>\n\n\n\n<p>enabled = true filter = sshd action = pf[localhost=192.168.0.10] logpath = \/var\/log\/authlog findtime = 600 maxretry = 3 bantime = 86400 ignoreip = 192.168.0.10<\/p>\n\n\n\n<p>Configure fail2ban what action to take when the ssh login fails.<\/p>\n\n\n\n<p>Existing configuration fail2ban for pf.conf is unchanged:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo vi \/etc\/fail2ban\/action.d\/pf.conf\n<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\"># Fail2Ban configuration file\n#\n# OpenBSD pf ban\/unban\n#\n# Author: Nick Hilliard &lt;nick@foobar.org&gt;\n#\n#\n\n[Definition]\n\n# Option:  actionstart\n# Notes.:  command executed once at the start of Fail2Ban.\n# Values:  CMD\n#\n# we don't enable PF automatically, as it will be enabled elsewhere\nactionstart =\n\n\n# Option:  actionstop\n# Notes.:  command executed once at the end of Fail2Ban\n# Values:  CMD\n#\n# we don't disable PF automatically either\nactionstop =\n\n\n# Option:  actioncheck\n# Notes.:  command executed once before each actionban command\n# Values:  CMD\n#\nactioncheck =\n\n\n# Option:  actionban\n# Notes.:  command executed when banning an IP. Take care that the\n#          command is executed with Fail2Ban user rights.\n# Tags:      IP address\n#            number of failures\n#            unix timestamp of the ban time\n# Values:  CMD\n#\nactionban = \/sbin\/pfctl -t  -T add \/32\n\n\n# Option:  actionunban\n# Notes.:  command executed when unbanning an IP. Take care that the\n#          command is executed with Fail2Ban user rights.\n# Tags:      IP address\n#            number of failures\n#            unix timestamp of the ban time\n# Values:  CMD\n#\n# note -r option used to remove matching rule\nactionunban = \/sbin\/pfctl -t  -T delete \/32\n\n[Init]\n# Option:  tablename\n# Notes.:  The pf table name.\n# Values:  [ STRING ]\n#\ntablename = fail2ban\n<\/pre>\n\n\n\n<p>Setup OpenBSD Packet Filter with a new table to store the banned ip addresses<\/p>\n\n\n\n<p>NOTE: that table names are always enclosed in <strong>&lt; &gt;<\/strong> angled brackets<\/p>\n\n\n\n<p>Edit `\/etc\/pf.conf` and add to end:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo vi \/etc\/pf.conf\n<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\"># BEGIN ADDED fail2ban\n# NOTE: ext_if is external interface device\next_if=\"vio0\"\ntable  persist\nblock quick proto tcp from  to $ext_if port ssh\n# END ADDED fail2ban\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Manage_Fail2ban\"><\/span>Manage Fail2ban<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Use rc scripts to manage:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo \/etc\/rc.d\/fail2ban check\nsudo \/etc\/rc.d\/fail2ban start\nsudo \/etc\/rc.d\/fail2ban stop\n<\/pre>\n\n\n\n<p>Manually manage:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo fail2ban-client status\nsudo fail2ban-client start\nsudo fail2ban-client stop\n<\/pre>\n\n\n\n<p>Tail fail2ban log:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo tail -f \/var\/log\/fail2ban.log\n<\/pre>\n\n\n\n<p>Print contents of table:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo pfctl -t fail2ban -Ts \n<\/pre>\n\n\n\n<p>Start and load pf.conf:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo pfctl -e\nsudo pfctl -f \/etc\/pf.conf\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>That\u2019s it! It can be satisfying to login and print out the content of the PF fail2ban table and see the blocked IP addresses. Also, fewer spikes in the log monitoring of failed logins.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is not my article. I found a link to the original article on a Reddit post: https:\/\/www.reddit.com\/r\/openbsd\/comments\/5e6u61\/fail2ban_on_openbsd_60\/ The page no-longer exists. I dug up an old copy of the page from the Internet Archive Wayback Machine. The original article was found here: https:\/\/blog.gordonturner.com\/2016\/11\/20\/fail2ban-on-openbsd-6-0\/ Gordon, if this is your article, please forgive the reprint. If you have ever had a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-285","post","type-post","status-publish","format-standard","hentry","category-misc"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/posts\/285","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/comments?post=285"}],"version-history":[{"count":2,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/posts\/285\/revisions"}],"predecessor-version":[{"id":287,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/posts\/285\/revisions\/287"}],"wp:attachment":[{"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/media?parent=285"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/categories?post=285"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/tags?post=285"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}