<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Fail2ban on Chanyeol Dev</title>
    <link>https://chanyeols.com/tags/fail2ban/</link>
    <description>Recent content in Fail2ban on Chanyeol Dev</description>
    <generator>Hugo</generator>
    <language>ko-kr</language>
    <lastBuildDate>Mon, 30 Mar 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://chanyeols.com/tags/fail2ban/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>노트북으로 홈서버 구축하기 - Fail2ban으로 SSH 브루트포스 공격 차단하기 (8편)</title>
      <link>https://chanyeols.com/posts/part-08-fail2ban/</link>
      <pubDate>Mon, 30 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://chanyeols.com/posts/part-08-fail2ban/</guid>
      <description>OCI 서버 auth.log를 열어보니 수천 줄의 SSH 로그인 시도가 쌓여 있었다. Fail2ban을 설치해서 브루트포스 공격을 자동으로 차단하는 과정을 정리합니다.</description>
      <content:encoded><![CDATA[<h2 id="얼마나-많이-들어오나">얼마나 많이 들어오나</h2>
<p>OCI 서버는 공인 IP가 직접 노출돼 있어서 설치 직후부터 SSH 로그인 시도가 들어온다. auth.log를 열어봤다가 깜짝 놀랐다.</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo grep <span style="color:#a5d6ff">&#34;Failed password&#34;</span> /var/log/auth.log | tail -20
</span></span></code></pre></div><p><img alt="auth.log에 Invalid user 로그가 수천 줄 쌓인 화면" loading="lazy" src="/images/homeserver-08-authlog.png"></p>
<p><code>Invalid user admin</code>, <code>Invalid user guest</code>, <code>Invalid user root</code> 같은 로그가 수분 간격으로 끊임없이 들어오고 있었다. 전 세계 봇들이 24시간 SSH 로그인을 시도하는 것이다. 방치하면 언젠가 뚫릴 수 있고, 서버 리소스도 낭비된다.</p>
<hr>
<h2 id="fail2ban이란">Fail2ban이란?</h2>
<p>로그 파일을 모니터링하다가 일정 횟수 이상 로그인에 실패한 IP를 자동으로 방화벽에서 차단하는 도구다.</p>
<ul>
<li>설치만 해도 SSH 기본 보호 즉시 적용</li>
<li>iptables와 연동해서 IP 차단</li>
<li>일정 시간 후 자동으로 차단 해제</li>
<li>SSH 외에도 Nginx, Apache 등 다양한 서비스 보호 가능</li>
</ul>
<hr>
<h2 id="설치">설치</h2>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo apt install fail2ban -y
</span></span><span style="display:flex;"><span>sudo systemctl enable fail2ban
</span></span><span style="display:flex;"><span>sudo systemctl start fail2ban
</span></span><span style="display:flex;"><span>sudo systemctl status fail2ban
</span></span></code></pre></div><p><img alt="fail2ban active (running) 상태" loading="lazy" src="/images/homeserver-08-fail2ban-status.png"></p>
<p>설치 직후부터 기본 SSH 보호가 바로 적용된다.</p>
<hr>
<h2 id="설정">설정</h2>
<p>Fail2ban 기본 설정은 <code>/etc/fail2ban/jail.conf</code>에 있지만 이 파일은 직접 수정하지 않는다. 업데이트 시 덮어씌워질 수 있기 때문이다. 대신 <code>jail.local</code>을 만들어서 오버라이드한다.</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo vi /etc/fail2ban/jail.local
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-plain" data-lang="plain"><span style="display:flex;"><span>[DEFAULT]
</span></span><span style="display:flex;"><span># 차단에서 제외할 IP (내 Tailscale IP 등)
</span></span><span style="display:flex;"><span>ignoreip = 127.0.0.1/8 ::1
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># 차단 지속 시간: 기본 10분 → 1시간
</span></span><span style="display:flex;"><span>bantime = 3600
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># 몇 초 동안 실패 횟수를 카운트할지
</span></span><span style="display:flex;"><span>findtime = 600
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># 몇 번 실패하면 차단할지
</span></span><span style="display:flex;"><span>maxretry = 5
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[sshd]
</span></span><span style="display:flex;"><span>enabled = true
</span></span><span style="display:flex;"><span>port = ssh
</span></span><span style="display:flex;"><span>logpath = %(sshd_log)s
</span></span><span style="display:flex;"><span>backend = %(sshd_backend)s
</span></span></code></pre></div><table>
  <thead>
      <tr>
          <th>항목</th>
          <th>기본값</th>
          <th>변경값</th>
          <th>설명</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>bantime</td>
          <td>600초</td>
          <td>3600초</td>
          <td>차단 지속 시간</td>
      </tr>
      <tr>
          <td>findtime</td>
          <td>600초</td>
          <td>600초</td>
          <td>실패 횟수 카운트 기간</td>
      </tr>
      <tr>
          <td>maxretry</td>
          <td>5회</td>
          <td>5회</td>
          <td>차단 기준 실패 횟수</td>
      </tr>
  </tbody>
</table>
<p>설정 적용:</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo systemctl restart fail2ban
</span></span></code></pre></div><blockquote>
<p>⚠️ 설정 전에 반드시 자신의 IP를 <code>ignoreip</code>에 추가해둘 것. 실수로 자신의 IP가 차단되면 SSH 접속이 불가능해진다.</p>
</blockquote>
<hr>
<h2 id="반복-공격자-장기-차단-recidive">반복 공격자 장기 차단 (recidive)</h2>
<p>같은 IP가 여러 번 차단됐다 풀리면 또 시도하는 경우가 있다. <code>recidive</code> jail을 활성화하면 반복 공격자를 장기간 차단할 수 있다.</p>
<p><code>jail.local</code>에 추가:</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-plain" data-lang="plain"><span style="display:flex;"><span>[recidive]
</span></span><span style="display:flex;"><span>enabled = true
</span></span><span style="display:flex;"><span>logpath = /var/log/fail2ban.log
</span></span><span style="display:flex;"><span>banaction = %(banaction_allports)s
</span></span><span style="display:flex;"><span>bantime = 604800   ; 7일
</span></span><span style="display:flex;"><span>findtime = 86400   ; 1일
</span></span><span style="display:flex;"><span>maxretry = 3       ; 하루에 3번 차단되면 7일 차단
</span></span></code></pre></div><hr>
<h2 id="nginx-보호">Nginx 보호</h2>
<p>OCI에서 Nginx 리버스 프록시를 운영하고 있으니 HTTP 레벨 공격도 막을 수 있다.</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-plain" data-lang="plain"><span style="display:flex;"><span>[nginx-http-auth]
</span></span><span style="display:flex;"><span>enabled = true
</span></span><span style="display:flex;"><span>port = http,https
</span></span><span style="display:flex;"><span>logpath = /var/log/nginx/error.log
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[nginx-botsearch]
</span></span><span style="display:flex;"><span>enabled = true
</span></span><span style="display:flex;"><span>port = http,https
</span></span><span style="display:flex;"><span>logpath = /var/log/nginx/access.log
</span></span><span style="display:flex;"><span>maxretry = 2
</span></span></code></pre></div><hr>
<h2 id="차단-현황-확인">차단 현황 확인</h2>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 전체 jail 상태</span>
</span></span><span style="display:flex;"><span>sudo fail2ban-client status
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># SSH jail 상세</span>
</span></span><span style="display:flex;"><span>sudo fail2ban-client status sshd
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-plain" data-lang="plain"><span style="display:flex;"><span>Status for the jail: sshd
</span></span><span style="display:flex;"><span>|- Filter
</span></span><span style="display:flex;"><span>|  |- Currently failed: 3
</span></span><span style="display:flex;"><span>|  |- Total failed:     1284
</span></span><span style="display:flex;"><span>|  `- File list:        /var/log/auth.log
</span></span><span style="display:flex;"><span>`- Actions
</span></span><span style="display:flex;"><span>   |- Currently banned: 12
</span></span><span style="display:flex;"><span>   |- Total banned:     87
</span></span><span style="display:flex;"><span>   `- Banned IP list:   185.156.73.233 139.19.117.130 ...
</span></span></code></pre></div><p><img alt="fail2ban-client status sshd 결과" loading="lazy" src="/images/homeserver-08-fail2ban-status-sshd.png"></p>
<p>실시간 로그 확인:</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo tail -f /var/log/fail2ban.log
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-plain" data-lang="plain"><span style="display:flex;"><span>2026-03-29 22:48:33 INFO [sshd] Ban 193.46.255.86
</span></span><span style="display:flex;"><span>2026-03-29 22:52:33 INFO [sshd] Ban 185.156.73.233
</span></span><span style="display:flex;"><span>2026-03-29 23:01:15 INFO [sshd] Ban 139.19.117.130
</span></span></code></pre></div><hr>
<h2 id="ip-수동-차단해제">IP 수동 차단/해제</h2>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 수동 차단</span>
</span></span><span style="display:flex;"><span>sudo fail2ban-client set sshd banip 1.2.3.4
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 차단 해제 (내 IP 실수로 차단됐을 때)</span>
</span></span><span style="display:flex;"><span>sudo fail2ban-client set sshd unbanip 1.2.3.4
</span></span></code></pre></div><hr>
<h2 id="차단-목록-확인">차단 목록 확인</h2>
<p>이후 시간이 조금 지나고 확인해보니, 정상적으로 잘 차단하고 있는 걸 확인할 수 있다.
<img alt="fail2ban-client log 결과" loading="lazy" src="/images/homeserver-08-fail2ban-log.png"></p>
<h2 id="설치-전후-비교">설치 전후 비교</h2>
<table>
  <thead>
      <tr>
          <th></th>
          <th>설치 전</th>
          <th>설치 후</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>auth.log</td>
          <td>Failed password 수천 줄</td>
          <td>차단된 IP는 시도 자체가 안 됨</td>
      </tr>
      <tr>
          <td>서버 부하</td>
          <td>SSH 시도로 인한 불필요한 부하</td>
          <td>최소화</td>
      </tr>
      <tr>
          <td>보안</td>
          <td>브루트포스 공격에 노출</td>
          <td>자동 차단</td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="정리">정리</h2>
<p>클라우드 서버를 운영한다면 Fail2ban은 선택이 아니라 필수다. 설치 자체는 5분이면 되고, 기본 설정만으로도 대부분의 브루트포스 공격을 막을 수 있다. <code>recidive</code> jail까지 설정해두면 반복 공격자를 장기간 차단해서 더욱 안전하게 운영할 수 있다.</p>
<p>다음 편에서는 서비스가 늘어나면서 기존 SSL 인증서에 서브도메인을 추가하는 방법을 다룬다.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
