<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://tcp-80.net/feed.xml" rel="self" type="application/atom+xml" /><link href="https://tcp-80.net/" rel="alternate" type="text/html" hreflang="ko" /><updated>2026-05-09T01:47:11+09:00</updated><id>https://tcp-80.net/feed.xml</id><title type="html">TCP-80.NET — 일본 서버 호스팅</title><subtitle>일본 도쿄 데이터센터 직영. 전용서버·가상서버(VPS)·가상데스크톱·DDoS/해킹 보안 서비스를 합리적인 가격으로 제공합니다. 24시간 한국어 지원.</subtitle><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><entry><title type="html">Linux 커널 네트워크 튜닝 — sysctl로 일본 서버 처리량 끌어올리기</title><link href="https://tcp-80.net/blog/2026/05/06/japan-server-linux-kernel-network-tuning/" rel="alternate" type="text/html" title="Linux 커널 네트워크 튜닝 — sysctl로 일본 서버 처리량 끌어올리기" /><published>2026-05-06T00:00:00+09:00</published><updated>2026-05-06T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/05/06/japan-server-linux-kernel-network-tuning</id><content type="html" xml:base="https://tcp-80.net/blog/2026/05/06/japan-server-linux-kernel-network-tuning/"><![CDATA[<p>웹서버 5,000 연결까지는 잘 받다가 그 이상에서 갑자기 멈추는 경험이 있었다면, 거의 모든 경우 <strong>커널의 기본값</strong>이 원인입니다. Linux는 데스크톱부터 서버까지 폭넓게 쓰이도록 보수적인 기본값을 설정해두는데, 일본 IDC의 고성능 서버에서는 이 값을 풀어줘야 본래 처리량이 나옵니다.</p>

<p><img src="/assets/img/posts/2026-05-06/sysctl-network-tuning.svg" alt="Linux 네트워크 스택과 sysctl 튜닝 포인트" /></p>

<hr />

<h2 id="어디부터-봐야-할까">어디부터 봐야 할까</h2>

<p>네트워크 패킷이 서버에 도달해서 애플리케이션까지 가는 경로는 4계층입니다.</p>

<table>
  <thead>
    <tr>
      <th>계층</th>
      <th>병목 발생 시 증상</th>
      <th>핵심 파라미터</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>NIC</td>
      <td>패킷 드롭, RX/TX 카운터 증가</td>
      <td>ring buffer, RSS 큐</td>
    </tr>
    <tr>
      <td>커널 TCP/IP</td>
      <td>accept 큐 풀, conntrack 가득</td>
      <td>somaxconn, conntrack_max</td>
    </tr>
    <tr>
      <td>연결 관리</td>
      <td>TIME_WAIT 누적, 임시 포트 고갈</td>
      <td>tcp_tw_reuse, port_range</td>
    </tr>
    <tr>
      <td>애플리케이션</td>
      <td>워커 부족, 파일 디스크립터 부족</td>
      <td>nofile, worker_connections</td>
    </tr>
  </tbody>
</table>

<p>이 글에서는 가운데 두 계층을 중심으로, 안전한 값을 제시합니다.</p>

<hr />

<h2 id="1단계--현재-상태-진단">1단계 — 현재 상태 진단</h2>

<p>설정을 만지기 전에 <strong>무엇이 부족한지</strong> 확인합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 패킷 드롭 발생 여부</span>
ip <span class="nt">-s</span> <span class="nb">link </span>show eth0 | <span class="nb">grep</span> <span class="nt">-A1</span> RX
netstat <span class="nt">-s</span> | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"drop|overflow"</span>

<span class="c"># accept 큐 오버플로</span>
ss <span class="nt">-s</span>
nstat <span class="nt">-a</span> | <span class="nb">grep</span> <span class="nt">-i</span> listen

<span class="c"># conntrack 사용량</span>
<span class="nb">cat</span> /proc/sys/net/netfilter/nf_conntrack_count
<span class="nb">cat</span> /proc/sys/net/netfilter/nf_conntrack_max

<span class="c"># TIME_WAIT 개수</span>
ss <span class="nt">-tan</span> | <span class="nb">awk</span> <span class="s1">'{print $1}'</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
</code></pre></div></div>

<p>“ListenOverflows”나 “drops” 카운터가 증가 중이라면 그 부분의 튜닝이 필요합니다. 모든 카운터가 0이고 처리량이 부족하다면 NIC나 애플리케이션 쪽을 봐야 합니다.</p>

<hr />

<h2 id="2단계--tcp-백로그--accept-큐">2단계 — TCP 백로그 / accept 큐</h2>

<p><code class="language-plaintext highlighter-rouge">somaxconn</code>은 <strong>수락(accept) 대기 큐</strong>의 최대 크기입니다. 기본값 4096이 작아 보이지 않지만, Nginx의 <code class="language-plaintext highlighter-rouge">listen ... backlog=</code>도 이 값에 의해 제한되므로 실제론 자주 부족합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/sysctl.d/99-network-tune.conf</span>
<span class="c"># accept 대기 큐</span>
net.core.somaxconn <span class="o">=</span> 8192

<span class="c"># SYN 백로그</span>
net.ipv4.tcp_max_syn_backlog <span class="o">=</span> 8192

<span class="c"># 연결 추적 테이블</span>
net.netfilter.nf_conntrack_max <span class="o">=</span> 1048576
net.netfilter.nf_conntrack_buckets <span class="o">=</span> 262144
</code></pre></div></div>

<p>Nginx 측에서도 <code class="language-plaintext highlighter-rouge">listen 80 backlog=8192;</code> 처럼 함께 명시해야 의미가 있습니다.</p>

<hr />

<h2 id="3단계--time_wait와-임시-포트">3단계 — TIME_WAIT와 임시 포트</h2>

<p>높은 동시 연결, 짧은 keep-alive 환경에서는 TIME_WAIT 상태 소켓이 빠르게 누적됩니다. 임시 포트가 고갈되면 새 연결이 안 됩니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># TIME_WAIT 재사용 (NAT 환경에서도 안전)</span>
net.ipv4.tcp_tw_reuse <span class="o">=</span> 1

<span class="c"># FIN_WAIT 짧게</span>
net.ipv4.tcp_fin_timeout <span class="o">=</span> 15

<span class="c"># 임시 포트 범위 확장</span>
net.ipv4.ip_local_port_range <span class="o">=</span> 10240 65535
</code></pre></div></div>

<p><strong>⚠️ 사용 금지</strong></p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">net.ipv4.tcp_tw_recycle</code> — 4.12 커널에서 제거됨. NAT 환경에서 연결 실패의 원인이 됩니다.</li>
</ul>

<hr />

<h2 id="4단계--송수신-버퍼">4단계 — 송수신 버퍼</h2>

<p>긴 RTT(예: 글로벌 사용자) 환경에서 처리량이 잘 안 나온다면 버퍼 크기가 작은 것일 수 있습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 최대 소켓 버퍼 (16MB)</span>
net.core.rmem_max <span class="o">=</span> 16777216
net.core.wmem_max <span class="o">=</span> 16777216

<span class="c"># TCP 자동 튜닝 한계</span>
net.ipv4.tcp_rmem <span class="o">=</span> 4096 87380 16777216
net.ipv4.tcp_wmem <span class="o">=</span> 4096 65536 16777216

<span class="c"># 백로그 큐 (소프트IRQ가 처리 못한 패킷)</span>
net.core.netdev_max_backlog <span class="o">=</span> 5000
</code></pre></div></div>

<p>대역폭 곱 RTT(BDP)가 8MB를 넘는 경우(예: 100Mbps × 100ms RTT = 1.25MB는 OK이지만 1Gbps × 100ms = 12MB)에는 위 16MB로도 부족할 수 있습니다.</p>

<hr />

<h2 id="5단계--혼잡-제어-알고리즘-bbr">5단계 — 혼잡 제어 알고리즘 (BBR)</h2>

<p>BBR은 패킷 손실이 아니라 <strong>대역폭과 RTT 측정</strong>으로 혼잡을 판단합니다. 한국-일본처럼 짧은 RTT, 또는 글로벌 긴 경로 양쪽 모두에서 cubic 대비 좋은 결과를 보이는 경우가 많습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>net.core.default_qdisc <span class="o">=</span> fq
net.ipv4.tcp_congestion_control <span class="o">=</span> bbr
</code></pre></div></div>

<p>활성 후 확인:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysctl net.ipv4.tcp_congestion_control
<span class="c"># net.ipv4.tcp_congestion_control = bbr</span>
</code></pre></div></div>

<hr />

<h2 id="6단계--keepalive-짧게">6단계 — keepalive 짧게</h2>

<p>방화벽이나 LB가 idle 연결을 끊는 환경에서는 keepalive를 짧게 잡아 미리 dead connection을 정리합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>net.ipv4.tcp_keepalive_time <span class="o">=</span> 600    <span class="c"># 10분 (기본 7200초 = 2시간)</span>
net.ipv4.tcp_keepalive_intvl <span class="o">=</span> 60
net.ipv4.tcp_keepalive_probes <span class="o">=</span> 3
</code></pre></div></div>

<hr />

<h2 id="7단계--syn-flood--보안-관련">7단계 — SYN Flood / 보안 관련</h2>

<p>DDoS 환경에서 동작하는 서버라면 다음 값을 함께 설정합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SYN Cookie (메모리 고갈 방어)</span>
net.ipv4.tcp_syncookies <span class="o">=</span> 1
net.ipv4.tcp_synack_retries <span class="o">=</span> 2

<span class="c"># 비정상 패킷 무시</span>
net.ipv4.conf.all.accept_source_route <span class="o">=</span> 0
net.ipv4.conf.default.accept_source_route <span class="o">=</span> 0

<span class="c"># IP 스푸핑 방어 (Reverse Path Filter)</span>
net.ipv4.conf.all.rp_filter <span class="o">=</span> 1
net.ipv4.conf.default.rp_filter <span class="o">=</span> 1

<span class="c"># ICMP redirect 무시</span>
net.ipv4.conf.all.accept_redirects <span class="o">=</span> 0
net.ipv4.conf.default.accept_redirects <span class="o">=</span> 0
</code></pre></div></div>

<p>DDoS 방어 원리에 대한 더 자세한 설명은 <a href="/blog/2026/04/07/ddos-defense-principles/">이 글</a>을 참고하세요.</p>

<hr />

<h2 id="8단계--애플리케이션-한계-nofile">8단계 — 애플리케이션 한계 (nofile)</h2>

<p>sysctl만 풀어도 애플리케이션 한계가 그대로면 의미가 없습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/security/limits.conf</span>
<span class="k">*</span>    soft  nofile  1048576
<span class="k">*</span>    hard  nofile  1048576
root soft  nofile  1048576
root hard  nofile  1048576
</code></pre></div></div>

<p>systemd 서비스 단위로도 적용:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/systemd/system/nginx.service.d/override.conf
</span><span class="nn">[Service]</span><span class="w">
</span><span class="py">LimitNOFILE</span><span class="p">=</span><span class="s">1048576</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl daemon-reload
<span class="nb">sudo </span>systemctl restart nginx
</code></pre></div></div>

<p>확인:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> /proc/<span class="si">$(</span>pidof nginx<span class="si">)</span>/limits | <span class="nb">grep</span> <span class="s2">"open files"</span>
</code></pre></div></div>

<hr />

<h2 id="한-번에-적용하는-권장-프로필">한 번에 적용하는 권장 프로필</h2>

<p>웹/API 서버의 무난한 시작점입니다. 워크로드에 따라 추가 조정이 필요합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/sysctl.d/99-server-tune.conf</span>
<span class="c"># === 백로그 / 큐 ===</span>
net.core.somaxconn <span class="o">=</span> 8192
net.core.netdev_max_backlog <span class="o">=</span> 5000
net.ipv4.tcp_max_syn_backlog <span class="o">=</span> 8192

<span class="c"># === TIME_WAIT / 포트 ===</span>
net.ipv4.tcp_tw_reuse <span class="o">=</span> 1
net.ipv4.tcp_fin_timeout <span class="o">=</span> 15
net.ipv4.ip_local_port_range <span class="o">=</span> 10240 65535

<span class="c"># === 버퍼 ===</span>
net.core.rmem_max <span class="o">=</span> 16777216
net.core.wmem_max <span class="o">=</span> 16777216
net.ipv4.tcp_rmem <span class="o">=</span> 4096 87380 16777216
net.ipv4.tcp_wmem <span class="o">=</span> 4096 65536 16777216

<span class="c"># === 혼잡 제어 ===</span>
net.core.default_qdisc <span class="o">=</span> fq
net.ipv4.tcp_congestion_control <span class="o">=</span> bbr

<span class="c"># === keepalive ===</span>
net.ipv4.tcp_keepalive_time <span class="o">=</span> 600
net.ipv4.tcp_keepalive_intvl <span class="o">=</span> 60
net.ipv4.tcp_keepalive_probes <span class="o">=</span> 3

<span class="c"># === conntrack ===</span>
net.netfilter.nf_conntrack_max <span class="o">=</span> 1048576

<span class="c"># === 보안 ===</span>
net.ipv4.tcp_syncookies <span class="o">=</span> 1
net.ipv4.conf.all.rp_filter <span class="o">=</span> 1
net.ipv4.conf.all.accept_redirects <span class="o">=</span> 0
net.ipv4.conf.all.accept_source_route <span class="o">=</span> 0
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>sysctl <span class="nt">--system</span>
<span class="nb">sudo </span>sysctl <span class="nt">-p</span> /etc/sysctl.d/99-server-tune.conf
</code></pre></div></div>

<hr />

<h2 id="안전한-적용-절차">안전한 적용 절차</h2>

<p>운영 서버에 한 번에 적용하지 마세요. 다음 절차를 권장합니다.</p>

<ol>
  <li><strong>개발/스테이징 서버에서 먼저</strong> 동일 워크로드로 부하 테스트(wrk, k6 등)</li>
  <li><strong>변경 전후 지표</strong> 비교 — RPS, 응답 시간, CPU, 메모리, 패킷 드롭</li>
  <li><strong>운영 서버에 점진 적용</strong> — 한 번에 한두 항목씩, 24시간 관찰</li>
  <li><strong>롤백 계획 준비</strong> — 적용한 파일을 <code class="language-plaintext highlighter-rouge">.disabled</code>로 바꾸면 다음 부팅 시 무효화됨</li>
</ol>

<p>운영 중 적용은 그라데이션이 핵심입니다. 일이 잘못되면 새벽 3시에 누군가 깨어나야 하므로 <strong>느려도 안전한</strong> 방법을 택하세요.</p>

<hr />

<h2 id="측정-도구">측정 도구</h2>

<p>튜닝 효과는 반드시 숫자로 확인해야 합니다.</p>

<table>
  <thead>
    <tr>
      <th>도구</th>
      <th>용도</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">wrk</code> / <code class="language-plaintext highlighter-rouge">wrk2</code></td>
      <td>HTTP 부하 생성</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k6</code></td>
      <td>시나리오 기반 부하 테스트</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">iperf3</code></td>
      <td>순수 네트워크 처리량 측정</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">mpstat</code> / <code class="language-plaintext highlighter-rouge">pidstat</code></td>
      <td>CPU·프로세스별 부하</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ss -s</code></td>
      <td>소켓 통계 요약</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">nstat -a</code></td>
      <td>모든 카운터 dump</td>
    </tr>
  </tbody>
</table>

<p>전체적인 모니터링 구성은 <a href="/blog/2026/02/23/japan-server-monitoring-guide/">Netdata 가이드</a>에 정리해두었습니다.</p>

<hr />

<h2 id="마무리">마무리</h2>

<p>커널 튜닝은 “블랙박스에서 손가락 굴리는” 작업이 아니라, 카운터 → 가설 → 측정 → 적용의 루프입니다. 위 권장 프로필을 그대로 가져가도 안전하지만, <strong>패킷 드롭이나 백로그 오버플로 카운터가 증가하지 않는다면</strong> 굳이 만질 필요가 없는 경우가 많습니다.</p>

<p>TCP-80.NET의 <a href="https://tcp-80.net/dedicated-server/">전용서버</a>는 NIC 인터럽트 분산까지 사전 설정해 출고합니다. 추가 튜닝에 대한 문의는 <a href="https://t.me/tcp80net">@tcp80net</a>으로 부탁드립니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[같은 하드웨어에서 두 배의 동시 연결을 받으려면 커널 설정부터 봐야 합니다. somaxconn, tcp_tw_reuse, conntrack, BBR 등 sysctl 핵심 파라미터를 NIC부터 애플리케이션까지 계층별로 정리하고, 안전한 적용 절차를 안내합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">HTTPS 보안 헤더 완전 가이드 — HSTS, CSP, X-Frame-Options 설정</title><link href="https://tcp-80.net/blog/2026/05/03/japan-server-https-security-headers/" rel="alternate" type="text/html" title="HTTPS 보안 헤더 완전 가이드 — HSTS, CSP, X-Frame-Options 설정" /><published>2026-05-03T00:00:00+09:00</published><updated>2026-05-03T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/05/03/japan-server-https-security-headers</id><content type="html" xml:base="https://tcp-80.net/blog/2026/05/03/japan-server-https-security-headers/"><![CDATA[<p><a href="https://www.ssllabs.com/ssltest/">https://www.ssllabs.com/ssltest/</a>에서 자기 사이트를 테스트해 보면 SSL 자체는 A이지만 <strong>헤더 설정 부족으로 등급이 깎이는 경우</strong>가 흔합니다. 헤더는 응답 한 줄을 추가하는 것이 전부인데, XSS, 클릭재킹, MITM 다운그레이드 공격을 한 번에 차단해줍니다.</p>

<hr />

<h2 id="한눈에-보는-핵심-헤더">한눈에 보는 핵심 헤더</h2>

<table>
  <thead>
    <tr>
      <th>헤더</th>
      <th>차단하는 공격</th>
      <th>우선순위</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Strict-Transport-Security</code></td>
      <td>HTTP 다운그레이드 / 중간자</td>
      <td>필수</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Content-Security-Policy</code></td>
      <td>XSS / 데이터 인젝션</td>
      <td>필수</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X-Content-Type-Options</code></td>
      <td>MIME 스니핑</td>
      <td>필수</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X-Frame-Options</code></td>
      <td>클릭재킹</td>
      <td>필수</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Referrer-Policy</code></td>
      <td>레퍼러 정보 누출</td>
      <td>권장</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Permissions-Policy</code></td>
      <td>브라우저 기능 무단 사용</td>
      <td>권장</td>
    </tr>
  </tbody>
</table>

<p>가장 먼저 추가해야 하는 것은 위 4개의 “필수” 헤더입니다.</p>

<hr />

<h2 id="1-hsts-strict-transport-security">1. HSTS (Strict-Transport-Security)</h2>

<p>브라우저가 <strong>이 도메인은 절대 HTTP로 접근하지 말라</strong>고 기억하게 만듭니다. SSL Strip 같은 다운그레이드 공격을 무력화합니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">add_header</span> <span class="s">Strict-Transport-Security</span> <span class="s">"max-age=31536000</span><span class="p">;</span> <span class="k">includeSubDomains</span><span class="p">;</span> <span class="k">preload"</span> <span class="s">always</span><span class="p">;</span>
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">max-age=31536000</code> — 1년간 유지</li>
  <li><code class="language-plaintext highlighter-rouge">includeSubDomains</code> — 모든 서브도메인에 동일 적용</li>
  <li><code class="language-plaintext highlighter-rouge">preload</code> — 브라우저 빌트인 목록(HSTS Preload)에 등재 신청용</li>
</ul>

<p><strong>주의:</strong> HSTS는 <strong>신중히</strong> 적용해야 합니다. 한 번 적용되면 만료 전까지 HTTP로 절대 접근할 수 없습니다. 인증서 갱신 실패나 서브도메인 중 HTTP만 쓰는 게 있다면 사이트 전체가 차단됩니다.</p>

<p>도입 절차:</p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">max-age=600</code> (10분)로 시작 → 며칠 운영</li>
  <li><code class="language-plaintext highlighter-rouge">max-age=86400</code> (1일) → 1주 관찰</li>
  <li><code class="language-plaintext highlighter-rouge">max-age=31536000</code> (1년)으로 강화</li>
  <li>(선택) <a href="https://hstspreload.org/">hstspreload.org</a>에 등록</li>
</ol>

<hr />

<h2 id="2-content-security-policy-csp">2. Content-Security-Policy (CSP)</h2>

<p>페이지에서 <strong>로드 가능한 리소스의 출처</strong>를 제한합니다. XSS 공격이 성공해도 외부로 데이터를 빼돌리거나 외부 스크립트를 실행하기 어렵게 만듭니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">add_header</span> <span class="s">Content-Security-Policy</span> <span class="s">"default-src</span> <span class="s">'self'</span><span class="p">;</span> <span class="k">script-src</span> <span class="s">'self'</span> <span class="s">https://cdn.jsdelivr.net</span><span class="p">;</span> <span class="k">style-src</span> <span class="s">'self'</span> <span class="s">'unsafe-inline'</span> <span class="s">https://fonts.googleapis.com</span><span class="p">;</span> <span class="k">font-src</span> <span class="s">'self'</span> <span class="s">https://fonts.gstatic.com</span><span class="p">;</span> <span class="k">img-src</span> <span class="s">'self'</span> <span class="s">data:</span> <span class="s">https:</span><span class="p">;</span> <span class="k">connect-src</span> <span class="s">'self'</span> <span class="s">https://api.example.com</span><span class="p">;</span> <span class="k">frame-ancestors</span> <span class="s">'none'</span><span class="p">;</span> <span class="k">base-uri</span> <span class="s">'self'</span><span class="p">;</span> <span class="k">form-action</span> <span class="s">'self'"</span> <span class="s">always</span><span class="p">;</span>
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>디렉티브</th>
      <th>의미</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">default-src 'self'</code></td>
      <td>기본은 같은 출처만 허용</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">script-src</code></td>
      <td>스크립트 출처 제한</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">style-src</code></td>
      <td>스타일시트 출처</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">img-src</code></td>
      <td>이미지 출처</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">connect-src</code></td>
      <td>XHR, fetch, WebSocket</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">frame-ancestors 'none'</code></td>
      <td>iframe 임베딩 차단 (X-Frame-Options 상위 호환)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">form-action 'self'</code></td>
      <td>폼 전송 대상 제한</td>
    </tr>
  </tbody>
</table>

<h3 id="csp-도입-절차">CSP 도입 절차</h3>

<p>기존 사이트에 갑자기 적용하면 정상 리소스까지 차단됩니다. 다음 순서로 도입하세요.</p>

<p><strong>1단계 — Report-Only 모드</strong> (차단 없이 위반 사항만 수집)</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">add_header</span> <span class="s">Content-Security-Policy-Report-Only</span> <span class="s">"default-src</span> <span class="s">'self'</span><span class="p">;</span> <span class="k">report-uri</span> <span class="n">/csp-report"</span> <span class="s">always</span><span class="p">;</span>
</code></pre></div></div>

<p>서버에서 <code class="language-plaintext highlighter-rouge">/csp-report</code> 엔드포인트를 만들어 위반 보고서를 수집·분석합니다.</p>

<p><strong>2단계</strong> — 위반 사항을 모두 정상화한 뒤 <code class="language-plaintext highlighter-rouge">Report-Only</code>를 떼고 일반 <code class="language-plaintext highlighter-rouge">CSP</code>로 전환합니다.</p>

<p><strong>3단계</strong> — <code class="language-plaintext highlighter-rouge">unsafe-inline</code>, <code class="language-plaintext highlighter-rouge">unsafe-eval</code>을 제거할 수 있도록 인라인 스크립트를 nonce/hash 방식으로 바꿉니다.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">nonce=</span><span class="s">"random123"</span><span class="nt">&gt;</span><span class="cm">/* 인라인 스크립트 */</span><span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>
<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">add_header</span> <span class="s">Content-Security-Policy</span> <span class="s">"script-src</span> <span class="s">'self'</span> <span class="s">'nonce-random123'"</span> <span class="s">always</span><span class="p">;</span>
</code></pre></div></div>

<hr />

<h2 id="3-x-content-type-options">3. X-Content-Type-Options</h2>

<p>브라우저가 응답의 <code class="language-plaintext highlighter-rouge">Content-Type</code>을 멋대로 추측(MIME sniffing)하지 못하게 합니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">add_header</span> <span class="s">X-Content-Type-Options</span> <span class="s">"nosniff"</span> <span class="s">always</span><span class="p">;</span>
</code></pre></div></div>

<p>이 한 줄만 추가하면 끝입니다. <strong>부작용 없이 무조건 추가</strong>하세요.</p>

<hr />

<h2 id="4-x-frame-options">4. X-Frame-Options</h2>

<p>다른 사이트가 우리 페이지를 iframe으로 감싸지 못하게 합니다(클릭재킹 방어).</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">add_header</span> <span class="s">X-Frame-Options</span> <span class="s">"SAMEORIGIN"</span> <span class="s">always</span><span class="p">;</span>
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>값</th>
      <th>의미</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DENY</code></td>
      <td>모든 iframe 거부</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SAMEORIGIN</code></td>
      <td>같은 출처만 허용</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ALLOW-FROM &lt;uri&gt;</code></td>
      <td>특정 사이트만 (현재는 비표준, CSP <code class="language-plaintext highlighter-rouge">frame-ancestors</code> 사용 권장)</td>
    </tr>
  </tbody>
</table>

<p>CSP <code class="language-plaintext highlighter-rouge">frame-ancestors</code>를 이미 설정했다면 X-Frame-Options는 옛 브라우저 호환용으로만 의미가 있습니다.</p>

<hr />

<h2 id="5-referrer-policy">5. Referrer-Policy</h2>

<p>다른 사이트로 이동할 때 어떤 레퍼러 정보를 노출할지 제어합니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">add_header</span> <span class="s">Referrer-Policy</span> <span class="s">"strict-origin-when-cross-origin"</span> <span class="s">always</span><span class="p">;</span>
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>값</th>
      <th>동작</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">no-referrer</code></td>
      <td>어떤 경우에도 레퍼러 안 보냄</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">same-origin</code></td>
      <td>같은 출처만</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">strict-origin-when-cross-origin</code></td>
      <td>권장 — 같은 출처는 전체, 외부는 도메인만, HTTPS→HTTP 다운그레이드 시 안 보냄</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">unsafe-url</code></td>
      <td>항상 전체 URL (비권장)</td>
    </tr>
  </tbody>
</table>

<p>특별한 이유가 없다면 <code class="language-plaintext highlighter-rouge">strict-origin-when-cross-origin</code>이 정답입니다.</p>

<hr />

<h2 id="6-permissions-policy">6. Permissions-Policy</h2>

<p>페이지가 카메라, 마이크, 위치, 결제 API 등을 사용할 권한을 명시합니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">add_header</span> <span class="s">Permissions-Policy</span> <span class="s">"geolocation=(),</span> <span class="s">microphone=(),</span> <span class="s">camera=(),</span> <span class="s">payment=(self)"</span> <span class="s">always</span><span class="p">;</span>
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">()</code> 빈 괄호 — 모든 출처 차단</li>
  <li><code class="language-plaintext highlighter-rouge">(self)</code> — 같은 출처만 허용</li>
  <li><code class="language-plaintext highlighter-rouge">(self "https://trusted.com")</code> — 특정 출처도 허용</li>
</ul>

<p>XSS가 성공해도 카메라·마이크 자동 켜기, 결제 API 무단 호출 등을 차단할 수 있습니다.</p>

<hr />

<h2 id="7-한-번에-적용하는-nginx-설정">7. 한 번에 적용하는 Nginx 설정</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/nginx/conf.d/security-headers.conf</code>로 분리해 모든 사이트에 include하면 관리가 편합니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/conf.d/security-headers.conf</span>
<span class="k">add_header</span> <span class="s">Strict-Transport-Security</span> <span class="s">"max-age=31536000</span><span class="p">;</span> <span class="k">includeSubDomains"</span> <span class="s">always</span><span class="p">;</span>
<span class="k">add_header</span> <span class="s">X-Content-Type-Options</span> <span class="s">"nosniff"</span> <span class="s">always</span><span class="p">;</span>
<span class="k">add_header</span> <span class="s">X-Frame-Options</span> <span class="s">"SAMEORIGIN"</span> <span class="s">always</span><span class="p">;</span>
<span class="k">add_header</span> <span class="s">Referrer-Policy</span> <span class="s">"strict-origin-when-cross-origin"</span> <span class="s">always</span><span class="p">;</span>
<span class="k">add_header</span> <span class="s">Permissions-Policy</span> <span class="s">"geolocation=(),</span> <span class="s">microphone=(),</span> <span class="s">camera=()"</span> <span class="s">always</span><span class="p">;</span>

<span class="c1"># CSP는 사이트마다 다르므로 server 블록에서 개별 적용</span>
</code></pre></div></div>

<p>서버 블록에서 사이트별로 CSP 추가:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span> <span class="s">http2</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">example.com</span><span class="p">;</span>

    <span class="kn">include</span> <span class="n">/etc/nginx/conf.d/security-headers.conf</span><span class="p">;</span>

    <span class="kn">add_header</span> <span class="s">Content-Security-Policy</span> <span class="s">"default-src</span> <span class="s">'self'</span><span class="p">;</span> <span class="kn">..."</span> <span class="s">always</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="8-검증">8. 검증</h2>

<p>설정을 적용한 뒤 다음 도구로 확인합니다.</p>

<ul>
  <li><a href="https://securityheaders.com">https://securityheaders.com</a> — A 등급이 목표</li>
  <li><a href="https://www.ssllabs.com/ssltest/">https://www.ssllabs.com/ssltest/</a> — A+ 등급이 목표</li>
  <li><a href="https://csp-evaluator.withgoogle.com">https://csp-evaluator.withgoogle.com</a> — CSP 정책 약점 검증</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 명령행에서 헤더만 확인</span>
curl <span class="nt">-I</span> https://example.com
</code></pre></div></div>

<hr />

<h2 id="흔한-실수">흔한 실수</h2>

<p><strong><code class="language-plaintext highlighter-rouge">always</code>를 빼먹는다</strong></p>
<ul>
  <li>Nginx의 <code class="language-plaintext highlighter-rouge">add_header</code>는 기본적으로 2xx, 3xx 응답에만 적용됩니다. 404, 500 같은 에러 페이지에도 헤더가 붙으려면 <code class="language-plaintext highlighter-rouge">always</code>가 필수입니다.</li>
</ul>

<p><strong><code class="language-plaintext highlighter-rouge">add_header</code>가 server 블록과 location 블록에 섞여 있을 때</strong></p>
<ul>
  <li>location 블록에 <code class="language-plaintext highlighter-rouge">add_header</code>가 하나라도 있으면 server 블록의 <code class="language-plaintext highlighter-rouge">add_header</code>는 <strong>덮어쓰여 사라집니다</strong>(상속 안 됨). location에서도 모든 헤더를 다시 명시하거나, location에서는 <code class="language-plaintext highlighter-rouge">add_header</code>를 쓰지 않는 것이 안전합니다.</li>
</ul>

<p><strong>CSP의 <code class="language-plaintext highlighter-rouge">unsafe-inline</code>을 영원히 두는 경우</strong></p>
<ul>
  <li>처음에는 어쩔 수 없지만, nonce/hash로 옮기면 XSS 방어 효과가 비교할 수 없이 커집니다. 우선순위를 두고 단계적으로 제거하세요.</li>
</ul>

<p><strong>HSTS를 처음부터 1년으로 적용</strong></p>
<ul>
  <li>인증서 갱신 실패 시 사이트가 1년간 접근 불가가 됩니다. 짧게 시작 → 점진적으로 늘리세요.</li>
</ul>

<hr />

<h2 id="마무리">마무리</h2>

<p>보안 헤더는 추가 비용도, 성능 저하도 거의 없는 보안 강화 수단입니다. SSL 인증서를 발급한 다음 단계로 반드시 적용해야 합니다.</p>

<p>TCP-80.NET의 <a href="https://tcp-80.net/virtual-server/">VPS</a> / <a href="https://tcp-80.net/dedicated-server/">전용서버</a>에서 Nginx 보안 설정 중 막히는 부분이 있으면 <a href="https://t.me/tcp80net">@tcp80net</a>으로 한국어 문의 가능합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="보안" /><summary type="html"><![CDATA[SSL 인증서만 설치하면 끝이 아닙니다. HSTS, CSP, X-Frame-Options, Referrer-Policy 등 응답 헤더는 추가 비용 없이 보안 등급을 한 단계 올려줍니다. Nginx 기준 실전 설정과 단계별 강화 전략을 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-security.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-security.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Blue-Green 무중단 배포 — 일본 서버에서 다운타임 0초로 배포하기</title><link href="https://tcp-80.net/blog/2026/04/30/japan-server-blue-green-deployment/" rel="alternate" type="text/html" title="Blue-Green 무중단 배포 — 일본 서버에서 다운타임 0초로 배포하기" /><published>2026-04-30T00:00:00+09:00</published><updated>2026-04-30T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/04/30/japan-server-blue-green-deployment</id><content type="html" xml:base="https://tcp-80.net/blog/2026/04/30/japan-server-blue-green-deployment/"><![CDATA[<p>배포할 때 잠깐이라도 서비스가 멈추면 사용자는 곧장 알아챕니다. 특히 결제, 게임, 실시간 서비스라면 단 몇 초의 다운타임도 비즈니스에 영향을 줍니다. <strong>Blue-Green 배포</strong>는 두 개의 동일한 환경을 운영하면서 트래픽을 한 번에 전환하는 가장 단순하고 검증된 무중단 배포 패턴입니다.</p>

<p><img src="/assets/img/posts/2026-04-30/blue-green-deploy.svg" alt="Blue-Green 무중단 배포" /></p>

<hr />

<h2 id="핵심-아이디어">핵심 아이디어</h2>

<table>
  <thead>
    <tr>
      <th>환경</th>
      <th>역할</th>
      <th>사용자 트래픽</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Blue</td>
      <td>현재 운영 (v1.0)</td>
      <td>100% 수신</td>
    </tr>
    <tr>
      <td>Green</td>
      <td>다음 버전 (v1.1) 대기</td>
      <td>0% — 검증만</td>
    </tr>
  </tbody>
</table>

<p>배포 절차:</p>
<ol>
  <li>Green에 신규 버전을 배포</li>
  <li>Green이 정상 동작하는지 헬스체크</li>
  <li>로드밸런서/프록시 설정만 변경 → 트래픽이 Green으로 전환</li>
  <li>Blue는 즉시 폐기하지 않고, 문제 발생 시 즉시 롤백 가능한 상태로 유지</li>
</ol>

<p>핵심은 <strong>트래픽 전환이 단일 설정 변경</strong>이라는 점입니다. 코드 푸시도, 빌드도, 재시작도 아닌 — Nginx의 <code class="language-plaintext highlighter-rouge">upstream</code>만 바꿉니다.</p>

<hr />

<h2 id="1단계--두-개의-애플리케이션-인스턴스">1단계 — 두 개의 애플리케이션 인스턴스</h2>

<p>같은 서버에서 두 인스턴스를 동시에 운영합니다(다른 포트로).</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Blue (운영 중)</span>
systemctl status myapp-blue   <span class="c"># 포트 8080</span>
<span class="c"># Green (대기)</span>
systemctl status myapp-green  <span class="c"># 포트 8081</span>
</code></pre></div></div>

<p>systemd 템플릿 유닛으로 관리하면 깔끔합니다.</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/systemd/system/myapp@.service
</span><span class="nn">[Unit]</span><span class="w">
</span><span class="py">Description</span><span class="p">=</span><span class="s">MyApp instance %i</span>
<span class="py">After</span><span class="p">=</span><span class="s">network.target</span>
<span class="w">
</span><span class="nn">[Service]</span><span class="w">
</span><span class="py">User</span><span class="p">=</span><span class="s">deploy</span>
<span class="py">WorkingDirectory</span><span class="p">=</span><span class="s">/opt/myapp/%i</span>
<span class="py">ExecStart</span><span class="p">=</span><span class="s">/opt/myapp/%i/bin/start.sh</span>
<span class="py">EnvironmentFile</span><span class="p">=</span><span class="s">/opt/myapp/%i/env</span>
<span class="py">Restart</span><span class="p">=</span><span class="s">always</span>
<span class="w">
</span><span class="nn">[Install]</span><span class="w">
</span><span class="py">WantedBy</span><span class="p">=</span><span class="s">multi-user.target</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl <span class="nb">enable </span>myapp@blue myapp@green
<span class="nb">sudo </span>systemctl start myapp@blue
</code></pre></div></div>

<hr />

<h2 id="2단계--nginx-upstream-정의">2단계 — Nginx upstream 정의</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/conf.d/myapp.conf</span>

<span class="k">upstream</span> <span class="s">blue</span> <span class="p">{</span>
    <span class="kn">server</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">8080</span><span class="p">;</span>
    <span class="kn">keepalive</span> <span class="mi">32</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">upstream</span> <span class="s">green</span> <span class="p">{</span>
    <span class="kn">server</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">8081</span><span class="p">;</span>
    <span class="kn">keepalive</span> <span class="mi">32</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1"># 현재 활성 upstream을 가리키는 별명</span>
<span class="k">upstream</span> <span class="s">active</span> <span class="p">{</span>
    <span class="kn">server</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">8080</span><span class="p">;</span>
    <span class="kn">keepalive</span> <span class="mi">32</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span> <span class="s">http2</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">app.example.com</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://active</span><span class="p">;</span>
        <span class="kn">proxy_http_version</span> <span class="mf">1.1</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Connection</span> <span class="s">""</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">active</code>가 가리키는 포트만 바꾸면 트래픽이 전환됩니다.</p>

<hr />

<h2 id="3단계--전환-스크립트">3단계 — 전환 스크립트</h2>

<p><code class="language-plaintext highlighter-rouge">active</code>의 포트만 바꿔서 nginx reload 하는 스크립트입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /usr/local/bin/switch-deploy.sh</span>
<span class="nb">set</span> <span class="nt">-euo</span> pipefail

<span class="nv">TARGET</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">1</span><span class="k">:-}</span><span class="s2">"</span>  <span class="c"># blue 또는 green</span>
<span class="nv">CONF</span><span class="o">=</span><span class="s2">"/etc/nginx/conf.d/myapp.conf"</span>

<span class="k">if</span> <span class="o">[[</span> <span class="s2">"</span><span class="nv">$TARGET</span><span class="s2">"</span> <span class="o">!=</span> <span class="s2">"blue"</span> <span class="o">&amp;&amp;</span> <span class="s2">"</span><span class="nv">$TARGET</span><span class="s2">"</span> <span class="o">!=</span> <span class="s2">"green"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
  </span><span class="nb">echo</span> <span class="s2">"Usage: </span><span class="nv">$0</span><span class="s2"> &lt;blue|green&gt;"</span>
  <span class="nb">exit </span>1
<span class="k">fi

</span><span class="nv">PORT</span><span class="o">=</span>8080
<span class="o">[[</span> <span class="s2">"</span><span class="nv">$TARGET</span><span class="s2">"</span> <span class="o">==</span> <span class="s2">"green"</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> <span class="nv">PORT</span><span class="o">=</span>8081

<span class="c"># active upstream의 포트만 치환</span>
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"/upstream active/,/}/ s|server 127.0.0.1:[0-9]*;|server 127.0.0.1:</span><span class="k">${</span><span class="nv">PORT</span><span class="k">}</span><span class="s2">;|"</span> <span class="s2">"</span><span class="nv">$CONF</span><span class="s2">"</span>

<span class="c"># Nginx 설정 검증 후 reload</span>
<span class="nb">sudo </span>nginx <span class="nt">-t</span>
<span class="nb">sudo </span>systemctl reload nginx

<span class="nb">echo</span> <span class="s2">"Switched to </span><span class="nv">$TARGET</span><span class="s2"> (port </span><span class="nv">$PORT</span><span class="s2">)"</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo chmod</span> +x /usr/local/bin/switch-deploy.sh
</code></pre></div></div>

<hr />

<h2 id="4단계--배포-스크립트-green에-배포">4단계 — 배포 스크립트 (Green에 배포)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /usr/local/bin/deploy-green.sh</span>
<span class="nb">set</span> <span class="nt">-euo</span> pipefail

<span class="nv">NEW_VERSION</span><span class="o">=</span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>
<span class="nv">APP_DIR</span><span class="o">=</span><span class="s2">"/opt/myapp/green"</span>

<span class="nb">echo</span> <span class="s2">"[1/4] Stopping green..."</span>
<span class="nb">sudo </span>systemctl stop myapp@green

<span class="nb">echo</span> <span class="s2">"[2/4] Deploying version </span><span class="nv">$NEW_VERSION</span><span class="s2"> to green..."</span>
<span class="nb">cd</span> <span class="s2">"</span><span class="nv">$APP_DIR</span><span class="s2">"</span>
git fetch origin
git checkout <span class="s2">"</span><span class="nv">$NEW_VERSION</span><span class="s2">"</span>
npm ci <span class="nt">--production</span>
<span class="c"># 또는 pip install / cargo build / docker pull 등</span>

<span class="nb">echo</span> <span class="s2">"[3/4] Starting green..."</span>
<span class="nb">sudo </span>systemctl start myapp@green

<span class="nb">echo</span> <span class="s2">"[4/4] Health check..."</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..30<span class="o">}</span><span class="p">;</span> <span class="k">do
  if </span>curl <span class="nt">-fsS</span> http://127.0.0.1:8081/healthz <span class="o">&gt;</span> /dev/null<span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"Green is healthy"</span>
    <span class="nb">exit </span>0
  <span class="k">fi
  </span><span class="nb">sleep </span>1
<span class="k">done

</span><span class="nb">echo</span> <span class="s2">"Green failed to start"</span> <span class="o">&gt;</span>&amp;2
<span class="nb">exit </span>1
</code></pre></div></div>

<p>성공하면 다음과 같이 트래픽을 전환합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> /usr/local/bin/deploy-green.sh v1.1.0
<span class="nb">sudo</span> /usr/local/bin/switch-deploy.sh green
</code></pre></div></div>

<hr />

<h2 id="5단계--헬스체크-엔드포인트">5단계 — 헬스체크 엔드포인트</h2>

<p><code class="language-plaintext highlighter-rouge">/healthz</code>는 단순 200을 반환하는 게 아니라 <strong>실제 의존성</strong>까지 체크해야 합니다.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@app.route</span><span class="p">(</span><span class="sh">'</span><span class="s">/healthz</span><span class="sh">'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">healthz</span><span class="p">():</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">db</span><span class="p">.</span><span class="nf">execute</span><span class="p">(</span><span class="sh">"</span><span class="s">SELECT 1</span><span class="sh">"</span><span class="p">)</span>          <span class="c1"># DB 연결
</span>        <span class="n">redis</span><span class="p">.</span><span class="nf">ping</span><span class="p">()</span>                     <span class="c1"># 캐시 연결
</span>        <span class="k">return</span> <span class="p">{</span><span class="sh">"</span><span class="s">status</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">ok</span><span class="sh">"</span><span class="p">},</span> <span class="mi">200</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">{</span><span class="sh">"</span><span class="s">status</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">fail</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">error</span><span class="sh">"</span><span class="p">:</span> <span class="nf">str</span><span class="p">(</span><span class="n">e</span><span class="p">)},</span> <span class="mi">503</span>
</code></pre></div></div>

<p>DB가 죽었는데 단순 200을 반환하면, Green으로 전환하자마자 모든 요청이 500으로 떨어집니다.</p>

<hr />

<h2 id="6단계--롤백">6단계 — 롤백</h2>

<p>문제가 생기면 한 줄로 되돌립니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> /usr/local/bin/switch-deploy.sh blue
</code></pre></div></div>

<p>이게 Blue-Green의 가장 큰 가치입니다. Blue가 살아 있는 한 <strong>언제든</strong> 단일 명령으로 즉시 복귀가 가능합니다.</p>

<hr />

<h2 id="주의해야-할-함정">주의해야 할 함정</h2>

<p><strong>상태가 있는 연결</strong></p>
<ul>
  <li>WebSocket, SSE, gRPC 스트림처럼 장기 연결을 유지하는 클라이언트는 reload 시 그대로 유지됩니다. 새 연결만 Green으로 갑니다. 점진적으로 자연스러운 전환이 됩니다.</li>
  <li>다만 <strong>세션 어피니티</strong>가 필요한 경우(예: 인메모리 세션) 두 인스턴스 모두에 세션 스토어가 공유돼야 합니다. Redis 세션 스토어 등을 두는 것이 안전합니다.</li>
</ul>

<p><strong>DB 마이그레이션</strong></p>
<ul>
  <li>Blue와 Green이 동시에 같은 DB를 보고 있으므로, <strong>이전 버전과 호환되는</strong> 마이그레이션만 적용해야 합니다. 컬럼 삭제, 타입 변경 같은 파괴적 변경은 다음 절차로 분리하세요.
    <ol>
      <li>새 컬럼 추가 (이번 배포)</li>
      <li>코드를 새 컬럼 사용으로 교체 (다음 배포)</li>
      <li>옛 컬럼 삭제 (그 다음 배포)</li>
    </ol>
  </li>
</ul>

<p><strong>환경 변수 / 비밀</strong></p>
<ul>
  <li>Green 환경 변수가 Blue와 다르면 의도하지 않은 차이가 생깁니다. 환경 변수 파일을 같은 곳에서 읽도록 통일하세요.</li>
</ul>

<p><strong>연결 풀 / 캐시 워밍업</strong></p>
<ul>
  <li>Green이 막 떴을 때 첫 요청은 DB 연결 풀이 비어 있어 느릴 수 있습니다. 헬스체크에서 가벼운 쿼리를 한 번 보내거나, <code class="language-plaintext highlighter-rouge">/warmup</code> 엔드포인트를 만들어 주요 쿼리를 미리 실행해두면 좋습니다.</li>
</ul>

<hr />

<h2 id="canary-배포로-확장">Canary 배포로 확장</h2>

<p>Blue-Green을 한 단계 발전시키면 Canary 배포가 됩니다. Nginx의 가중치 기능으로 트래픽을 부분 전환할 수 있습니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">upstream</span> <span class="s">active</span> <span class="p">{</span>
    <span class="kn">server</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">8080</span> <span class="s">weight=9</span><span class="p">;</span>  <span class="c1"># Blue 90%</span>
    <span class="kn">server</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">8081</span> <span class="s">weight=1</span><span class="p">;</span>  <span class="c1"># Green 10%</span>
    <span class="kn">keepalive</span> <span class="mi">32</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>10%로 시작 → 30% → 50% → 100% 단계로 모니터링하면서 늘리면 됩니다. 문제 발생 시 가중치만 0으로 바꿔 즉시 차단합니다.</p>

<hr />

<h2 id="마무리">마무리</h2>

<p>Blue-Green은 거창한 도구가 아닙니다. <strong>두 개의 인스턴스 + 한 줄 짜리 Nginx upstream 변경</strong>만 있으면 다운타임 0초 배포가 가능합니다. 진입 비용이 낮으면서 효과는 즉시 체감됩니다.</p>

<p>TCP-80.NET의 <a href="https://tcp-80.net/virtual-server/">일본 VPS</a> 4GB 플랜이면 Blue-Green 환경 두 개를 모두 띄우기에 충분합니다. systemd 템플릿이나 Nginx 설정에 막히는 부분이 있으면 <a href="https://t.me/tcp80net">@tcp80net</a>으로 한국어 문의 가능합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[사용자가 늘어날수록 "잠시 점검"이 곧 매출 손실로 이어집니다. Blue-Green 배포는 두 개의 환경을 번갈아 사용해 다운타임 0초로 배포하는 가장 단순하고 검증된 패턴입니다. 일본 서버 환경에서 Nginx 기반으로 구현하는 방법을 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">MinIO로 일본 서버에 S3 호환 오브젝트 스토리지 구축</title><link href="https://tcp-80.net/blog/2026/04/27/japan-server-minio-object-storage/" rel="alternate" type="text/html" title="MinIO로 일본 서버에 S3 호환 오브젝트 스토리지 구축" /><published>2026-04-27T00:00:00+09:00</published><updated>2026-04-27T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/04/27/japan-server-minio-object-storage</id><content type="html" xml:base="https://tcp-80.net/blog/2026/04/27/japan-server-minio-object-storage/"><![CDATA[<p>자체 오브젝트 스토리지가 필요한 이유는 다양합니다. AWS S3 비용 절감, 데이터를 일본 국내(또는 한국 인접)에 둬야 하는 규정, 빠른 LAN 내부 액세스 등. 그럴 때 가장 검증된 선택지가 <strong>MinIO</strong>입니다. AWS S3 API와 100% 호환되어 코드 수정 없이 그대로 옮길 수 있습니다.</p>

<hr />

<h2 id="minio를-선택해야-할-때">MinIO를 선택해야 할 때</h2>

<table>
  <thead>
    <tr>
      <th>상황</th>
      <th>MinIO 적합</th>
      <th>비고</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>S3 비용 절감</td>
      <td>✓</td>
      <td>데이터 트래픽 비용도 자체 회선이라 0원</td>
    </tr>
    <tr>
      <td>데이터를 일본·한국에 둬야 함</td>
      <td>✓</td>
      <td>도쿄 IDC 사용</td>
    </tr>
    <tr>
      <td>사진·영상 호스팅</td>
      <td>✓</td>
      <td>정적 파일 서빙 가능</td>
    </tr>
    <tr>
      <td>글로벌 CDN 필요</td>
      <td>△</td>
      <td>앞단에 Cloudflare 등 추가 필요</td>
    </tr>
    <tr>
      <td>99.99% 가용성 필요</td>
      <td>△</td>
      <td>분산 노드 4대+ 권장</td>
    </tr>
  </tbody>
</table>

<p>단일 노드 MinIO는 디스크 1대를 그대로 사용하므로 디스크 장애 = 데이터 손실입니다. <strong>중요한 데이터는 백업 또는 분산 모드(4노드+)로</strong> 운영해야 합니다.</p>

<hr />

<h2 id="1단계--디스크-준비">1단계 — 디스크 준비</h2>

<p>MinIO는 빈 디렉토리만 있으면 동작하지만, <strong>별도 디스크/파티션</strong>을 권장합니다. 다른 서비스의 디스크 사용량과 영향을 분리하기 위함입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 새 디스크 마운트 예시 (전용서버에 추가 디스크가 있을 때)</span>
<span class="nb">sudo </span>mkfs.xfs /dev/sdb1
<span class="nb">sudo mkdir</span> <span class="nt">-p</span> /mnt/minio
<span class="nb">sudo </span>mount /dev/sdb1 /mnt/minio

<span class="c"># /etc/fstab 등록</span>
<span class="nb">echo</span> <span class="s2">"/dev/sdb1  /mnt/minio  xfs  defaults,noatime  0  2"</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/fstab
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">xfs</code>가 큰 파일과 많은 파일 양쪽에서 안정적이라 MinIO 공식 문서도 권장합니다.</p>

<hr />

<h2 id="2단계--minio-설치">2단계 — MinIO 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 바이너리 다운로드</span>
wget https://dl.min.io/server/minio/release/linux-amd64/minio <span class="nt">-O</span> /usr/local/bin/minio
<span class="nb">chmod</span> +x /usr/local/bin/minio

<span class="c"># 클라이언트(mc)도 함께</span>
wget https://dl.min.io/client/mc/release/linux-amd64/mc <span class="nt">-O</span> /usr/local/bin/mc
<span class="nb">chmod</span> +x /usr/local/bin/mc
</code></pre></div></div>

<p>전용 사용자 생성:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>useradd <span class="nt">-r</span> minio-user <span class="nt">-s</span> /sbin/nologin
<span class="nb">sudo chown</span> <span class="nt">-R</span> minio-user:minio-user /mnt/minio
</code></pre></div></div>

<hr />

<h2 id="3단계--systemd-서비스로-등록">3단계 — systemd 서비스로 등록</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/systemd/system/minio.service
</span><span class="nn">[Unit]</span><span class="w">
</span><span class="py">Description</span><span class="p">=</span><span class="s">MinIO</span>
<span class="py">After</span><span class="p">=</span><span class="s">network-online.target</span>
<span class="py">Wants</span><span class="p">=</span><span class="s">network-online.target</span>
<span class="w">
</span><span class="nn">[Service]</span><span class="w">
</span><span class="py">User</span><span class="p">=</span><span class="s">minio-user</span>
<span class="py">Group</span><span class="p">=</span><span class="s">minio-user</span>
<span class="py">EnvironmentFile</span><span class="p">=</span><span class="s">/etc/default/minio</span>
<span class="py">ExecStart</span><span class="p">=</span><span class="s">/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES</span>
<span class="py">Restart</span><span class="p">=</span><span class="s">always</span>
<span class="py">LimitNOFILE</span><span class="p">=</span><span class="s">65536</span>
<span class="py">TasksMax</span><span class="p">=</span><span class="s">infinity</span>
<span class="py">TimeoutStopSec</span><span class="p">=</span><span class="s">infinity</span>
<span class="w">
</span><span class="nn">[Install]</span><span class="w">
</span><span class="py">WantedBy</span><span class="p">=</span><span class="s">multi-user.target</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/default/minio</span>
<span class="nv">MINIO_VOLUMES</span><span class="o">=</span><span class="s2">"/mnt/minio"</span>
<span class="nv">MINIO_OPTS</span><span class="o">=</span><span class="s2">"--console-address :9001 --address :9000"</span>
<span class="nv">MINIO_ROOT_USER</span><span class="o">=</span><span class="s2">"admin"</span>
<span class="nv">MINIO_ROOT_PASSWORD</span><span class="o">=</span><span class="s2">"&lt;강력한 비밀번호 32자 이상&gt;"</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl daemon-reload
<span class="nb">sudo </span>systemctl <span class="nb">enable</span> <span class="nt">--now</span> minio
<span class="nb">sudo </span>systemctl status minio
</code></pre></div></div>

<hr />

<h2 id="4단계--방화벽">4단계 — 방화벽</h2>

<p>기본 포트는 <code class="language-plaintext highlighter-rouge">9000</code>(API), <code class="language-plaintext highlighter-rouge">9001</code>(Console)입니다. 외부에 노출할 필요가 없다면 차단하고, Nginx 리버스 프록시 뒤에 둡니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 외부 노출 차단, localhost만</span>
<span class="nb">sudo </span>ufw deny 9000
<span class="nb">sudo </span>ufw deny 9001
</code></pre></div></div>

<hr />

<h2 id="5단계--nginx로-https-종단">5단계 — Nginx로 HTTPS 종단</h2>

<p><code class="language-plaintext highlighter-rouge">s3.example.com</code> 도메인을 MinIO 앞에 둡니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/sites-available/minio</span>
<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span> <span class="s">http2</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">s3.example.com</span><span class="p">;</span>

    <span class="kn">ssl_certificate</span>     <span class="n">/etc/letsencrypt/live/s3.example.com/fullchain.pem</span><span class="p">;</span>
    <span class="kn">ssl_certificate_key</span> <span class="n">/etc/letsencrypt/live/s3.example.com/privkey.pem</span><span class="p">;</span>

    <span class="c1"># 대용량 업로드 허용</span>
    <span class="kn">client_max_body_size</span> <span class="mi">5G</span><span class="p">;</span>
    <span class="kn">proxy_request_buffering</span> <span class="no">off</span><span class="p">;</span>
    <span class="kn">proxy_buffering</span> <span class="no">off</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:9000</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$http_host</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-Proto</span> <span class="nv">$scheme</span><span class="p">;</span>

        <span class="kn">proxy_connect_timeout</span> <span class="mi">300</span><span class="p">;</span>
        <span class="kn">proxy_http_version</span> <span class="mf">1.1</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Connection</span> <span class="s">""</span><span class="p">;</span>
        <span class="kn">chunked_transfer_encoding</span> <span class="no">off</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1"># Console (관리 UI)</span>
<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span> <span class="s">http2</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">console.s3.example.com</span><span class="p">;</span>

    <span class="kn">ssl_certificate</span>     <span class="n">/etc/letsencrypt/live/console.s3.example.com/fullchain.pem</span><span class="p">;</span>
    <span class="kn">ssl_certificate_key</span> <span class="n">/etc/letsencrypt/live/console.s3.example.com/privkey.pem</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:9001</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$http_host</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-Proto</span> <span class="nv">$scheme</span><span class="p">;</span>

        <span class="c1"># WebSocket (콘솔 실시간 갱신)</span>
        <span class="kn">proxy_http_version</span> <span class="mf">1.1</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Upgrade</span> <span class="nv">$http_upgrade</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Connection</span> <span class="s">"upgrade"</span><span class="p">;</span>
        <span class="kn">chunked_transfer_encoding</span> <span class="no">off</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">client_max_body_size</code>는 업로드 가능한 최대 객체 크기입니다. 영상 업로드까지 받으려면 충분히 키워야 합니다.</p>

<hr />

<h2 id="6단계--버킷-생성과-사용자-권한">6단계 — 버킷 생성과 사용자 권한</h2>

<p><code class="language-plaintext highlighter-rouge">mc</code> 클라이언트로 관리합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 별칭 등록</span>
mc <span class="nb">alias set local </span>https://s3.example.com admin <span class="s1">'&lt;MINIO_ROOT_PASSWORD&gt;'</span>

<span class="c"># 버킷 생성</span>
mc mb <span class="nb">local</span>/uploads
mc mb <span class="nb">local</span>/backups

<span class="c"># 버킷 목록</span>
mc <span class="nb">ls local</span>

<span class="c"># 정책 적용 (uploads만 공개 읽기)</span>
mc anonymous <span class="nb">set </span>download <span class="nb">local</span>/uploads
</code></pre></div></div>

<p>애플리케이션용 별도 사용자(IAM 키)를 만듭니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mc admin user add <span class="nb">local </span>app-user <span class="s1">'&lt;32자 비밀번호&gt;'</span>

<span class="c"># 정책 작성: uploads 버킷에만 접근</span>
<span class="nb">cat</span> <span class="o">&gt;</span> /tmp/app-policy.json <span class="o">&lt;&lt;</span><span class="no">EOF</span><span class="sh">
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": ["arn:aws:s3:::uploads/*"]
    },
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::uploads"]
    }
  ]
}
</span><span class="no">EOF

</span>mc admin policy create <span class="nb">local </span>app-policy /tmp/app-policy.json
mc admin policy attach <span class="nb">local </span>app-policy <span class="nt">--user</span> app-user
</code></pre></div></div>

<p>이제 <code class="language-plaintext highlighter-rouge">app-user</code>의 액세스 키와 시크릿 키를 애플리케이션 환경 변수로 사용하면 됩니다.</p>

<hr />

<h2 id="7단계--애플리케이션-코드-s3-sdk-그대로">7단계 — 애플리케이션 코드 (S3 SDK 그대로)</h2>

<p>AWS S3 SDK에 endpoint만 바꿔주면 됩니다.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">boto3</span>

<span class="n">s3</span> <span class="o">=</span> <span class="n">boto3</span><span class="p">.</span><span class="nf">client</span><span class="p">(</span>
    <span class="sh">'</span><span class="s">s3</span><span class="sh">'</span><span class="p">,</span>
    <span class="n">endpoint_url</span><span class="o">=</span><span class="sh">'</span><span class="s">https://s3.example.com</span><span class="sh">'</span><span class="p">,</span>
    <span class="n">aws_access_key_id</span><span class="o">=</span><span class="sh">'</span><span class="s">app-user</span><span class="sh">'</span><span class="p">,</span>
    <span class="n">aws_secret_access_key</span><span class="o">=</span><span class="sh">'</span><span class="s">&lt;32자 비밀번호&gt;</span><span class="sh">'</span><span class="p">,</span>
    <span class="n">region_name</span><span class="o">=</span><span class="sh">'</span><span class="s">ap-northeast-1</span><span class="sh">'</span>
<span class="p">)</span>

<span class="n">s3</span><span class="p">.</span><span class="nf">upload_file</span><span class="p">(</span><span class="sh">'</span><span class="s">/tmp/photo.jpg</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">uploads</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">photos/2026/04/photo.jpg</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Node.js (AWS SDK v3)</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">S3Client</span><span class="p">,</span> <span class="nx">PutObjectCommand</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@aws-sdk/client-s3</span><span class="dl">"</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">s3</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">S3Client</span><span class="p">({</span>
  <span class="na">endpoint</span><span class="p">:</span> <span class="dl">"</span><span class="s2">https://s3.example.com</span><span class="dl">"</span><span class="p">,</span>
  <span class="na">region</span><span class="p">:</span> <span class="dl">"</span><span class="s2">ap-northeast-1</span><span class="dl">"</span><span class="p">,</span>
  <span class="na">credentials</span><span class="p">:</span> <span class="p">{</span>
    <span class="na">accessKeyId</span><span class="p">:</span> <span class="dl">"</span><span class="s2">app-user</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">secretAccessKey</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">S3_SECRET</span><span class="p">,</span>
  <span class="p">},</span>
  <span class="na">forcePathStyle</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>  <span class="c1">// MinIO는 path-style 권장</span>
<span class="p">});</span>
</code></pre></div></div>

<hr />

<h2 id="8단계--백업">8단계 — 백업</h2>

<p>단일 노드 MinIO는 디스크 장애에 취약합니다. 다음 중 하나는 반드시 적용하세요.</p>

<p><strong>옵션 A: 별도 서버로 미러링</strong> (Site Replication)</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mc admin replicate add <span class="nb">local </span>backup <span class="nt">--remote-bucket</span><span class="o">=</span>uploads
</code></pre></div></div>

<p><strong>옵션 B: 정기적으로 다른 위치로 동기화</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 매일 새벽 백업 서버로 동기화</span>
mc mirror <span class="nt">--remove</span> <span class="nb">local</span>/uploads backup-server/uploads
</code></pre></div></div>

<p><strong>옵션 C: 분산 모드 (운영 환경 권장)</strong>
서버 4대 이상으로 erasure coding을 활성화. 디스크 절반이 죽어도 데이터가 보존됩니다.</p>

<hr />

<h2 id="운영-모니터링">운영 모니터링</h2>

<p>MinIO는 Prometheus 메트릭을 기본 제공합니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET https://s3.example.com/minio/v2/metrics/cluster
</code></pre></div></div>

<p>주요 지표:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">minio_node_disk_free_bytes</code> — 디스크 여유 공간</li>
  <li><code class="language-plaintext highlighter-rouge">minio_s3_requests_total</code> — 초당 요청 수</li>
  <li><code class="language-plaintext highlighter-rouge">minio_node_disk_latency_us</code> — 디스크 지연</li>
</ul>

<p>Netdata, Grafana 대시보드와 연결하면 실시간 모니터링이 됩니다.</p>

<hr />

<h2 id="마무리">마무리</h2>

<p>MinIO는 “S3 호환 + 자체 운영 + 일본 IDC 위치”라는 세 조건을 한 번에 만족시킵니다. 데이터 주권 요구가 있는 한국·일본 기업에 특히 잘 맞습니다.</p>

<p>영상·이미지 같은 대용량 워크로드는 <a href="https://tcp-80.net/dedicated-server/">전용서버</a>의 디스크 옵션이 더 적합하며, 디스크 추가 옵션 문의는 <a href="https://t.me/tcp80net">@tcp80net</a>으로 부탁드립니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[AWS S3가 비싸지거나 데이터 주권이 필요해지면 MinIO가 답입니다. 일본 서버 한 대에서 S3 API 100% 호환 오브젝트 스토리지를 운영하는 방법을 설치, HTTPS, 사용자 권한, 백업까지 다룹니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 메일 발송 — SPF, DKIM, DMARC 완전 정복</title><link href="https://tcp-80.net/blog/2026/04/24/japan-server-spf-dkim-dmarc/" rel="alternate" type="text/html" title="일본 서버 메일 발송 — SPF, DKIM, DMARC 완전 정복" /><published>2026-04-24T00:00:00+09:00</published><updated>2026-04-24T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/04/24/japan-server-spf-dkim-dmarc</id><content type="html" xml:base="https://tcp-80.net/blog/2026/04/24/japan-server-spf-dkim-dmarc/"><![CDATA[<p>자체 도메인에서 보낸 트랜잭션 메일(가입 인증, 비밀번호 재설정 등)이 스팸함으로 빠진다면 거의 100% <strong>메일 인증</strong> 문제입니다. 2024년부터 Gmail은 일정량 이상 발송하는 모든 도메인에 SPF·DKIM·DMARC를 의무화했습니다.</p>

<p><img src="/assets/img/posts/2026-04-24/email-auth-flow.svg" alt="SPF · DKIM · DMARC 인증 흐름" /></p>

<hr />

<h2 id="세-가지의-역할">세 가지의 역할</h2>

<table>
  <thead>
    <tr>
      <th>인증</th>
      <th>검증 대상</th>
      <th>핵심</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>SPF</strong></td>
      <td>“이 IP가 이 도메인을 보낼 자격이 있는가?”</td>
      <td>발송 IP 화이트리스트</td>
    </tr>
    <tr>
      <td><strong>DKIM</strong></td>
      <td>“본문이 중간에 변조되지 않았는가?”</td>
      <td>디지털 서명(비대칭키)</td>
    </tr>
    <tr>
      <td><strong>DMARC</strong></td>
      <td>“SPF/DKIM 실패 시 어떻게 처리할 것인가?”</td>
      <td>정책 + 보고서 수신</td>
    </tr>
  </tbody>
</table>

<p>SPF만 있으면 본문 변조를 못 잡고, DKIM만 있으면 발송지 IP를 속일 수 있습니다. <strong>세 가지가 함께</strong> 동작해야 안전합니다.</p>

<hr />

<h2 id="사전-조건">사전 조건</h2>

<ul>
  <li>일본 서버에 PTR(역방향 DNS)이 설정되어 있어야 합니다. TCP-80.NET은 PTR 등록을 <a href="https://t.me/tcp80net">@tcp80net</a> 요청으로 처리합니다.</li>
  <li>도메인의 DNS를 직접 편집할 수 있어야 합니다(Cloudflare, 가비아, AWS Route 53 등).</li>
  <li>메일 서버(Postfix 등)가 이미 동작 중이어야 합니다.</li>
</ul>

<hr />

<h2 id="1단계--spf-설정">1단계 — SPF 설정</h2>

<p>SPF는 도메인의 TXT 레코드에 한 줄을 추가하는 것으로 끝납니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>타입: TXT
이름: @
값: v=spf1 ip4:203.0.113.10 -all
</code></pre></div></div>

<p>여러 발송 경로가 있을 때:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>v=spf1 ip4:203.0.113.10 ip4:203.0.113.11 include:_spf.google.com -all
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>표현</th>
      <th>의미</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ip4:</code> <code class="language-plaintext highlighter-rouge">ip6:</code></td>
      <td>허용 IP</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">include:</code></td>
      <td>외부 발송 서비스(예: SendGrid, Mailgun)의 SPF 임포트</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">~all</code></td>
      <td>그 외는 SoftFail (일반적으로 권장)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">-all</code></td>
      <td>그 외는 HardFail (가장 엄격)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">?all</code></td>
      <td>중립 (사실상 의미 없음)</td>
    </tr>
  </tbody>
</table>

<p>처음에는 <code class="language-plaintext highlighter-rouge">~all</code>로 시작하고, 안정되면 <code class="language-plaintext highlighter-rouge">-all</code>로 강화하는 것이 안전합니다.</p>

<p>검증:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dig +short TXT example.com
</code></pre></div></div>

<hr />

<h2 id="2단계--dkim-설정-postfix--opendkim">2단계 — DKIM 설정 (Postfix + OpenDKIM)</h2>

<p>DKIM은 메일 본문에 서명을 추가하고, 공개키를 DNS에 게시해 수신 서버가 검증할 수 있게 합니다.</p>

<h3 id="opendkim-설치">OpenDKIM 설치</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>opendkim opendkim-tools
<span class="nb">sudo mkdir</span> <span class="nt">-p</span> /etc/opendkim/keys/example.com
<span class="nb">sudo chown</span> <span class="nt">-R</span> opendkim:opendkim /etc/opendkim
</code></pre></div></div>

<h3 id="키-생성">키 생성</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> /etc/opendkim/keys/example.com
<span class="nb">sudo </span>opendkim-genkey <span class="nt">-s</span> default <span class="nt">-d</span> example.com
<span class="nb">sudo chown </span>opendkim:opendkim default.private
</code></pre></div></div>

<p>생성된 <code class="language-plaintext highlighter-rouge">default.txt</code>에 DNS 등록용 공개키가 들어 있습니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>default._domainkey  IN  TXT  ( "v=DKIM1; h=sha256; k=rsa; "
  "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..." )
</code></pre></div></div>

<p>이 내용을 도메인 DNS에 TXT 레코드로 추가합니다(이름: <code class="language-plaintext highlighter-rouge">default._domainkey</code>).</p>

<h3 id="opendkim-설정">OpenDKIM 설정</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/opendkim.conf
</span><span class="na">Syslog</span><span class="w">                  </span><span class="na">yes</span><span class="w">
</span><span class="na">UMask</span><span class="w">                   </span><span class="na">002</span><span class="w">
</span><span class="na">Domain</span><span class="w">                  </span><span class="na">example.com</span><span class="w">
</span><span class="na">KeyFile</span><span class="w">                 </span><span class="na">/etc/opendkim/keys/example.com/default.private</span><span class="w">
</span><span class="na">Selector</span><span class="w">                </span><span class="na">default</span><span class="w">
</span><span class="na">Socket</span><span class="w">                  </span><span class="na">inet:8891@localhost</span><span class="w">
</span><span class="na">Mode</span><span class="w">                    </span><span class="na">sv</span><span class="w">
</span><span class="na">SubDomains</span><span class="w">              </span><span class="na">no</span><span class="w">
</span><span class="na">AutoRestart</span><span class="w">             </span><span class="na">yes</span><span class="w">
</span><span class="na">SignatureAlgorithm</span><span class="w">      </span><span class="na">rsa-sha256</span><span class="w">
</span></code></pre></div></div>

<h3 id="postfix-연동">Postfix 연동</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/postfix/main.cf 끝에 추가
</span><span class="py">milter_default_action</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">accept</span>
<span class="py">milter_protocol</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">6</span>
<span class="py">smtpd_milters</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">inet:localhost:8891</span>
<span class="py">non_smtpd_milters</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">inet:localhost:8891</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl <span class="nb">enable</span> <span class="nt">--now</span> opendkim
<span class="nb">sudo </span>systemctl restart postfix
</code></pre></div></div>

<p>테스트 메일을 보내고 Gmail 헤더에서 <code class="language-plaintext highlighter-rouge">dkim=pass</code>가 보이면 성공입니다.</p>

<hr />

<h2 id="3단계--dmarc-설정">3단계 — DMARC 설정</h2>

<p>DMARC는 SPF/DKIM 실패 시 동작과 보고서 수신 주소를 정의합니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>타입: TXT
이름: _dmarc
값: v=DMARC1; p=none; rua=mailto:dmarc@example.com; pct=100
</code></pre></div></div>

<h3 id="정책-단계">정책 단계</h3>

<p>DMARC는 <strong>단계적으로 강화</strong>해야 합니다. 처음부터 <code class="language-plaintext highlighter-rouge">reject</code>로 두면 정상 메일까지 차단되는 사고가 일어납니다.</p>

<table>
  <thead>
    <tr>
      <th>단계</th>
      <th>정책</th>
      <th>동작</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1단계 (모니터링)</td>
      <td><code class="language-plaintext highlighter-rouge">p=none</code></td>
      <td>차단 없이 보고서만 수집 (1~2주)</td>
    </tr>
    <tr>
      <td>2단계 (격리)</td>
      <td><code class="language-plaintext highlighter-rouge">p=quarantine</code></td>
      <td>실패 시 스팸함으로 (1~2주)</td>
    </tr>
    <tr>
      <td>3단계 (차단)</td>
      <td><code class="language-plaintext highlighter-rouge">p=reject</code></td>
      <td>실패 시 메일 거부</td>
    </tr>
  </tbody>
</table>

<p><code class="language-plaintext highlighter-rouge">rua=</code>로 지정한 주소로 매일 인증 결과 보고서가 옵니다. 대규모 발송 환경이면 <a href="https://dmarcian.com">https://dmarcian.com</a> 같은 분석 SaaS를 쓰는 게 편합니다.</p>

<hr />

<h2 id="4단계--bimi-선택">4단계 — BIMI (선택)</h2>

<p>BIMI는 인증된 도메인의 메일에 <strong>브랜드 로고</strong>를 표시해주는 표준입니다. DMARC <code class="language-plaintext highlighter-rouge">p=quarantine</code> 이상이 전제 조건입니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>타입: TXT
이름: default._bimi
값: v=BIMI1; l=https://example.com/logo.svg; a=https://example.com/vmc.pem
</code></pre></div></div>

<p>BIMI 자체는 인증이 아니지만, 사용자에게 메일이 정품임을 시각적으로 보여줘 클릭률을 높이는 효과가 있습니다.</p>

<hr />

<h2 id="5단계--검증-도구">5단계 — 검증 도구</h2>

<p>설정이 다 끝나면 다음 도구로 확인합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 한 번에 보기</span>
dig +short TXT example.com           <span class="c"># SPF</span>
dig +short TXT default._domainkey.example.com  <span class="c"># DKIM</span>
dig +short TXT _dmarc.example.com    <span class="c"># DMARC</span>
</code></pre></div></div>

<p>웹 도구:</p>
<ul>
  <li><a href="https://mxtoolbox.com/SuperTool.aspx">https://mxtoolbox.com/SuperTool.aspx</a> — SPF/DKIM/DMARC 한 번에 확인</li>
  <li><code class="language-plaintext highlighter-rouge">check-auth@verifier.port25.com</code> 으로 메일을 보내면 자동 응답으로 결과 분석</li>
</ul>

<hr />

<h2 id="자주-빠지는-함정">자주 빠지는 함정</h2>

<p><strong>SPF에 <code class="language-plaintext highlighter-rouge">include:</code> 너무 많이 추가</strong></p>
<ul>
  <li>SPF는 DNS 조회 횟수가 <strong>10회를 초과하면 실패</strong> 처리됩니다. SendGrid, Mailgun, Google 등을 모두 추가하면 한도를 넘기 쉬우니, 사용하지 않는 서비스는 제거하세요.</li>
</ul>

<p><strong>DKIM 키 길이 1024 → 2048 변경 시</strong></p>
<ul>
  <li>일부 DNS 제공자는 TXT 레코드 한 줄 길이 제한이 있습니다. 따옴표로 분할해 넣어야 하는 경우가 있으니 등록 후 <code class="language-plaintext highlighter-rouge">dig</code>로 반드시 검증하세요.</li>
</ul>

<p><strong>DMARC <code class="language-plaintext highlighter-rouge">reject</code> 직행</strong></p>
<ul>
  <li>외부 SaaS(설문, 청구서, CRM 등)도 같은 도메인으로 발송 중이라면, 정책을 강화하면 그쪽 메일이 모두 차단됩니다. 보고서로 발송 출처를 모두 파악한 뒤 단계적으로 강화하세요.</li>
</ul>

<p><strong>메일 발송 IP의 PTR 누락</strong></p>
<ul>
  <li>IPv6로 메일을 보낼 때 PTR이 없으면 Gmail은 거의 무조건 거부합니다. 호스팅사에 PTR 등록을 요청하세요.</li>
</ul>

<hr />

<h2 id="마무리">마무리</h2>

<p>SPF·DKIM·DMARC는 한 번 잘 설정해두면 도메인 평판이 안정적으로 누적됩니다. 설정 후에는 <strong>DMARC 보고서를 1주일 정도 모니터링</strong>한 뒤 정책을 점진 강화하세요.</p>

<p>TCP-80.NET의 <a href="https://tcp-80.net/dedicated-server/">일본 서버</a>는 PTR 등록을 무료로 지원하며, 메일 서버 운영 중 막히는 부분이 있으면 <a href="https://t.me/tcp80net">@tcp80net</a>으로 한국어 안내가 가능합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="보안" /><summary type="html"><![CDATA[자체 일본 서버에서 메일을 보내는 순간 Gmail·Naver·Outlook은 SPF, DKIM, DMARC 세 가지를 모두 검사합니다. 하나라도 실패하면 스팸함 직행입니다. DNS 설정부터 Postfix·OpenDKIM 연동, 정책 강화까지 단계별로 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-security.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-security.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 게임 서버 네트워크 튜닝 — 지연을 1ms 줄이는 실전 설정</title><link href="https://tcp-80.net/blog/2026/04/21/japan-game-server-network-tuning/" rel="alternate" type="text/html" title="일본 게임 서버 네트워크 튜닝 — 지연을 1ms 줄이는 실전 설정" /><published>2026-04-21T00:00:00+09:00</published><updated>2026-04-21T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/04/21/japan-game-server-network-tuning</id><content type="html" xml:base="https://tcp-80.net/blog/2026/04/21/japan-game-server-network-tuning/"><![CDATA[<p>게임 서버는 일반 웹 서비스와 다릅니다. 처리량보다 <strong>지연(latency)</strong> 과 <strong>지터(jitter)</strong> 가 사용자 체감에 직결되며, 1프레임(16.7ms)을 늘리는 순간 캐릭터가 미끄러지듯 보이기 시작합니다. 이 글에서는 일본 도쿄 IDC에 위치한 게임 서버에서 적용할 수 있는 네트워크 튜닝 포인트를 정리합니다.</p>

<hr />

<h2 id="게임-서버에서-중요한-지표">게임 서버에서 중요한 지표</h2>

<table>
  <thead>
    <tr>
      <th>지표</th>
      <th>의미</th>
      <th>목표</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>지연(Latency)</td>
      <td>RTT의 절반, 일방향 시간</td>
      <td>한국→일본 ≤ 30ms</td>
    </tr>
    <tr>
      <td>지터(Jitter)</td>
      <td>RTT의 변동폭</td>
      <td>≤ 5ms</td>
    </tr>
    <tr>
      <td>패킷 손실</td>
      <td>사라진 패킷 비율</td>
      <td>≤ 0.1%</td>
    </tr>
    <tr>
      <td>처리량(Throughput)</td>
      <td>초당 패킷 수</td>
      <td>게임에 따라</td>
    </tr>
  </tbody>
</table>

<p>웹은 1초가 빠르고 늦고에 민감하지만, 게임은 <strong>5ms와 10ms의 차이</strong>가 곧 승패에 영향을 줍니다.</p>

<hr />

<h2 id="1단계--데이터센터-위치-선택">1단계 — 데이터센터 위치 선택</h2>

<p>같은 일본이라도 도쿄/오사카/후쿠오카에 따라 한국 사용자와의 RTT가 다릅니다.</p>

<table>
  <thead>
    <tr>
      <th>위치</th>
      <th>한국(서울)→일본 RTT</th>
      <th>비고</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>도쿄 (KIX-NRT 우회 경로)</td>
      <td>25~35ms</td>
      <td>가장 보편적, 가성비</td>
    </tr>
    <tr>
      <td>오사카</td>
      <td>30~40ms</td>
      <td>도쿄보다 약간 길지만 안정적</td>
    </tr>
    <tr>
      <td>후쿠오카</td>
      <td>20~25ms</td>
      <td>한국과 가장 가까움, 한국 게이머 대상 게임에 유리</td>
    </tr>
  </tbody>
</table>

<p>다만 후쿠오카는 IDC 선택지가 좁아 가용성이 떨어질 수 있습니다. 글로벌 사용자도 함께 받는다면 도쿄가 균형이 좋습니다.</p>

<hr />

<h2 id="2단계--nic-큐와-irq-분산">2단계 — NIC 큐와 IRQ 분산</h2>

<p>게임 서버처럼 패킷이 많은 워크로드는 <strong>단일 CPU에 인터럽트가 몰리면</strong> 그 코어만 100%가 되고 다른 코어는 놀게 됩니다. RSS(Receive Side Scaling)로 큐를 늘리고 IRQ를 분산해야 합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># NIC가 지원하는 큐 개수 확인</span>
ethtool <span class="nt">-l</span> eth0

<span class="c"># 큐 개수를 코어 수 만큼 설정</span>
<span class="nb">sudo </span>ethtool <span class="nt">-L</span> eth0 combined 8

<span class="c"># IRQ를 각 코어에 분산</span>
<span class="nb">sudo </span>systemctl <span class="nb">enable</span> <span class="nt">--now</span> irqbalance
</code></pre></div></div>

<p>수동으로 IRQ를 고정하고 싶다면 <code class="language-plaintext highlighter-rouge">set_irq_affinity.sh</code> 스크립트를 사용하거나 <code class="language-plaintext highlighter-rouge">/proc/irq/&lt;번호&gt;/smp_affinity</code>를 직접 편집합니다.</p>

<hr />

<h2 id="3단계--tcpudp-버퍼-튜닝">3단계 — TCP/UDP 버퍼 튜닝</h2>

<p>게임이 UDP를 쓰더라도 백엔드 통신(DB, 인증)은 대부분 TCP입니다. 양쪽 모두 튜닝합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/sysctl.d/99-game.conf</span>
<span class="c"># 수신/송신 버퍼 (최소 / 기본 / 최대)</span>
net.core.rmem_max <span class="o">=</span> 26214400
net.core.wmem_max <span class="o">=</span> 26214400
net.ipv4.tcp_rmem <span class="o">=</span> 4096 87380 16777216
net.ipv4.tcp_wmem <span class="o">=</span> 4096 65536 16777216

<span class="c"># UDP 수신 버퍼 (대형 게임 패킷에 중요)</span>
net.core.netdev_max_backlog <span class="o">=</span> 5000

<span class="c"># TIME_WAIT 빠르게 재사용</span>
net.ipv4.tcp_tw_reuse <span class="o">=</span> 1
net.ipv4.tcp_fin_timeout <span class="o">=</span> 15

<span class="c"># 동시 연결 백로그</span>
net.core.somaxconn <span class="o">=</span> 4096
net.ipv4.tcp_max_syn_backlog <span class="o">=</span> 4096

<span class="c"># 임시 포트 범위 확장 (클라이언트 연결이 많을 때)</span>
net.ipv4.ip_local_port_range <span class="o">=</span> 10240 65535
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>sysctl <span class="nt">--system</span>
</code></pre></div></div>

<p><strong>주의:</strong> <code class="language-plaintext highlighter-rouge">tcp_tw_recycle</code>은 더 이상 권장되지 않으며 NAT 환경에서 문제를 일으킵니다. <code class="language-plaintext highlighter-rouge">tcp_tw_reuse</code>만 사용하세요.</p>

<hr />

<h2 id="4단계--혼잡-제어-알고리즘">4단계 — 혼잡 제어 알고리즘</h2>

<p>기본 알고리즘은 <code class="language-plaintext highlighter-rouge">cubic</code>이지만, 한국-일본처럼 RTT가 짧은 회선에서는 <strong>BBR</strong>이 더 좋은 결과를 내는 경우가 많습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 현재 알고리즘 확인</span>
sysctl net.ipv4.tcp_congestion_control

<span class="c"># 사용 가능한 알고리즘 확인</span>
sysctl net.ipv4.tcp_available_congestion_control

<span class="c"># BBR 활성화</span>
<span class="nb">echo</span> <span class="s2">"net.core.default_qdisc = fq"</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/sysctl.conf
<span class="nb">echo</span> <span class="s2">"net.ipv4.tcp_congestion_control = bbr"</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/sysctl.conf
<span class="nb">sudo </span>sysctl <span class="nt">-p</span>
</code></pre></div></div>

<p>BBR은 패킷 손실이 아니라 <strong>대역폭과 RTT 측정</strong>으로 혼잡을 판단해, 짧은 RTT 환경에서 cubic보다 응답성이 좋습니다.</p>

<hr />

<h2 id="5단계--udp-게임-서버-최적화">5단계 — UDP 게임 서버 최적화</h2>

<p>대부분의 실시간 게임(FPS, MOBA 등)은 UDP를 사용합니다. UDP 특유의 튜닝 포인트가 있습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># UDP 메모리 풀 (16MB)</span>
sysctl <span class="nt">-w</span> net.ipv4.udp_mem<span class="o">=</span><span class="s2">"65536 131072 262144"</span>

<span class="c"># UDP 수신 큐 깊이</span>
sysctl <span class="nt">-w</span> net.core.netdev_max_backlog<span class="o">=</span>10000
</code></pre></div></div>

<p>게임 서버 프로세스의 <strong>소켓 버퍼 크기</strong>도 코드에서 직접 늘려야 합니다.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="mi">4</span> <span class="o">*</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024</span><span class="p">;</span>  <span class="c1">// 4MB</span>
<span class="n">setsockopt</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">SOL_SOCKET</span><span class="p">,</span> <span class="n">SO_RCVBUF</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">size</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">size</span><span class="p">));</span>
<span class="n">setsockopt</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">SOL_SOCKET</span><span class="p">,</span> <span class="n">SO_SNDBUF</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">size</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">size</span><span class="p">));</span>
</code></pre></div></div>

<hr />

<h2 id="6단계--mtu와-패킷-단편화">6단계 — MTU와 패킷 단편화</h2>

<p>기본 MTU는 1500입니다. PPPoE 회선이 섞이면 1492로 떨어지며, 단편화가 일어나면 한 패킷의 손실이 두 배 영향을 줍니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># MTU 확인</span>
ip <span class="nb">link </span>show eth0

<span class="c"># 경로상 단편화가 일어나는지 테스트</span>
ping <span class="nt">-c</span> 3 <span class="nt">-M</span> <span class="k">do</span> <span class="nt">-s</span> 1472 example.com   <span class="c"># 1472 + 28 = 1500</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Frag needed</code>가 보이면 경로상 MTU가 1500보다 작은 구간이 있습니다. 게임 서버에서는 페이로드를 <strong>1400 이하</strong>로 유지하는 것이 안전합니다.</p>

<hr />

<h2 id="7단계--ddos-보호">7단계 — DDoS 보호</h2>

<p>게임 서버는 일반 사이트보다 DDoS 표적이 되기 쉽습니다. 특히 UDP 서비스는 reflection 공격 발생 시 응답을 못 보내게 됩니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># UDP 응답 속도 제한 (서비스 포트 외)</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> udp <span class="nt">-m</span> limit <span class="nt">--limit</span> 1000/s <span class="nt">--limit-burst</span> 2000 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> udp <span class="nt">-j</span> DROP

<span class="c"># SYN Flood 방어</span>
sysctl <span class="nt">-w</span> net.ipv4.tcp_syncookies<span class="o">=</span>1
sysctl <span class="nt">-w</span> net.ipv4.tcp_synack_retries<span class="o">=</span>2
</code></pre></div></div>

<p>L3/L4 단의 대형 공격은 호스팅사 네트워크에서 막아야 합니다. TCP-80.NET의 <a href="https://tcp-80.net/dedicated-server/">전용서버</a>는 모두 L3/L4 DDoS 방어가 무료 기본 포함이며, <a href="https://tcp-80.net/ddos-security/">전용 DDoS 보호 서비스</a>로 L7까지 강화할 수 있습니다.</p>

<hr />

<h2 id="8단계--모니터링">8단계 — 모니터링</h2>

<p>지연/손실은 자주 측정해야 의미가 있습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 실시간 RTT/손실</span>
mtr <span class="nt">--report</span> <span class="nt">--report-cycles</span> 100 client-ip

<span class="c"># 인터페이스 패킷 통계</span>
ip <span class="nt">-s</span> <span class="nb">link </span>show eth0

<span class="c"># 드롭 발생 여부</span>
netstat <span class="nt">-s</span> | <span class="nb">grep</span> <span class="nt">-i</span> drop

<span class="c"># softirq 부하 (특정 코어가 100%인지)</span>
mpstat <span class="nt">-P</span> ALL 1
</code></pre></div></div>

<p>지속적인 모니터링은 <a href="/blog/2026/02/23/japan-server-monitoring-guide/">모니터링 가이드</a>를 참고하세요. Netdata로 NIC 큐별 RX/TX, softirq, CPU 분포까지 한 화면에서 볼 수 있습니다.</p>

<hr />

<h2 id="마무리">마무리</h2>

<p>게임 서버 튜닝은 “어느 한 가지 설정으로 모든 게 빨라지는” 마법이 없습니다. <strong>위치 선정 → 인터럽트 분산 → 버퍼/혼잡제어 → DDoS 보호</strong> 의 단계를 차례로 점검하면, 같은 하드웨어에서 1~3ms를 줄일 수 있습니다.</p>

<p>TCP-80.NET은 도쿄 IDC 직영으로 한국 회선까지의 경로가 짧고 안정적입니다. 게임 서버용 <a href="https://tcp-80.net/dedicated-server/">전용서버</a> 구성에 대한 문의는 <a href="https://t.me/tcp80net">@tcp80net</a>으로 부탁드립니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="게임" /><summary type="html"><![CDATA[게임 서버에서는 5ms의 지연 차이도 사용자가 체감합니다. 일본 서버의 위치 이점을 최대한 살리기 위한 NIC 인터럽트, TCP/UDP 튜닝, 패킷 우선순위, MTU 설정 등 네트워크 최적화 포인트를 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버에서 k3s로 가벼운 쿠버네티스 운영하기</title><link href="https://tcp-80.net/blog/2026/04/18/japan-server-k3s-guide/" rel="alternate" type="text/html" title="일본 서버에서 k3s로 가벼운 쿠버네티스 운영하기" /><published>2026-04-18T00:00:00+09:00</published><updated>2026-04-18T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/04/18/japan-server-k3s-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/04/18/japan-server-k3s-guide/"><![CDATA[<p>쿠버네티스는 좋지만, 컨트롤 플레인 한 대를 위해 서버 3대를 쓰기엔 비용이 부담입니다. 단일 노드만으로도 K8s API와 매니페스트를 그대로 쓸 수 있다면 가장 좋겠죠. <strong>k3s</strong>가 그런 도구입니다.</p>

<p><img src="/assets/img/posts/2026-04-18/k3s-architecture.svg" alt="k3s 단일 노드 아키텍처" /></p>

<hr />

<h2 id="k3s가-적합한-경우">k3s가 적합한 경우</h2>

<table>
  <thead>
    <tr>
      <th>상황</th>
      <th>k3s</th>
      <th>풀 K8s</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>사이드 프로젝트 / 스테이징</td>
      <td>✓</td>
      <td>과함</td>
    </tr>
    <tr>
      <td>프로덕션, 노드 1~3대</td>
      <td>✓</td>
      <td>과함</td>
    </tr>
    <tr>
      <td>노드 10대 이상, HA 필요</td>
      <td>△</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>엣지·IoT 디바이스</td>
      <td>✓</td>
      <td>✕</td>
    </tr>
    <tr>
      <td>메모리 1GB 서버</td>
      <td>✓</td>
      <td>✕</td>
    </tr>
  </tbody>
</table>

<p>k3s는 풀 K8s와 <strong>API 호환</strong>입니다. <code class="language-plaintext highlighter-rouge">kubectl</code> 명령, <code class="language-plaintext highlighter-rouge">Deployment</code> YAML 등이 그대로 동작합니다. 차이는 etcd 대신 SQLite를 쓰고, 불필요한 컨트롤러를 제거해 가볍게 만든 점입니다.</p>

<hr />

<h2 id="1단계--사전-준비">1단계 — 사전 준비</h2>

<p>일본 서버 1대(Ubuntu 22.04 LTS, 메모리 2GB 이상 권장)를 준비합니다. swap이 켜져 있으면 비활성화해야 합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># swap 비활성화 (k8s 권장)</span>
<span class="nb">sudo </span>swapoff <span class="nt">-a</span>
<span class="nb">sudo sed</span> <span class="nt">-i</span> <span class="s1">'/ swap / s/^/#/'</span> /etc/fstab

<span class="c"># 커널 모듈 적재</span>
<span class="nb">sudo </span>modprobe overlay
<span class="nb">sudo </span>modprobe br_netfilter

<span class="c"># sysctl 설정</span>
<span class="nb">cat</span> <span class="o">&lt;&lt;</span><span class="no">EOF</span><span class="sh"> | sudo tee /etc/sysctl.d/99-k3s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
</span><span class="no">EOF
</span><span class="nb">sudo </span>sysctl <span class="nt">--system</span>
</code></pre></div></div>

<hr />

<h2 id="2단계--k3s-설치">2단계 — k3s 설치</h2>

<p>공식 설치 스크립트는 한 줄입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-sfL</span> https://get.k3s.io | sh -
</code></pre></div></div>

<p>설치가 끝나면 자동으로 systemd 서비스가 등록되고 클러스터가 동작합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl status k3s
<span class="nb">sudo </span>k3s kubectl get nodes
<span class="c"># NAME       STATUS   ROLES                  AGE   VERSION</span>
<span class="c"># server1    Ready    control-plane,master   30s   v1.30.x+k3s1</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">kubectl</code>을 root 없이 사용하려면 kubeconfig를 사용자 홈으로 복사합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> <span class="nt">-p</span> ~/.kube
<span class="nb">sudo cp</span> /etc/rancher/k3s/k3s.yaml ~/.kube/config
<span class="nb">sudo chown</span> <span class="si">$(</span><span class="nb">id</span> <span class="nt">-u</span><span class="si">)</span>:<span class="si">$(</span><span class="nb">id</span> <span class="nt">-g</span><span class="si">)</span> ~/.kube/config
<span class="nb">chmod </span>600 ~/.kube/config

kubectl get pods <span class="nt">-A</span>
</code></pre></div></div>

<hr />

<h2 id="3단계--기본-컴포넌트">3단계 — 기본 컴포넌트</h2>

<p>k3s는 다음을 기본으로 포함합니다.</p>

<ul>
  <li><strong>Traefik</strong> — Ingress 컨트롤러 (L7 라우팅, 자동 HTTPS)</li>
  <li><strong>CoreDNS</strong> — 클러스터 내부 DNS</li>
  <li><strong>ServiceLB(Klipper)</strong> — <code class="language-plaintext highlighter-rouge">Service: LoadBalancer</code> 타입 자동 처리</li>
  <li><strong>Local Path Provisioner</strong> — <code class="language-plaintext highlighter-rouge">PersistentVolumeClaim</code>을 호스트 디렉토리에 매핑</li>
  <li><strong>Metrics Server</strong> — <code class="language-plaintext highlighter-rouge">kubectl top</code> 동작</li>
</ul>

<p>별도 설치 없이 첫 배포부터 외부 접근, HTTPS, 영구 볼륨이 모두 가능합니다.</p>

<hr />

<h2 id="4단계--첫-배포-nginx-예시">4단계 — 첫 배포 (Nginx 예시)</h2>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># nginx.yaml</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">nginx</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">2</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span> <span class="pi">{</span> <span class="nv">app</span><span class="pi">:</span> <span class="nv">nginx</span> <span class="pi">}</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">labels</span><span class="pi">:</span> <span class="pi">{</span> <span class="nv">app</span><span class="pi">:</span> <span class="nv">nginx</span> <span class="pi">}</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">nginx</span>
          <span class="na">image</span><span class="pi">:</span> <span class="s">nginx:1.27</span>
          <span class="na">ports</span><span class="pi">:</span>
            <span class="pi">-</span> <span class="na">containerPort</span><span class="pi">:</span> <span class="m">80</span>
<span class="nn">---</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Service</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">nginx</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">selector</span><span class="pi">:</span> <span class="pi">{</span> <span class="nv">app</span><span class="pi">:</span> <span class="nv">nginx</span> <span class="pi">}</span>
  <span class="na">ports</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">port</span><span class="pi">:</span> <span class="m">80</span>
      <span class="na">targetPort</span><span class="pi">:</span> <span class="m">80</span>
<span class="nn">---</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">networking.k8s.io/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Ingress</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">nginx</span>
  <span class="na">annotations</span><span class="pi">:</span>
    <span class="na">cert-manager.io/cluster-issuer</span><span class="pi">:</span> <span class="s">letsencrypt-prod</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">ingressClassName</span><span class="pi">:</span> <span class="s">traefik</span>
  <span class="na">rules</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">host</span><span class="pi">:</span> <span class="s">app.example.com</span>
      <span class="na">http</span><span class="pi">:</span>
        <span class="na">paths</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="na">path</span><span class="pi">:</span> <span class="s">/</span>
            <span class="na">pathType</span><span class="pi">:</span> <span class="s">Prefix</span>
            <span class="na">backend</span><span class="pi">:</span>
              <span class="na">service</span><span class="pi">:</span>
                <span class="na">name</span><span class="pi">:</span> <span class="s">nginx</span>
                <span class="na">port</span><span class="pi">:</span>
                  <span class="na">number</span><span class="pi">:</span> <span class="m">80</span>
  <span class="na">tls</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">hosts</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">app.example.com</span><span class="pi">]</span>
      <span class="na">secretName</span><span class="pi">:</span> <span class="s">nginx-tls</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> nginx.yaml
kubectl get ingress
</code></pre></div></div>

<p>도메인의 A 레코드를 일본 서버 IP로 향하게 하면 <code class="language-plaintext highlighter-rouge">https://app.example.com</code>으로 접근 가능합니다.</p>

<hr />

<h2 id="5단계--lets-encrypt-자동-인증서-cert-manager">5단계 — Let’s Encrypt 자동 인증서 (cert-manager)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Helm 설치</span>
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

<span class="c"># cert-manager 설치</span>
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm <span class="nb">install </span>cert-manager jetstack/cert-manager <span class="se">\</span>
  <span class="nt">--namespace</span> cert-manager <span class="nt">--create-namespace</span> <span class="se">\</span>
  <span class="nt">--set</span> crds.enabled<span class="o">=</span><span class="nb">true</span>
</code></pre></div></div>

<p>ClusterIssuer 등록:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># letsencrypt.yaml</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">cert-manager.io/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">ClusterIssuer</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">letsencrypt-prod</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">acme</span><span class="pi">:</span>
    <span class="na">server</span><span class="pi">:</span> <span class="s">https://acme-v02.api.letsencrypt.org/directory</span>
    <span class="na">email</span><span class="pi">:</span> <span class="s">admin@example.com</span>
    <span class="na">privateKeySecretRef</span><span class="pi">:</span>
      <span class="na">name</span><span class="pi">:</span> <span class="s">letsencrypt-prod</span>
    <span class="na">solvers</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">http01</span><span class="pi">:</span>
          <span class="na">ingress</span><span class="pi">:</span>
            <span class="na">ingressClassName</span><span class="pi">:</span> <span class="s">traefik</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> letsencrypt.yaml
</code></pre></div></div>

<p>이후 Ingress의 <code class="language-plaintext highlighter-rouge">tls:</code> 섹션과 <code class="language-plaintext highlighter-rouge">cert-manager.io/cluster-issuer</code> 어노테이션만 추가하면 인증서가 자동 발급·갱신됩니다.</p>

<hr />

<h2 id="6단계--모니터링과-로그">6단계 — 모니터링과 로그</h2>

<p>가벼운 환경에서는 Prometheus 풀스택보다 간단한 도구가 적합합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 컨테이너 단위 리소스 확인</span>
kubectl top pods <span class="nt">-A</span>
kubectl top nodes

<span class="c"># 특정 파드 로그</span>
kubectl logs <span class="nt">-f</span> deploy/nginx

<span class="c"># 컨테이너 안으로 진입</span>
kubectl <span class="nb">exec</span> <span class="nt">-it</span> deploy/nginx <span class="nt">--</span> /bin/sh
</code></pre></div></div>

<p>운영 모니터링이 필요하다면 <strong>k9s</strong>라는 TUI 도구가 매우 유용합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-sS</span> https://webinstall.dev/k9s | bash
k9s
</code></pre></div></div>

<hr />

<h2 id="7단계--백업">7단계 — 백업</h2>

<p>k3s의 상태는 SQLite 파일 하나에 저장됩니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># k3s 정지</span>
<span class="nb">sudo </span>systemctl stop k3s

<span class="c"># 백업</span>
<span class="nb">sudo cp</span> /var/lib/rancher/k3s/server/db/state.db /backup/k3s-<span class="si">$(</span><span class="nb">date</span> +%F<span class="si">)</span>.db

<span class="c"># 시작</span>
<span class="nb">sudo </span>systemctl start k3s
</code></pre></div></div>

<p>자동화된 백업이 필요하면 cron으로 매일 새벽 실행되도록 설정합니다.</p>

<hr />

<h2 id="운영-시-주의점">운영 시 주의점</h2>

<ul>
  <li><strong>단일 노드의 한계</strong> — 노드가 죽으면 모든 서비스가 죽습니다. 진짜 HA가 필요하면 노드 3대 + embedded etcd 모드로 구성하세요.</li>
  <li><strong>로컬 볼륨의 종속성</strong> — Local Path Provisioner는 호스트 디렉토리를 사용하므로, 노드를 옮기면 데이터도 함께 이동시켜야 합니다.</li>
  <li><strong>메모리 모니터링</strong> — k3s 자체는 가볍지만 그 위에서 도는 워크로드(Java, MySQL 등)가 메모리를 잡아먹습니다. 1GB VPS는 권장하지 않습니다.</li>
  <li><strong>포트 충돌</strong> — k3s는 6443(API), 10250(kubelet) 포트를 사용합니다. 외부에서 직접 접근할 일이 없다면 방화벽으로 막아두세요.</li>
</ul>

<hr />

<h2 id="마무리">마무리</h2>

<p>k3s는 “쿠버네티스 학습 비용은 그대로 가져가되, 운영 비용은 한 대 분량으로” 줄이고 싶을 때 가장 합리적인 선택입니다. TCP-80.NET의 <a href="https://tcp-80.net/virtual-server/">일본 VPS</a> 4GB 플랜이면 k3s + 웹 + DB + 캐시까지 모두 운영 가능합니다.</p>

<p>설치 중 막히는 부분이 있으면 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요. 한국어로 도와드립니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[풀 쿠버네티스는 메모리만 4GB 이상 잡아먹지만, k3s는 512MB로 동일한 API를 제공합니다. 일본 VPS 한 대에 k3s를 설치해 단일 노드 클러스터를 구성하고, Ingress·인증서·스토리지·배포까지 실전 절차를 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 IPv6 설정 가이드 — 듀얼 스택부터 방화벽, DNS까지</title><link href="https://tcp-80.net/blog/2026/04/15/japan-server-ipv6-guide/" rel="alternate" type="text/html" title="일본 서버 IPv6 설정 가이드 — 듀얼 스택부터 방화벽, DNS까지" /><published>2026-04-15T00:00:00+09:00</published><updated>2026-04-15T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/04/15/japan-server-ipv6-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/04/15/japan-server-ipv6-guide/"><![CDATA[<p>일본은 IPv6 보급이 빠른 국가 중 하나입니다. 2026년 기준 NTT, KDDI, SoftBank 등 주요 ISP의 가정·모바일 회선 상당수가 기본 IPv6입니다. 즉, <strong>일본 사용자 일부는 이미 IPv6로 들어옵니다</strong>. AAAA 레코드를 설정해두지 않으면 IPv4로 우회 접속이 일어나며, 일부 환경에서는 응답 지연으로 이어질 수 있습니다.</p>

<hr />

<h2 id="ipv6를-도입해야-할-때">IPv6를 도입해야 할 때</h2>

<p>다음 중 하나라도 해당된다면 도입을 고려해야 합니다.</p>

<ul>
  <li>일본 모바일·가정 사용자 비중이 큰 서비스</li>
  <li>신규 도메인 등록 시 가능한 표준을 모두 갖추고 싶을 때</li>
  <li>IPv4 주소 추가 발급이 어렵거나 비싼 환경</li>
  <li>메일 서버 운영 — 일부 메일 서비스(Gmail 등)는 IPv6 발신자에 더 엄격해서 정확한 PTR/SPF 정렬이 필수</li>
  <li>향후 CDN·외부 SaaS 연동에서 IPv6-only 엔드포인트를 만나는 경우</li>
</ul>

<p>반대로 IPv4만으로 충분한 사내 서비스, 단순 백엔드라면 굳이 도입할 필요가 없습니다.</p>

<hr />

<h2 id="1단계--서버에-ipv6가-할당되어-있는지-확인">1단계 — 서버에 IPv6가 할당되어 있는지 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ip <span class="nt">-6</span> addr show
<span class="c"># 또는</span>
ifconfig | <span class="nb">grep </span>inet6
</code></pre></div></div>

<p>IPv6 주소가 보이지 않거나 link-local(<code class="language-plaintext highlighter-rouge">fe80::</code>)만 보인다면 호스팅사에 글로벌 IPv6 주소를 요청해야 합니다. TCP-80.NET 서버를 사용 중이라면 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 IPv6 할당을 요청하면 됩니다.</p>

<p>라우팅 확인:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ip <span class="nt">-6</span> route show
ping6 <span class="nt">-c</span> 3 ipv6.google.com
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">ipv6.google.com</code> 응답이 정상이면 외부 IPv6 통신이 동작하는 상태입니다.</p>

<hr />

<h2 id="2단계--듀얼-스택-구성">2단계 — 듀얼 스택 구성</h2>

<p>대부분의 환경은 IPv4와 IPv6를 동시에 운영하는 <strong>듀얼 스택(Dual Stack)</strong> 입니다. 서비스별로 어떤 스택을 사용할지 결정합니다.</p>

<table>
  <thead>
    <tr>
      <th>서비스</th>
      <th>권장 스택</th>
      <th>비고</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>웹(80/443)</td>
      <td>IPv4 + IPv6</td>
      <td>AAAA 등록</td>
    </tr>
    <tr>
      <td>SSH</td>
      <td>IPv4만 (또는 둘 다 + 방화벽)</td>
      <td>공격 노출 면</td>
    </tr>
    <tr>
      <td>메일</td>
      <td>IPv4 + IPv6</td>
      <td>PTR 필수</td>
    </tr>
    <tr>
      <td>DB(외부 노출 안 함)</td>
      <td>내부 인터페이스만</td>
      <td>localhost 또는 사설망</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="3단계--dns-aaaa-레코드-등록">3단계 — DNS AAAA 레코드 등록</h2>

<p>서버의 글로벌 IPv6 주소를 도메인의 <code class="language-plaintext highlighter-rouge">AAAA</code> 레코드로 등록합니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>타입: AAAA
이름: @
값: 2001:db8:1234:5678::10
TTL: 300
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">www</code>, API 서브도메인 등 외부 노출이 필요한 모든 호스트에 동일하게 등록합니다.</p>

<p>전파 후 외부에서 검증:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dig AAAA example.com +short
<span class="c"># → 2001:db8:1234:5678::10</span>
</code></pre></div></div>

<hr />

<h2 id="4단계--nginx-듀얼-스택-바인딩">4단계 — Nginx 듀얼 스택 바인딩</h2>

<p>기본 설정은 IPv4만 듣는 경우가 많습니다. 다음 두 줄을 함께 적어 IPv6도 듣게 합니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
    <span class="kn">listen</span> <span class="s">[::]:80</span><span class="p">;</span>

    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span> <span class="s">http2</span><span class="p">;</span>
    <span class="kn">listen</span> <span class="s">[::]:443</span> <span class="s">ssl</span> <span class="s">http2</span><span class="p">;</span>

    <span class="kn">server_name</span> <span class="s">example.com</span> <span class="s">www.example.com</span><span class="p">;</span>
    <span class="c1"># ...</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">[::]</code>는 모든 IPv6 인터페이스에서 듣는다는 의미입니다. Apache, Caddy, Traefik도 동일한 개념의 듀얼 바인딩 설정을 지원합니다.</p>

<p>설정 적용 후 확인:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ss <span class="nt">-tlnp</span> | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s1">':(80|443)'</span>
<span class="c"># tcp LISTEN ... 0.0.0.0:80</span>
<span class="c"># tcp LISTEN ... [::]:80</span>
</code></pre></div></div>

<hr />

<h2 id="5단계--방화벽-규칙">5단계 — 방화벽 규칙</h2>

<p>IPv4와 <strong>별도로</strong> IPv6 규칙을 설정해야 합니다. iptables는 ip6tables, ufw는 자동으로 양쪽 규칙을 만들어 줍니다.</p>

<h3 id="ufw-사용-시">ufw 사용 시</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/default/ufw 에서 IPV6=yes 인지 확인</span>
<span class="nb">sudo grep </span>IPV6 /etc/default/ufw

<span class="c"># 규칙 추가 (ufw가 ip4·ip6 양쪽에 자동 적용)</span>
<span class="nb">sudo </span>ufw allow 22/tcp
<span class="nb">sudo </span>ufw allow 80,443/tcp
<span class="nb">sudo </span>ufw <span class="nb">enable
sudo </span>ufw status verbose
</code></pre></div></div>

<h3 id="iptables-직접-사용-시">iptables 직접 사용 시</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># IPv4</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">-m</span> multiport <span class="nt">--dports</span> 80,443 <span class="nt">-j</span> ACCEPT

<span class="c"># IPv6 — 별도로 설정해야 함</span>
ip6tables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">-m</span> multiport <span class="nt">--dports</span> 80,443 <span class="nt">-j</span> ACCEPT

<span class="c"># 영구 저장 (Debian/Ubuntu)</span>
apt <span class="nb">install </span>iptables-persistent
netfilter-persistent save
</code></pre></div></div>

<h3 id="nftables-사용-시-최신-권장">nftables 사용 시 (최신 권장)</h3>

<pre><code class="language-nft">table inet filter {
    chain input {
        type filter hook input priority 0;
        ct state established,related accept
        iif lo accept
        tcp dport { 22, 80, 443 } accept
        # IPv6 ND/RA는 반드시 허용해야 IPv6 자체가 동작
        icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert, echo-request } accept
        drop
    }
}
</code></pre>

<p><strong>중요:</strong> IPv6는 ICMPv6 메시지에 의존합니다. <strong>NDP(Neighbor Discovery), RA(Router Advertisement)</strong> 를 차단하면 IPv6 자체가 동작하지 않습니다. 무작정 ICMP 전체를 막으면 안 됩니다.</p>

<hr />

<h2 id="6단계--메일-서버라면-ptr과-spf">6단계 — 메일 서버라면 PTR과 SPF</h2>

<p>IPv6로 메일을 발송하면 수신 측은 <strong>IPv6 PTR(역방향 DNS)</strong> 을 매우 엄격히 봅니다. PTR이 없거나 일치하지 않으면 Gmail은 거의 무조건 차단합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 발신 서버 IPv6의 PTR 확인</span>
dig <span class="nt">-x</span> 2001:db8:1234:5678::10
</code></pre></div></div>

<p>PTR이 비어 있다면 호스팅사에 등록을 요청해야 합니다(개별 사용자가 직접 설정 불가). SPF 레코드도 IPv6를 포함해야 합니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>v=spf1 ip4:203.0.113.10 ip6:2001:db8:1234:5678::10 ~all
</code></pre></div></div>

<hr />

<h2 id="7단계--검증">7단계 — 검증</h2>

<p>브라우저로 <a href="https://test-ipv6.com">https://test-ipv6.com</a> 접속해 자신의 환경이 IPv6로 외부에 잘 닿는지 확인합니다. 서버 측 검증은 다음 도구를 사용합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 외부에서 서버에 IPv6로 접속되는지</span>
curl <span class="nt">-6</span> https://example.com <span class="nt">-I</span>

<span class="c"># IPv4와 IPv6 동시에 시도</span>
curl <span class="nt">-v</span> https://example.com 2&gt;&amp;1 | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"Trying|Connected"</span>
</code></pre></div></div>

<hr />

<h2 id="자주-발생하는-문제">자주 발생하는 문제</h2>

<p><strong>브라우저는 한국이고 사이트 응답이 매우 느려졌다</strong></p>
<ul>
  <li>한국 가정 ISP는 IPv6 보급률이 일본보다 낮습니다. AAAA 레코드를 등록했는데 IPv6 경로가 비정상이면 브라우저가 타임아웃 후 IPv4로 폴백하느라 첫 응답이 느려집니다.</li>
  <li>해결: 서버 측 IPv6가 정상인지 다시 확인하고, 비정상이면 일단 AAAA 레코드를 제거.</li>
</ul>

<p><strong>일부 사용자만 접속이 안 된다</strong></p>
<ul>
  <li>사용자의 IPv6 경로 문제일 가능성이 큽니다. 동일 ISP의 다른 사용자는 정상이라면 사용자 측 라우터 설정 문제로 추정됩니다.</li>
</ul>

<p><strong>SSH 접속에서 IPv6 주소가 자꾸 사용된다</strong></p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">~/.ssh/config</code>에 <code class="language-plaintext highlighter-rouge">AddressFamily inet</code>을 명시하거나 <code class="language-plaintext highlighter-rouge">ssh -4</code>로 명시 호출하면 IPv4를 강제할 수 있습니다.</li>
</ul>

<hr />

<h2 id="마무리">마무리</h2>

<p>IPv6는 거창한 기술이 아니라 “한 줄짜리 추가 설정의 모음”입니다. AAAA 레코드 한 줄, <code class="language-plaintext highlighter-rouge">listen [::]:</code> 한 줄, ip6tables 규칙 몇 줄로 시작할 수 있습니다.</p>

<p>TCP-80.NET의 <a href="https://tcp-80.net/dedicated-server/">일본 전용서버</a>와 <a href="https://tcp-80.net/virtual-server/">VPS</a>는 요청 시 IPv6 주소를 발급해 드립니다. PTR 등록도 함께 지원하니 메일 서버 운영 계획이 있다면 <a href="https://t.me/tcp80net">@tcp80net</a>으로 미리 알려주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="네트워크" /><summary type="html"><![CDATA[IPv4 주소 부족이 현실이 되면서 일본 서버에도 IPv6를 함께 운영하는 사례가 빠르게 늘고 있습니다. 듀얼 스택 구성, 방화벽 규칙, DNS AAAA 레코드, Nginx 바인딩 등 실무에서 바로 적용할 수 있는 IPv6 설정을 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">GitHub Actions로 일본 서버에 자동 배포 — SSH 키부터 무중단 재시작까지</title><link href="https://tcp-80.net/blog/2026/04/12/github-actions-japan-server-deploy/" rel="alternate" type="text/html" title="GitHub Actions로 일본 서버에 자동 배포 — SSH 키부터 무중단 재시작까지" /><published>2026-04-12T00:00:00+09:00</published><updated>2026-04-12T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/04/12/github-actions-japan-server-deploy</id><content type="html" xml:base="https://tcp-80.net/blog/2026/04/12/github-actions-japan-server-deploy/"><![CDATA[<p><code class="language-plaintext highlighter-rouge">git push</code> 한 번에 일본 서버까지 자동 배포되는 파이프라인을 만들면 휴먼 에러가 줄고, 새벽 배포 부담도 사라집니다. 이 글에서는 <strong>GitHub Actions + SSH 키</strong> 조합으로 가장 단순하고 안정적인 자동 배포 파이프라인을 구성합니다.</p>

<p><img src="/assets/img/posts/2026-04-12/github-actions-deploy.svg" alt="GitHub Actions → 일본 서버 자동 배포 파이프라인" /></p>

<hr />

<h2 id="전체-그림">전체 그림</h2>

<p>배포 단계는 4가지입니다.</p>

<ol>
  <li>개발자가 <code class="language-plaintext highlighter-rouge">main</code> 브랜치에 push</li>
  <li>GitHub Actions가 빌드 및 테스트</li>
  <li>SSH로 일본 서버에 접속해 새 코드 동기화</li>
  <li>서비스 재시작 (systemctl 또는 docker)</li>
</ol>

<p>각 단계를 하나씩 살펴보겠습니다.</p>

<hr />

<h2 id="1단계--서버에-배포-전용-사용자-만들기">1단계 — 서버에 배포 전용 사용자 만들기</h2>

<p><code class="language-plaintext highlighter-rouge">root</code>로 직접 배포하면 사고 위험이 큽니다. 권한이 제한된 <code class="language-plaintext highlighter-rouge">deploy</code> 사용자를 따로 만듭니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 일본 서버에서 실행</span>
<span class="nb">sudo </span>adduser <span class="nt">--disabled-password</span> <span class="nt">--gecos</span> <span class="s2">""</span> deploy
<span class="nb">sudo mkdir</span> <span class="nt">-p</span> /home/deploy/.ssh
<span class="nb">sudo chmod </span>700 /home/deploy/.ssh
<span class="nb">sudo chown</span> <span class="nt">-R</span> deploy:deploy /home/deploy/.ssh

<span class="c"># 애플리케이션 디렉토리 권한 부여</span>
<span class="nb">sudo mkdir</span> <span class="nt">-p</span> /var/www/myapp
<span class="nb">sudo chown</span> <span class="nt">-R</span> deploy:deploy /var/www/myapp

<span class="c"># systemctl restart 권한만 sudo 없이 허용</span>
<span class="nb">echo</span> <span class="s1">'deploy ALL=(ALL) NOPASSWD: /bin/systemctl restart myapp'</span> | <span class="nb">sudo tee</span> /etc/sudoers.d/deploy
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">NOPASSWD</code>로 허용하는 명령은 <strong>딱 필요한 것만</strong> 명시해야 합니다. <code class="language-plaintext highlighter-rouge">ALL</code>을 주면 사실상 root입니다.</p>

<hr />

<h2 id="2단계--ssh-키-페어-생성">2단계 — SSH 키 페어 생성</h2>

<p>로컬 PC에서 배포 전용 키를 만듭니다. 평소 개인 키와 분리하는 것이 좋습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-f</span> ~/.ssh/deploy_key <span class="nt">-N</span> <span class="s2">""</span> <span class="nt">-C</span> <span class="s2">"github-actions-deploy"</span>
</code></pre></div></div>

<p>생성된 공개키를 일본 서버의 <code class="language-plaintext highlighter-rouge">deploy</code> 사용자에게 등록합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 로컬에서 일본 서버로 전송</span>
ssh-copy-id <span class="nt">-i</span> ~/.ssh/deploy_key.pub deploy@your-server-ip

<span class="c"># 또는 수동으로</span>
<span class="nb">cat</span> ~/.ssh/deploy_key.pub | ssh root@your-server-ip <span class="s2">"cat &gt;&gt; /home/deploy/.ssh/authorized_keys &amp;&amp; chown deploy:deploy /home/deploy/.ssh/authorized_keys &amp;&amp; chmod 600 /home/deploy/.ssh/authorized_keys"</span>
</code></pre></div></div>

<p>연결 테스트:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh <span class="nt">-i</span> ~/.ssh/deploy_key deploy@your-server-ip <span class="s2">"whoami &amp;&amp; pwd"</span>
<span class="c"># → deploy</span>
<span class="c"># → /home/deploy</span>
</code></pre></div></div>

<hr />

<h2 id="3단계--github-repository-secrets-등록">3단계 — GitHub Repository Secrets 등록</h2>

<p>GitHub 저장소 → Settings → Secrets and variables → Actions에서 다음 시크릿을 등록합니다.</p>

<table>
  <thead>
    <tr>
      <th>이름</th>
      <th>값</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SERVER_HOST</code></td>
      <td>일본 서버 IP 또는 도메인</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SERVER_USER</code></td>
      <td><code class="language-plaintext highlighter-rouge">deploy</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SSH_PRIVATE_KEY</code></td>
      <td><code class="language-plaintext highlighter-rouge">~/.ssh/deploy_key</code> 파일 내용 전체</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SSH_PORT</code></td>
      <td><code class="language-plaintext highlighter-rouge">22</code> (또는 변경한 포트)</td>
    </tr>
  </tbody>
</table>

<p><code class="language-plaintext highlighter-rouge">SSH_PRIVATE_KEY</code>는 <code class="language-plaintext highlighter-rouge">cat ~/.ssh/deploy_key</code> 결과를 그대로 복사해서 붙여넣습니다. <code class="language-plaintext highlighter-rouge">-----BEGIN OPENSSH PRIVATE KEY-----</code> 부터 <code class="language-plaintext highlighter-rouge">-----END OPENSSH PRIVATE KEY-----</code> 까지 모두 포함해야 합니다.</p>

<hr />

<h2 id="4단계--github-actions-워크플로">4단계 — GitHub Actions 워크플로</h2>

<p><code class="language-plaintext highlighter-rouge">.github/workflows/deploy.yml</code> 파일을 생성합니다. 아래는 Node.js 앱 기준 예시입니다.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Deploy to Japan Server</span>

<span class="na">on</span><span class="pi">:</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">main</span><span class="pi">]</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">deploy</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Setup Node</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/setup-node@v4</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">node-version</span><span class="pi">:</span> <span class="s1">'</span><span class="s">20'</span>
          <span class="na">cache</span><span class="pi">:</span> <span class="s1">'</span><span class="s">npm'</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Install &amp; build</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">npm ci</span>
          <span class="s">npm run build</span>
          <span class="s">npm test</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy via SSH</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">appleboy/ssh-action@v1.0.3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">host</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">username</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">key</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">port</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">script</span><span class="pi">:</span> <span class="pi">|</span>
            <span class="s">cd /var/www/myapp</span>
            <span class="s">git fetch origin main</span>
            <span class="s">git reset --hard origin/main</span>
            <span class="s">npm ci --production</span>
            <span class="s">sudo systemctl restart myapp</span>
</code></pre></div></div>

<p>PHP/Python/Go도 빌드 단계만 바꾸면 동일한 구조로 적용 가능합니다.</p>

<hr />

<h2 id="5단계--정적-사이트jekyll-hugo-next-빌드-결과인-경우">5단계 — 정적 사이트(Jekyll, Hugo, Next 빌드 결과)인 경우</h2>

<p>빌드 결과물을 서버로 전송하는 형태가 더 깔끔합니다. <code class="language-plaintext highlighter-rouge">rsync</code>를 사용합니다.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Build site</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">bundle install</span>
          <span class="s">bundle exec jekyll build</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Setup SSH key</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">mkdir -p ~/.ssh</span>
          <span class="s">echo "$" &gt; ~/.ssh/deploy_key</span>
          <span class="s">chmod 600 ~/.ssh/deploy_key</span>
          <span class="s">ssh-keyscan -p $ $ &gt;&gt; ~/.ssh/known_hosts</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Rsync to server</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">rsync -avz --delete -e "ssh -i ~/.ssh/deploy_key -p $" \</span>
            <span class="s">_site/ $@$:/var/www/myapp/</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">--delete</code> 옵션은 서버 쪽 불필요 파일을 제거하므로 의도하지 않은 파일이 남는 일을 막습니다.</p>

<hr />

<h2 id="6단계--docker-사용-시">6단계 — Docker 사용 시</h2>

<p>이미지를 GitHub Container Registry에 올리고, 서버에서 pull → restart 하는 방식이 일반적입니다.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Login to GHCR</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">docker/login-action@v3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">registry</span><span class="pi">:</span> <span class="s">ghcr.io</span>
          <span class="na">username</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">password</span><span class="pi">:</span> <span class="s">$</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Build &amp; push</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">docker/build-push-action@v5</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">context</span><span class="pi">:</span> <span class="s">.</span>
          <span class="na">push</span><span class="pi">:</span> <span class="kc">true</span>
          <span class="na">tags</span><span class="pi">:</span> <span class="s">ghcr.io/$:latest</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Deploy</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">appleboy/ssh-action@v1.0.3</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">host</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">username</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">key</span><span class="pi">:</span> <span class="s">$</span>
          <span class="na">script</span><span class="pi">:</span> <span class="pi">|</span>
            <span class="s">cd /opt/myapp</span>
            <span class="s">docker compose pull</span>
            <span class="s">docker compose up -d</span>
            <span class="s">docker image prune -f</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">docker compose up -d</code>는 변경된 컨테이너만 재생성하므로 다른 서비스에는 영향이 없습니다.</p>

<hr />

<h2 id="보안-체크리스트">보안 체크리스트</h2>

<p>배포 자동화는 잘못 만들면 자동 해킹 도구가 됩니다. 반드시 확인하세요.</p>

<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">deploy</code> 사용자에게 비밀번호 로그인 차단 (<code class="language-plaintext highlighter-rouge">PasswordAuthentication no</code>)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">deploy</code> 사용자의 sudo 권한은 <strong>재시작 명령으로만</strong> 제한</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />SSH 포트는 22 외 다른 포트로 변경 (자동화 도구의 무차별 공격 회피)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">authorized_keys</code>에는 GitHub Actions용 키 외 다른 키 없음</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />워크플로 파일에 직접 IP/비밀번호를 적지 말고 항상 Secrets 사용</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">pull_request</code> 트리거에는 secrets가 노출될 수 있으므로 신중히 사용</li>
</ul>

<hr />

<h2 id="흔한-트러블슈팅">흔한 트러블슈팅</h2>

<p><strong><code class="language-plaintext highlighter-rouge">Permission denied (publickey)</code></strong></p>
<ul>
  <li>서버의 <code class="language-plaintext highlighter-rouge">/home/deploy/.ssh/authorized_keys</code> 권한이 600인지, 디렉토리는 700인지 확인</li>
  <li>등록한 시크릿이 <strong>공개키가 아닌 개인키</strong>인지 확인 (실수가 매우 잦습니다)</li>
</ul>

<p><strong><code class="language-plaintext highlighter-rouge">Host key verification failed</code></strong></p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">ssh-keyscan</code> 단계가 누락되었거나, 서버가 호스트 키를 변경했을 때</li>
  <li><code class="language-plaintext highlighter-rouge">appleboy/ssh-action</code> 사용 시 자동 처리되지만, 직접 <code class="language-plaintext highlighter-rouge">ssh</code> 호출 시에는 명시 필요</li>
</ul>

<p><strong>빌드는 성공했는데 서버에서 옛날 버전이 도는 경우</strong></p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">git pull</code>이 충돌로 실패한 채 무시되었을 가능성</li>
  <li><code class="language-plaintext highlighter-rouge">git reset --hard origin/main</code>으로 강제 동기화하거나, 빌드 결과를 rsync하는 방식으로 전환</li>
</ul>

<hr />

<h2 id="마무리">마무리</h2>

<p>자동 배포의 본질은 “에러는 자동화하지 않고, 안전한 동작만 자동화”입니다. 테스트 단계를 충실히 두면 잘못된 코드가 일본 서버에 닿기 전에 차단할 수 있습니다.</p>

<p>TCP-80.NET의 <a href="https://tcp-80.net/virtual-server/">일본 VPS</a>는 SSH 포트 변경, 방화벽 설정 등에 대해 텔레그램으로 한국어 안내를 제공합니다. CI/CD 환경 구성 중 문의가 있으시면 <a href="https://t.me/tcp80net">@tcp80net</a>으로 부담 없이 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[매번 수동으로 git pull · 빌드 · 재시작을 반복하고 있다면 GitHub Actions로 자동화할 시점입니다. SSH 키 등록부터 빌드, 무중단 재시작 스크립트까지 일본 서버 배포 파이프라인을 처음부터 끝까지 안내합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Cloudflare와 일본 서버 연동 가이드 — CDN, DNS, WAF 한 번에</title><link href="https://tcp-80.net/blog/2026/04/09/cloudflare-japan-server-integration/" rel="alternate" type="text/html" title="Cloudflare와 일본 서버 연동 가이드 — CDN, DNS, WAF 한 번에" /><published>2026-04-09T00:00:00+09:00</published><updated>2026-04-09T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/04/09/cloudflare-japan-server-integration</id><content type="html" xml:base="https://tcp-80.net/blog/2026/04/09/cloudflare-japan-server-integration/"><![CDATA[<p>일본 서버는 한국과 가까워 RTT가 20~40ms로 충분히 빠르지만, 글로벌 사용자나 정적 콘텐츠가 많은 사이트라면 Cloudflare를 앞단에 두는 것이 효과적입니다. 캐싱·CDN뿐 아니라 <strong>오리진 IP 은폐, L7 DDoS 방어, 무료 SSL</strong> 까지 한꺼번에 해결됩니다.</p>

<p><img src="/assets/img/posts/2026-04-09/cloudflare-japan-flow.svg" alt="Cloudflare + 일본 서버 트래픽 흐름" /></p>

<hr />

<h2 id="왜-일본-서버--cloudflare-조합인가">왜 일본 서버 + Cloudflare 조합인가</h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>일본 서버 단독</th>
      <th>일본 서버 + Cloudflare</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>한국·일본 응답 속도</td>
      <td>빠름 (직접 도쿄 IDC)</td>
      <td>더 빠름 (가까운 PoP 캐시)</td>
    </tr>
    <tr>
      <td>글로벌 응답 속도</td>
      <td>느림</td>
      <td>빠름 (전 세계 PoP)</td>
    </tr>
    <tr>
      <td>DDoS 방어</td>
      <td>L3/L4만 (호스팅사 제공)</td>
      <td>L7까지 추가</td>
    </tr>
    <tr>
      <td>오리진 IP 노출</td>
      <td>노출됨</td>
      <td>숨겨짐</td>
    </tr>
    <tr>
      <td>SSL 인증서</td>
      <td>직접 발급·갱신</td>
      <td>Cloudflare 자동</td>
    </tr>
  </tbody>
</table>

<p>특히 <strong>오리진 IP 은폐</strong>는 보안상 큰 차이를 만듭니다. 공격자가 IP를 특정하지 못하면 직접 공격이 불가능해지기 때문입니다.</p>

<hr />

<h2 id="1단계--도메인을-cloudflare에-추가">1단계 — 도메인을 Cloudflare에 추가</h2>

<ol>
  <li><a href="https://dash.cloudflare.com">https://dash.cloudflare.com</a> 가입 후 <strong>Add a Site</strong> 선택</li>
  <li>도메인 입력 → 무료 플랜 선택</li>
  <li>Cloudflare가 기존 DNS 레코드를 자동으로 가져옵니다</li>
</ol>

<p>기존 레코드가 누락되거나 잘못 가져온 경우 직접 추가해야 합니다. 특히 메일 관련 MX, SPF(TXT) 레코드는 누락되기 쉽습니다.</p>

<hr />

<h2 id="2단계--네임서버-변경">2단계 — 네임서버 변경</h2>

<p>도메인 등록업체(가비아, Whois, 일본 Onamae 등)에서 <strong>네임서버</strong>를 Cloudflare가 안내한 두 개로 변경합니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>예시:
  ada.ns.cloudflare.com
  ben.ns.cloudflare.com
</code></pre></div></div>

<p>전파에는 보통 수 분에서 24시간이 걸립니다. Cloudflare 대시보드의 <strong>Overview</strong> 탭에서 활성화 여부를 확인할 수 있습니다.</p>

<hr />

<h2 id="3단계--a-레코드와-프록시-설정">3단계 — A 레코드와 프록시 설정</h2>

<p><code class="language-plaintext highlighter-rouge">A</code> 레코드는 일본 서버 IP를 가리키게 하되, <strong>주황색 구름(프록시 ON)</strong> 으로 설정합니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>타입: A
이름: @
값: 203.0.113.10  (일본 서버 IP)
프록시 상태: 프록시됨 (Proxied) — 주황 구름
</code></pre></div></div>

<ul>
  <li>회색 구름(DNS only): 사용자는 서버 IP를 직접 알게 됨 → 공격에 노출</li>
  <li>주황 구름(Proxied): 사용자는 Cloudflare IP만 봄 → 오리진 IP 은폐</li>
</ul>

<p><code class="language-plaintext highlighter-rouge">www</code> 서브도메인도 동일하게 설정하거나 CNAME으로 루트를 가리키게 합니다.</p>

<hr />

<h2 id="4단계--ssltls-모드">4단계 — SSL/TLS 모드</h2>

<p>Cloudflare 대시보드 → SSL/TLS → Overview에서 모드를 선택합니다.</p>

<table>
  <thead>
    <tr>
      <th>모드</th>
      <th>동작</th>
      <th>권장도</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Off</td>
      <td>모두 HTTP</td>
      <td>✕ 절대 사용 금지</td>
    </tr>
    <tr>
      <td>Flexible</td>
      <td>사용자↔CF는 HTTPS, CF↔서버는 HTTP</td>
      <td>✕ 보안 취약</td>
    </tr>
    <tr>
      <td>Full</td>
      <td>양쪽 HTTPS, 인증서 검증 안 함</td>
      <td>△ 자체 서명 인증서 가능</td>
    </tr>
    <tr>
      <td><strong>Full (strict)</strong></td>
      <td>양쪽 HTTPS, 인증서 검증</td>
      <td>✓ 권장</td>
    </tr>
  </tbody>
</table>

<p><code class="language-plaintext highlighter-rouge">Full (strict)</code> 모드를 사용하려면 오리진 서버에 유효한 인증서가 있어야 합니다. Let’s Encrypt를 그대로 써도 되고, Cloudflare가 무료로 제공하는 <strong>Origin Certificate</strong>(15년 유효)를 사용하는 것이 편합니다.</p>

<hr />

<h2 id="5단계--오리진-보호-가장-중요">5단계 — 오리진 보호 (가장 중요)</h2>

<p>Cloudflare 프록시를 설정해도 누군가 과거 IP를 알고 있다면 직접 공격이 가능합니다. 서버 방화벽에서 <strong>Cloudflare IP만</strong> 허용해야 진정한 보호가 됩니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Cloudflare가 게시하는 IP 목록 (최신본은 cloudflare.com/ips 참조)</span>
<span class="nv">CF_IPS</span><span class="o">=</span><span class="si">$(</span>curl <span class="nt">-s</span> https://www.cloudflare.com/ips-v4<span class="si">)</span>

<span class="c"># 80, 443 포트는 Cloudflare IP만 허용</span>
<span class="k">for </span>ip <span class="k">in</span> <span class="nv">$CF_IPS</span><span class="p">;</span> <span class="k">do
  </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">-m</span> multiport <span class="nt">--dports</span> 80,443 <span class="nt">-s</span> <span class="nv">$ip</span> <span class="nt">-j</span> ACCEPT
<span class="k">done</span>

<span class="c"># 그 외 직접 접근은 차단</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">-m</span> multiport <span class="nt">--dports</span> 80,443 <span class="nt">-j</span> DROP
</code></pre></div></div>

<p>ufw를 사용하는 경우:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for </span>ip <span class="k">in</span> <span class="si">$(</span>curl <span class="nt">-s</span> https://www.cloudflare.com/ips-v4<span class="si">)</span><span class="p">;</span> <span class="k">do
  </span>ufw allow from <span class="nv">$ip</span> to any port 80,443 proto tcp
<span class="k">done</span>
</code></pre></div></div>

<p>Nginx에서 실제 클라이언트 IP를 로그에 남기려면 <code class="language-plaintext highlighter-rouge">real_ip</code> 모듈을 설정합니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/conf.d/cloudflare-realip.conf</span>
<span class="k">set_real_ip_from</span> <span class="mf">173.245</span><span class="s">.48.0/20</span><span class="p">;</span>
<span class="k">set_real_ip_from</span> <span class="mf">103.21</span><span class="s">.244.0/22</span><span class="p">;</span>
<span class="c1"># ... (Cloudflare IP 전체 목록을 추가)</span>
<span class="k">real_ip_header</span> <span class="s">CF-Connecting-IP</span><span class="p">;</span>
</code></pre></div></div>

<hr />

<h2 id="6단계--캐시-정책">6단계 — 캐시 정책</h2>

<p>기본 설정에서도 정적 자산(이미지, CSS, JS)은 캐시되지만, <strong>HTML까지 캐시</strong>하려면 Page Rules 또는 Cache Rules를 추가합니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Cache Rules 예시:
  Hostname equals example.com
  → Cache Level: Cache Everything
  → Edge TTL: 2 hours
  → Browser TTL: 4 hours
</code></pre></div></div>

<p>WordPress 같은 동적 사이트는 로그인 사용자에게 캐시된 페이지가 보이지 않도록 다음 쿠키를 <strong>Bypass Cache</strong> 조건으로 추가합니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wp-.*
wordpress_logged_in_.*
comment_author_.*
</code></pre></div></div>

<hr />

<h2 id="7단계--waf--bot-차단">7단계 — WAF / Bot 차단</h2>

<p>Security → WAF → Custom Rules에서 패턴 기반 차단 규칙을 만들 수 있습니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>규칙 예시:
  - User-Agent에 "sqlmap" 또는 "nikto" 포함 → Block
  - Country가 특정 국가가 아니면서 /wp-login.php 접근 → Challenge
  - 분당 100회 이상 동일 IP 요청 → Rate limit
</code></pre></div></div>

<p><strong>Bot Fight Mode</strong>를 켜면 알려진 악성 봇과 데이터센터 IP를 자동으로 차단합니다(무료 플랜에서 사용 가능).</p>

<hr />

<h2 id="흔히-빠지는-함정">흔히 빠지는 함정</h2>

<ol>
  <li><strong>MX 레코드를 프록시하지 않기</strong> — 메일 관련 레코드(MX, mail.도메인)는 회색 구름(DNS only)으로 두어야 합니다. 프록시할 수 없는 프로토콜입니다.</li>
  <li><strong>DNS 전파 전 강제 HTTPS 켜기</strong> — Full (strict)로 켜둔 상태에서 오리진에 인증서가 없으면 <strong>에러 526</strong>이 발생합니다. 먼저 인증서 설치 → 모드 변경 순으로 진행하세요.</li>
  <li><strong>오리진 IP 누출</strong> — Cloudflare 적용 후에도 메일 서버, FTP, cPanel 등이 직접 같은 IP를 사용하면 IP가 알려집니다. 메일 발송은 별도 IP에서 하거나 외부 SMTP를 쓰는 것이 안전합니다.</li>
  <li><strong>개발 모드 켜둔 채 방치</strong> — Cloudflare의 “Development Mode”는 캐시를 끄는 임시 옵션입니다. 3시간 후 자동 해제되지만, 의도치 않게 켜둔 채 광고를 돌리면 캐시 효과가 사라집니다.</li>
</ol>

<hr />

<h2 id="마무리">마무리</h2>

<p>Cloudflare는 일본 서버의 약점인 글로벌 응답 속도를 보완하면서, 동시에 오리진 보호와 L7 방어까지 무료로 제공합니다. <strong>오리진 방화벽 → Cloudflare IP 허용 리스트</strong> 설정은 반드시 함께 적용해야 효과를 볼 수 있습니다.</p>

<p>TCP-80.NET의 <a href="https://tcp-80.net/virtual-server/">일본 VPS</a>와 <a href="https://tcp-80.net/dedicated-server/">전용서버</a>는 모두 L3/L4 네트워크 단 DDoS 방어가 기본 포함되므로, Cloudflare와 결합하면 L3~L7 전 계층 방어를 갖출 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버 앞단에 Cloudflare를 두면 한국·일본 사용자 모두에게 빠른 응답을 제공하고, 오리진 IP 노출을 막아 직접 공격을 차단할 수 있습니다. DNS 위임부터 캐시 정책, 오리진 보호까지 실전 절차를 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">DDoS 방어의 원리 — 공격 트래픽은 어떻게 걸러지는가</title><link href="https://tcp-80.net/blog/2026/04/07/ddos-defense-principles/" rel="alternate" type="text/html" title="DDoS 방어의 원리 — 공격 트래픽은 어떻게 걸러지는가" /><published>2026-04-07T00:00:00+09:00</published><updated>2026-04-07T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/04/07/ddos-defense-principles</id><content type="html" xml:base="https://tcp-80.net/blog/2026/04/07/ddos-defense-principles/"><![CDATA[<p>“DDoS 방어 서비스를 사용하면 공격이 막힌다”는 건 알지만, <strong>어떤 원리로</strong> 수백 Gbps의 공격 트래픽 속에서 정상 사용자만 골라내는지 궁금했던 적이 있으신가요? 이 글에서는 DDoS 방어의 핵심 메커니즘을 단계별로 설명합니다.</p>

<hr />

<h2 id="다계층-방어-구조">다계층 방어 구조</h2>

<p>DDoS 방어는 한 가지 기술로 해결되지 않습니다. 공격 트래픽이 서버에 도달하기까지 여러 계층을 거치면서 단계적으로 걸러지는 <strong>다계층(Multi-layer) 방어</strong> 구조가 핵심입니다.</p>

<p><img src="/assets/img/posts/2026-04-07/ddos-defense-layers.svg" alt="DDoS 방어 다계층 구조" /></p>

<table>
  <thead>
    <tr>
      <th>방어 계층</th>
      <th>역할</th>
      <th>차단 대상</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>ISP / 상위 네트워크</td>
      <td>대용량 볼류메트릭 공격 차단</td>
      <td>UDP Flood, ICMP Flood, DNS Amplification</td>
    </tr>
    <tr>
      <td>스크러빙 센터</td>
      <td>정밀 트래픽 분석 및 필터링</td>
      <td>SYN Flood, 프로토콜 이상, 봇 트래픽</td>
    </tr>
    <tr>
      <td>서버 레벨</td>
      <td>잔여 공격 차단, 세밀한 제어</td>
      <td>Slowloris, HTTP Flood, 비정상 요청</td>
    </tr>
  </tbody>
</table>

<p>각 단계를 통과할 때마다 공격 트래픽이 제거되어, 최종적으로 서버에는 정상 트래픽만 도달합니다.</p>

<hr />

<h2 id="1단계--isp--상위-네트워크-방어">1단계 — ISP / 상위 네트워크 방어</h2>

<p>서버가 위치한 데이터센터의 상위 네트워크(ISP)에서 수행하는 방어입니다. 대용량 트래픽 공격을 가장 먼저 걸러냅니다.</p>

<h3 id="bgp-blackhole-routing">BGP Blackhole Routing</h3>

<p>공격이 감지되면 해당 IP로 향하는 트래픽을 네트워크 경계에서 <strong>모두 폐기(Blackhole)</strong> 하는 방식입니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>정상적인 라우팅:
  인터넷 → ISP → 데이터센터 → 서버 (공격 트래픽도 함께 도달)

BGP Blackhole 적용 후:
  인터넷 → ISP → /dev/null (트래픽 전체 폐기)
</code></pre></div></div>

<ul>
  <li><strong>장점:</strong> 수백 Gbps 공격도 즉시 차단 가능</li>
  <li><strong>단점:</strong> 정상 트래픽도 함께 차단됨 — 서비스 중단과 같은 효과</li>
  <li><strong>용도:</strong> 공격 규모가 너무 커서 다른 방어가 불가능할 때 최후의 수단</li>
</ul>

<h3 id="bgp-flowspec">BGP Flowspec</h3>

<p>Blackhole보다 정밀한 방식입니다. 특정 <strong>프로토콜, 포트, 패킷 크기</strong> 등을 기준으로 필터링 규칙을 동적으로 배포합니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>예시 Flowspec 규칙:
  목적지: 203.0.113.10
  프로토콜: UDP
  포트: != 53 (DNS 제외)
  동작: DROP

→ 해당 IP로 오는 UDP 트래픽 중 DNS 외 전부 차단
→ 정상적인 DNS 응답은 통과
</code></pre></div></div>

<h3 id="acl-기반-필터링">ACL 기반 필터링</h3>

<p>라우터/스위치 레벨에서 <strong>출발지 IP, 프로토콜, 포트</strong> 기반으로 패킷을 차단합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 일반적인 ACL 필터 예시 (Cisco IOS 형식)</span>
access-list 101 deny udp any host 203.0.113.10 eq 80
access-list 101 deny icmp any any <span class="nb">echo
</span>access-list 101 permit ip any any
</code></pre></div></div>

<hr />

<h2 id="2단계--스크러빙-센터">2단계 — 스크러빙 센터</h2>

<p>DDoS 방어의 핵심 기술입니다. 공격 트래픽과 정상 트래픽을 <strong>분리(Scrubbing)</strong> 하여, 정상 트래픽만 오리진 서버로 전달합니다.</p>

<p><img src="/assets/img/posts/2026-04-07/ddos-scrubbing-flow.svg" alt="스크러빙 센터 동작 원리" /></p>

<h3 id="동작-과정">동작 과정</h3>

<p><strong>1) 트래픽 우회(Diversion)</strong></p>

<p>공격이 감지되면 서버로 향하는 트래픽을 스크러빙 센터로 우회시킵니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>평상시:
  사용자 → ISP → 데이터센터 → 서버

공격 감지 시:
  사용자 → ISP → [스크러빙 센터] → 데이터센터 → 서버
</code></pre></div></div>

<p>우회 방법은 크게 두 가지입니다:</p>

<ul>
  <li><strong>BGP 경로 변경:</strong> 서버 IP의 라우팅 경로를 스크러빙 센터로 변경</li>
  <li><strong>DNS 변경:</strong> 도메인이 스크러빙 센터의 IP를 가리키도록 변경 (프록시 방식)</li>
</ul>

<p><strong>2) 심층 패킷 분석(DPI)</strong></p>

<p>스크러빙 센터에 도착한 트래픽은 패킷 단위로 정밀 분석됩니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>분석 항목:
├── 프로토콜 유효성 — TCP 핸드셰이크가 정상적인가?
├── 페이로드 패턴 — 알려진 공격 시그니처와 일치하는가?
├── 통계적 이상 — 평소 대비 트래픽 패턴이 비정상인가?
├── IP 평판 — 이 IP가 봇넷에 속한 것으로 알려져 있는가?
└── 행위 분석 — 실제 브라우저/클라이언트 행위와 일치하는가?
</code></pre></div></div>

<p><strong>3) 필터링 및 전달(Injection)</strong></p>

<p>분석 결과에 따라 악성 트래픽은 폐기하고, 정상 트래픽만 GRE 터널이나 직접 연결을 통해 오리진 서버로 전달합니다.</p>

<hr />

<h2 id="3단계--서버-레벨-방어">3단계 — 서버 레벨 방어</h2>

<p>상위 단계에서 대부분의 공격이 걸러지지만, 서버 자체에서도 추가 방어를 설정해야 합니다. 특히 <strong>L7(애플리케이션) 공격</strong>은 정상 요청과 구분이 어려워 서버 레벨 방어가 중요합니다.</p>

<h3 id="syn-cookie--syn-flood-방어의-핵심">SYN Cookie — SYN Flood 방어의 핵심</h3>

<p>SYN Flood는 TCP 3-way 핸드셰이크를 악용한 공격입니다. 공격자가 대량의 SYN 패킷을 보내고 ACK를 보내지 않으면, 서버의 연결 테이블이 가득 차서 정상 접속이 불가능해집니다.</p>

<p><strong>SYN Cookie의 원리:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>일반적인 TCP 핸드셰이크:
  클라이언트 → SYN → 서버 (서버가 연결 정보를 메모리에 저장)
  서버 → SYN-ACK → 클라이언트
  클라이언트 → ACK → 서버 (연결 성립)

SYN Cookie 적용 시:
  클라이언트 → SYN → 서버 (메모리에 저장하지 않음!)
  서버 → SYN-ACK → 클라이언트
    └→ 시퀀스 번호에 연결 정보를 암호화하여 포함 (= Cookie)
  클라이언트 → ACK → 서버
    └→ 서버가 ACK의 시퀀스 번호에서 연결 정보를 복원
    └→ 정상 ACK가 돌아온 경우에만 연결 성립
</code></pre></div></div>

<p>핵심은 <strong>ACK가 돌아올 때까지 서버 메모리를 전혀 사용하지 않는다</strong>는 것입니다. 공격자가 아무리 많은 SYN을 보내도 메모리가 고갈되지 않습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Linux에서 SYN Cookie 활성화</span>
sysctl <span class="nt">-w</span> net.ipv4.tcp_syncookies<span class="o">=</span>1

<span class="c"># 영구 적용</span>
<span class="nb">echo</span> <span class="s2">"net.ipv4.tcp_syncookies = 1"</span> <span class="o">&gt;&gt;</span> /etc/sysctl.conf
sysctl <span class="nt">-p</span>
</code></pre></div></div>

<h3 id="connection-tracking-제한">Connection Tracking 제한</h3>

<p>Linux의 <code class="language-plaintext highlighter-rouge">conntrack</code>은 모든 네트워크 연결을 추적합니다. DDoS 공격 시 이 테이블이 가득 차면 정상 연결도 거부됩니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 현재 conntrack 사용량 확인</span>
<span class="nb">cat</span> /proc/sys/net/netfilter/nf_conntrack_count
<span class="nb">cat</span> /proc/sys/net/netfilter/nf_conntrack_max

<span class="c"># 최대값 상향 (메모리에 여유가 있을 때)</span>
sysctl <span class="nt">-w</span> net.netfilter.nf_conntrack_max<span class="o">=</span>1048576

<span class="c"># 연결 추적 타임아웃 단축</span>
sysctl <span class="nt">-w</span> net.netfilter.nf_conntrack_tcp_timeout_established<span class="o">=</span>600
sysctl <span class="nt">-w</span> net.netfilter.nf_conntrack_tcp_timeout_time_wait<span class="o">=</span>30
</code></pre></div></div>

<h3 id="iptables-rate-limiting">iptables Rate Limiting</h3>

<p>동일 IP에서 과도한 요청을 보내는 경우 iptables로 제한할 수 있습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 동일 IP에서 초당 새 연결 20개 제한</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-m</span> connlimit <span class="nt">--connlimit-above</span> 50 <span class="nt">-j</span> DROP
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-m</span> limit <span class="nt">--limit</span> 20/s <span class="nt">--limit-burst</span> 40 <span class="nt">-j</span> ACCEPT

<span class="c"># 비정상 패킷 차단</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--tcp-flags</span> ALL NONE <span class="nt">-j</span> DROP
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--tcp-flags</span> ALL ALL <span class="nt">-j</span> DROP
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="o">!</span> <span class="nt">--syn</span> <span class="nt">-m</span> state <span class="nt">--state</span> NEW <span class="nt">-j</span> DROP
</code></pre></div></div>

<h3 id="nginx-rate-limiting">Nginx Rate Limiting</h3>

<p>L7 공격에 대한 방어입니다. 동일 IP에서 과도한 HTTP 요청을 제한합니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/nginx.conf</span>
<span class="k">http</span> <span class="p">{</span>
    <span class="c1"># 요청 속도 제한 존 정의 (IP당 초당 10요청)</span>
    <span class="kn">limit_req_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=req_limit:10m</span> <span class="s">rate=10r/s</span><span class="p">;</span>

    <span class="c1"># 연결 수 제한 존 정의 (IP당 동시 연결 20개)</span>
    <span class="kn">limit_conn_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=conn_limit:10m</span><span class="p">;</span>

    <span class="kn">server</span> <span class="p">{</span>
        <span class="c1"># 요청 속도 제한 적용 (burst 허용 20개, 초과 시 지연 없이 거부)</span>
        <span class="kn">limit_req</span> <span class="s">zone=req_limit</span> <span class="s">burst=20</span> <span class="s">nodelay</span><span class="p">;</span>

        <span class="c1"># 동시 연결 수 제한</span>
        <span class="kn">limit_conn</span> <span class="s">conn_limit</span> <span class="mi">20</span><span class="p">;</span>

        <span class="c1"># 요청 본문 크기 제한 (Slowloris 변형 방어)</span>
        <span class="kn">client_body_timeout</span> <span class="s">10s</span><span class="p">;</span>
        <span class="kn">client_header_timeout</span> <span class="s">10s</span><span class="p">;</span>
        <span class="kn">client_max_body_size</span> <span class="mi">1m</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="bgp-anycast--대규모-방어의-핵심-인프라">BGP Anycast — 대규모 방어의 핵심 인프라</h2>

<p>전 세계에 분산된 여러 지점에서 <strong>동일한 IP 주소</strong>를 광고하여, 사용자(또는 공격자)의 트래픽이 가장 가까운 지점으로 자동 라우팅되게 하는 기술입니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Anycast 없이:
  모든 공격 트래픽 → 서버 1대로 집중 → 대역폭 초과 → 서비스 다운

Anycast 적용:
  공격 트래픽 → 전 세계 PoP(Point of Presence)으로 분산
  ├→ 도쿄 PoP: 30Gbps 처리
  ├→ 싱가포르 PoP: 25Gbps 처리
  ├→ LA PoP: 20Gbps 처리
  └→ 프랑크푸르트 PoP: 25Gbps 처리
  총 100Gbps 공격이 4곳으로 분산 → 각 지점에서 처리 가능
</code></pre></div></div>

<p>Cloudflare, Akamai 같은 대형 DDoS 방어 업체가 수십 Tbps 규모의 공격을 방어할 수 있는 이유가 바로 이 Anycast 네트워크 덕분입니다.</p>

<hr />

<h2 id="l7-방어--봇과-사람을-구분하는-원리">L7 방어 — 봇과 사람을 구분하는 원리</h2>

<p>L3/L4 공격은 패킷 수준에서 비교적 쉽게 구분할 수 있지만, L7 공격은 <strong>정상적인 HTTP 요청과 동일한 형태</strong>를 띠기 때문에 구분이 어렵습니다.</p>

<h3 id="javascript-challenge">JavaScript Challenge</h3>

<p>사용자의 브라우저에 JavaScript를 실행시켜, 실제 브라우저인지 확인합니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. 서버가 JavaScript 챌린지 페이지 응답
2. 정상 브라우저: JS 실행 → 계산 결과 전송 → 통과
3. 봇/스크립트: JS 실행 불가 → 차단
</code></pre></div></div>

<h3 id="행위-기반-분석-behavioral-analysis">행위 기반 분석 (Behavioral Analysis)</h3>

<p>정상 사용자와 봇의 행동 패턴 차이를 분석합니다.</p>

<table>
  <thead>
    <tr>
      <th>행위</th>
      <th>정상 사용자</th>
      <th>봇/공격</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>요청 간격</td>
      <td>불규칙적</td>
      <td>매우 일정</td>
    </tr>
    <tr>
      <td>마우스 이동</td>
      <td>자연스러운 곡선</td>
      <td>없음 또는 직선</td>
    </tr>
    <tr>
      <td>쿠키/세션</td>
      <td>유지</td>
      <td>없거나 비정상</td>
    </tr>
    <tr>
      <td>User-Agent</td>
      <td>일관된 브라우저 정보</td>
      <td>무작위 또는 비어 있음</td>
    </tr>
    <tr>
      <td>요청 순서</td>
      <td>HTML → CSS → JS → 이미지</td>
      <td>HTML만 반복</td>
    </tr>
  </tbody>
</table>

<h3 id="rate-limiting--ip-평판">Rate Limiting + IP 평판</h3>

<ul>
  <li>동일 IP에서 비정상적으로 많은 요청 → 속도 제한 후 차단</li>
  <li>알려진 봇넷 IP, TOR 출구 노드, 데이터센터 IP 등을 평판 DB로 관리</li>
  <li>평판이 낮은 IP에 더 강한 검증 적용</li>
</ul>

<hr />

<h2 id="방어-방식-비교-요약">방어 방식 비교 요약</h2>

<table>
  <thead>
    <tr>
      <th>방어 방식</th>
      <th>방어 가능 공격</th>
      <th>장점</th>
      <th>단점</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>BGP Blackhole</td>
      <td>모든 볼류메트릭</td>
      <td>즉시 적용, 간단</td>
      <td>정상 트래픽도 차단</td>
    </tr>
    <tr>
      <td>BGP Flowspec</td>
      <td>L3/L4</td>
      <td>선별적 차단 가능</td>
      <td>ISP 지원 필요</td>
    </tr>
    <tr>
      <td>스크러빙 센터</td>
      <td>L3/L4/L7</td>
      <td>정밀 분석, 정상 트래픽 보존</td>
      <td>비용, 지연 추가</td>
    </tr>
    <tr>
      <td>SYN Cookie</td>
      <td>SYN Flood</td>
      <td>서버 자체 적용 가능</td>
      <td>TCP 옵션 일부 제한</td>
    </tr>
    <tr>
      <td>Rate Limiting</td>
      <td>L7 Flood</td>
      <td>간단한 설정</td>
      <td>오탐 가능성</td>
    </tr>
    <tr>
      <td>JS Challenge</td>
      <td>L7 봇 공격</td>
      <td>높은 정확도</td>
      <td>JS 미지원 클라이언트 차단</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="마무리">마무리</h2>

<p>DDoS 방어의 핵심은 <strong>단일 솔루션이 아닌 다계층 구조</strong>에 있습니다. 상위 네트워크에서 대용량 공격을 흡수하고, 스크러빙 센터에서 정밀 필터링하며, 서버 레벨에서 잔여 공격을 처리하는 구조가 효과적입니다.</p>

<p>직접 모든 방어를 구축하기보다는, 네트워크 단 방어가 기본 제공되는 호스팅을 선택하는 것이 현실적입니다. TCP-80.NET은 모든 서버에 L3/L4 네트워크 공격 차단을 <strong>기본 무료 제공</strong>하며, L7 공격 방어가 필요한 경우 <a href="https://tcp-80.net/ddos-security/">전용 DDoS 방어 서비스</a>를 추가할 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="보안" /><category term="가이드" /><summary type="html"><![CDATA[DDoS 방어가 실제로 어떤 원리로 동작하는지 알아봅니다. 다계층 방어 구조, 스크러빙 센터의 동작 방식, BGP Anycast, SYN Cookie 등 핵심 메커니즘을 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-security.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-security.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">리눅스 서버에서 데이터베이스 운영 시 겪는 문제점과 해결법 총정리</title><link href="https://tcp-80.net/blog/2026/04/01/linux-server-database-issues/" rel="alternate" type="text/html" title="리눅스 서버에서 데이터베이스 운영 시 겪는 문제점과 해결법 총정리" /><published>2026-04-01T00:00:00+09:00</published><updated>2026-04-01T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/04/01/linux-server-database-issues</id><content type="html" xml:base="https://tcp-80.net/blog/2026/04/01/linux-server-database-issues/"><![CDATA[<p>리눅스 서버에서 데이터베이스를 직접 운영하면 관리형 DB(RDS 등) 대비 비용은 절감되지만, 그만큼 직접 해결해야 할 문제가 많습니다. 이 글에서는 실무에서 자주 마주치는 데이터베이스 운영 문제를 체계적으로 정리하고, 각각의 해결 방법을 안내합니다.</p>

<p><img src="/assets/img/posts/2026-04-01/db-linux-architecture.png" alt="리눅스 서버 데이터베이스 아키텍처" /></p>

<hr />

<h2 id="1-메모리-부족으로-인한-성능-저하">1. 메모리 부족으로 인한 성능 저하</h2>

<p>데이터베이스 성능 문제의 가장 흔한 원인은 <strong>메모리 부족</strong>입니다. 특히 InnoDB의 Buffer Pool 크기가 부족하면 디스크 I/O가 급증하면서 전체 쿼리 속도가 느려집니다.</p>

<h3 id="증상">증상</h3>

<ul>
  <li>쿼리 응답 시간이 점점 길어짐</li>
  <li><code class="language-plaintext highlighter-rouge">iostat</code>에서 디스크 사용률 90% 이상</li>
  <li><code class="language-plaintext highlighter-rouge">free -h</code>에서 available 메모리가 거의 없음</li>
  <li>OOM Killer가 DB 프로세스를 강제 종료</li>
</ul>

<h3 id="해결-방법">해결 방법</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 현재 Buffer Pool 크기 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"</span>

<span class="c"># 전체 메모리의 60~70%를 Buffer Pool에 할당 (예: 8GB 서버)</span>
<span class="c"># /etc/mysql/mysql.conf.d/mysqld.cnf 에 추가</span>
innodb_buffer_pool_size <span class="o">=</span> 5G
innodb_buffer_pool_instances <span class="o">=</span> 4

<span class="c"># OOM Killer 방지 — DB 프로세스 우선순위 조정</span>
<span class="nb">echo</span> <span class="nt">-17</span> <span class="o">&gt;</span> /proc/<span class="si">$(</span>pidof mysqld<span class="si">)</span>/oom_adj
</code></pre></div></div>

<p><strong>핵심 포인트:</strong> 서버 메모리가 4GB 이하라면 데이터베이스 전용 서버로 쓰기엔 부족합니다. 최소 8GB 이상을 권장합니다.</p>

<hr />

<h2 id="2-디스크-io-병목">2. 디스크 I/O 병목</h2>

<p>HDD를 사용하는 서버에서 데이터베이스를 운영하면 랜덤 읽기/쓰기 성능이 심각하게 떨어집니다. 특히 트래픽이 몰리는 시간대에 쿼리 지연이 발생합니다.</p>

<h3 id="진단-방법">진단 방법</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 디스크 I/O 상태 확인</span>
iostat <span class="nt">-xz</span> 1 5

<span class="c"># 주요 지표:</span>
<span class="c"># %util — 90% 이상이면 병목</span>
<span class="c"># await — 10ms 이상이면 지연 발생 중</span>
<span class="c"># r/s, w/s — 초당 읽기/쓰기 횟수</span>

<span class="c"># MySQL의 I/O 대기 상태 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SHOW ENGINE INNODB STATUS</span><span class="se">\G</span><span class="s2">"</span> | <span class="nb">grep</span> <span class="nt">-A</span> 5 <span class="s2">"FILE I/O"</span>

<span class="c"># 어떤 프로세스가 I/O를 많이 쓰는지 확인</span>
iotop <span class="nt">-oP</span>
</code></pre></div></div>

<h3 id="해결-방법-1">해결 방법</h3>

<ul>
  <li><strong>NVMe SSD로 교체</strong> — 가장 효과적 (IOPS 100배 이상 향상)</li>
  <li><code class="language-plaintext highlighter-rouge">innodb_flush_method = O_DIRECT</code> 설정으로 OS 캐시 이중화 방지</li>
  <li><code class="language-plaintext highlighter-rouge">innodb_io_capacity</code>, <code class="language-plaintext highlighter-rouge">innodb_io_capacity_max</code> 값을 SSD에 맞게 상향</li>
</ul>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SSD 환경에 맞는 I/O 설정
</span><span class="py">innodb_flush_method</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">O_DIRECT</span>
<span class="py">innodb_io_capacity</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2000</span>
<span class="py">innodb_io_capacity_max</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">4000</span>
</code></pre></div></div>

<hr />

<h2 id="3-슬로우-쿼리-누적">3. 슬로우 쿼리 누적</h2>

<p>운영 초기에는 빨랐던 쿼리가 데이터가 쌓이면서 점점 느려지는 것은 매우 흔한 문제입니다. 인덱스 누락, 불필요한 풀 테이블 스캔이 주요 원인입니다.</p>

<h3 id="슬로우-쿼리-로그-활성화">슬로우 쿼리 로그 활성화</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/mysql/mysql.conf.d/mysqld.cnf
</span><span class="py">slow_query_log</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1</span>
<span class="py">slow_query_log_file</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/mysql/slow.log</span>
<span class="py">long_query_time</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1</span>
<span class="py">log_queries_not_using_indexes</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1</span>
</code></pre></div></div>

<h3 id="분석-및-최적화">분석 및 최적화</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 슬로우 쿼리 요약 (상위 10개)</span>
mysqldumpslow <span class="nt">-s</span> t <span class="nt">-t</span> 10 /var/log/mysql/slow.log

<span class="c"># 특정 쿼리의 실행 계획 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"EXPLAIN SELECT * FROM orders WHERE user_id = 12345;"</span>

<span class="c"># 인덱스 추가</span>
mysql <span class="nt">-e</span> <span class="s2">"ALTER TABLE orders ADD INDEX idx_user_id (user_id);"</span>

<span class="c"># 현재 실행 중인 쿼리 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SHOW FULL PROCESSLIST;"</span>
</code></pre></div></div>

<p><strong>주의:</strong> 인덱스를 무작정 추가하면 INSERT/UPDATE 성능이 저하됩니다. EXPLAIN 결과를 확인한 뒤 필요한 인덱스만 추가하세요.</p>

<hr />

<h2 id="4-커넥션-폭주-및-max_connections-초과">4. 커넥션 폭주 및 max_connections 초과</h2>

<p>트래픽이 급증하거나 애플리케이션에서 커넥션을 제대로 반환하지 않으면 DB 접속이 거부됩니다.</p>

<h3 id="증상-1">증상</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ERROR 1040 (HY000): Too many connections
</code></pre></div></div>

<h3 id="진단">진단</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 현재 커넥션 수 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SHOW STATUS LIKE 'Threads_connected';"</span>

<span class="c"># 최대 커넥션 설정 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SHOW VARIABLES LIKE 'max_connections';"</span>

<span class="c"># 어떤 호스트에서 많이 접속하는지 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SELECT host, COUNT(*) as cnt FROM information_schema.processlist GROUP BY host ORDER BY cnt DESC;"</span>
</code></pre></div></div>

<h3 id="해결-방법-2">해결 방법</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># max_connections 상향 (기본값 151은 대부분 부족)
</span><span class="py">max_connections</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">500</span>
<span class="py">wait_timeout</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">300</span>
<span class="py">interactive_timeout</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">300</span>
</code></pre></div></div>

<p><strong>근본 해결:</strong> 애플리케이션에서 커넥션 풀을 사용하세요. PHP는 <code class="language-plaintext highlighter-rouge">pdo_mysql</code>의 persistent connection, Node.js는 <code class="language-plaintext highlighter-rouge">mysql2</code>의 Pool, Python은 <code class="language-plaintext highlighter-rouge">SQLAlchemy</code>의 QueuePool 등을 활용합니다.</p>

<hr />

<h2 id="5-lock-경합과-deadlock">5. Lock 경합과 Deadlock</h2>

<p>동시에 여러 트랜잭션이 같은 데이터를 수정하려 할 때 Lock 경합이 발생합니다. 심하면 Deadlock으로 트랜잭션이 강제 롤백됩니다.</p>

<p><img src="/assets/img/posts/2026-04-01/db-linux-bottleneck.png" alt="DB 성능 병목 포인트 5가지" /></p>

<h3 id="진단-1">진단</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># InnoDB Lock 대기 상태 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SELECT * FROM information_schema.innodb_lock_waits</span><span class="se">\G</span><span class="s2">"</span>

<span class="c"># 최근 Deadlock 정보</span>
mysql <span class="nt">-e</span> <span class="s2">"SHOW ENGINE INNODB STATUS</span><span class="se">\G</span><span class="s2">"</span> | <span class="nb">grep</span> <span class="nt">-A</span> 30 <span class="s2">"LATEST DETECTED DEADLOCK"</span>

<span class="c"># Lock 대기 중인 쿼리 목록</span>
mysql <span class="nt">-e</span> <span class="s2">"SELECT * FROM sys.innodb_lock_waits</span><span class="se">\G</span><span class="s2">"</span>
</code></pre></div></div>

<h3 id="해결-방법-3">해결 방법</h3>

<ul>
  <li>트랜잭션 범위를 <strong>최소화</strong> — 필요한 쿼리만 트랜잭션 안에</li>
  <li>UPDATE/DELETE 시 <strong>인덱스를 반드시 사용</strong> (인덱스 없으면 테이블 전체 Lock)</li>
  <li>여러 테이블을 수정할 때 <strong>항상 같은 순서로 접근</strong></li>
  <li><code class="language-plaintext highlighter-rouge">innodb_lock_wait_timeout</code> 값 조정 (기본 50초)</li>
</ul>

<hr />

<h2 id="6-백업-실패-및-복구-불가">6. 백업 실패 및 복구 불가</h2>

<p>“백업이 있다”와 “복구 가능한 백업이 있다”는 완전히 다릅니다. 실제로 복구를 시도하면 실패하는 경우가 많습니다.</p>

<p><img src="/assets/img/posts/2026-04-01/db-linux-backup.png" alt="DB 백업 전략 비교" /></p>

<h3 id="mysqldump-백업-소규모-db">mysqldump 백업 (소규모 DB)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 전체 데이터베이스 백업</span>
mysqldump <span class="nt">--all-databases</span> <span class="nt">--single-transaction</span> <span class="nt">--routines</span> <span class="nt">--triggers</span> <span class="se">\</span>
  <span class="nt">--quick</span> <span class="nt">--lock-tables</span><span class="o">=</span><span class="nb">false</span> <span class="o">&gt;</span> /backup/full_<span class="si">$(</span><span class="nb">date</span> +%Y%m%d_%H%M%S<span class="si">)</span>.sql

<span class="c"># 특정 DB만 백업</span>
mysqldump <span class="nt">--single-transaction</span> mydb <span class="o">&gt;</span> /backup/mydb_<span class="si">$(</span><span class="nb">date</span> +%Y%m%d<span class="si">)</span>.sql

<span class="c"># gzip 압축 백업</span>
mysqldump <span class="nt">--single-transaction</span> mydb | <span class="nb">gzip</span> <span class="o">&gt;</span> /backup/mydb_<span class="si">$(</span><span class="nb">date</span> +%Y%m%d<span class="si">)</span>.sql.gz
</code></pre></div></div>

<h3 id="xtrabackup-대규모-db-무중단-백업">xtrabackup (대규모 DB, 무중단 백업)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Percona XtraBackup 전체 백업</span>
xtrabackup <span class="nt">--backup</span> <span class="nt">--target-dir</span><span class="o">=</span>/backup/full/

<span class="c"># 증분 백업</span>
xtrabackup <span class="nt">--backup</span> <span class="nt">--target-dir</span><span class="o">=</span>/backup/inc1/ <span class="se">\</span>
  <span class="nt">--incremental-basedir</span><span class="o">=</span>/backup/full/

<span class="c"># 복구 준비</span>
xtrabackup <span class="nt">--prepare</span> <span class="nt">--target-dir</span><span class="o">=</span>/backup/full/
</code></pre></div></div>

<h3 id="자동-백업-cron-설정">자동 백업 cron 설정</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/cron.d/db-backup</span>
<span class="c"># 매일 새벽 3시 전체 백업</span>
0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> root mysqldump <span class="nt">--all-databases</span> <span class="nt">--single-transaction</span> | <span class="nb">gzip</span> <span class="o">&gt;</span> /backup/daily_<span class="si">$(</span><span class="nb">date</span> +<span class="se">\%</span>Y<span class="se">\%</span>m<span class="se">\%</span>d<span class="si">)</span>.sql.gz

<span class="c"># 30일 이상 된 백업 자동 삭제</span>
0 4 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> root find /backup/ <span class="nt">-name</span> <span class="s2">"*.sql.gz"</span> <span class="nt">-mtime</span> +30 <span class="nt">-delete</span>
</code></pre></div></div>

<p><strong>반드시 확인:</strong> 백업 후 정기적으로 복구 테스트를 실행하세요. 복구되지 않는 백업은 없는 것과 같습니다.</p>

<hr />

<h2 id="7-보안-취약점">7. 보안 취약점</h2>

<p>리눅스에서 직접 DB를 운영하면 보안 설정도 직접 해야 합니다. 기본 설정 그대로 두면 외부에서 침투당할 수 있습니다.</p>

<h3 id="필수-보안-설정">필수 보안 설정</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># MySQL 보안 초기 설정 (설치 직후 실행)</span>
mysql_secure_installation

<span class="c"># 외부 접속 차단 — bind-address 설정</span>
<span class="c"># /etc/mysql/mysql.conf.d/mysqld.cnf</span>
bind-address <span class="o">=</span> 127.0.0.1

<span class="c"># 불필요한 원격 접속 계정 제거</span>
mysql <span class="nt">-e</span> <span class="s2">"SELECT user, host FROM mysql.user WHERE host != 'localhost';"</span>
mysql <span class="nt">-e</span> <span class="s2">"DROP USER 'root'@'%';"</span>

<span class="c"># 방화벽으로 3306 포트 차단</span>
ufw deny 3306
</code></pre></div></div>

<h3 id="권한-최소화-원칙">권한 최소화 원칙</h3>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 애플리케이션용 계정은 필요한 권한만 부여</span>
<span class="k">CREATE</span> <span class="k">USER</span> <span class="s1">'webapp'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="s1">'strong_password_here'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span><span class="p">,</span> <span class="k">INSERT</span><span class="p">,</span> <span class="k">UPDATE</span><span class="p">,</span> <span class="k">DELETE</span> <span class="k">ON</span> <span class="n">mydb</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">'webapp'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>

<span class="c1">-- SUPER, FILE, PROCESS 권한은 절대 애플리케이션에 부여하지 말 것</span>
<span class="c1">-- 관리 작업용 별도 계정 사용</span>
</code></pre></div></div>

<hr />

<h2 id="8-복제replication-지연-및-장애">8. 복제(Replication) 지연 및 장애</h2>

<p>Master-Slave 구조에서 복제 지연이 발생하면 읽기 분산의 의미가 없어지고, 데이터 불일치 문제가 생깁니다.</p>

<h3 id="복제-상태-확인">복제 상태 확인</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Slave 서버에서 복제 상태 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SHOW SLAVE STATUS</span><span class="se">\G</span><span class="s2">"</span> | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"Seconds_Behind|Running|Error"</span>

<span class="c"># 핵심 확인 항목:</span>
<span class="c"># Slave_IO_Running: Yes</span>
<span class="c"># Slave_SQL_Running: Yes</span>
<span class="c"># Seconds_Behind_Master: 0 (지연 없음)</span>
</code></pre></div></div>

<h3 id="복제-지연-해결">복제 지연 해결</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Slave 서버 성능 튜닝
</span><span class="py">slave_parallel_workers</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">4</span>
<span class="py">slave_parallel_type</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">LOGICAL_CLOCK</span>
<span class="py">slave_preserve_commit_order</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1</span>
<span class="w">
</span><span class="c"># Binary Log 포맷 설정 (ROW 권장)
</span><span class="py">binlog_format</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">ROW</span>
</code></pre></div></div>

<hr />

<h2 id="9-디스크-용량-부족">9. 디스크 용량 부족</h2>

<p>데이터베이스 파일, 바이너리 로그, 슬로우 쿼리 로그 등이 디스크를 꽉 채우면 DB가 갑자기 멈출 수 있습니다.</p>

<h3 id="모니터링">모니터링</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 디스크 사용량 확인</span>
<span class="nb">df</span> <span class="nt">-h</span> /var/lib/mysql/

<span class="c"># MySQL 데이터 디렉토리 크기</span>
<span class="nb">du</span> <span class="nt">-sh</span> /var/lib/mysql/

<span class="c"># 데이터베이스별 용량 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SELECT table_schema, ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)' FROM information_schema.tables GROUP BY table_schema ORDER BY SUM(data_length + index_length) DESC;"</span>

<span class="c"># 바이너리 로그 크기 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SHOW BINARY LOGS;"</span>
</code></pre></div></div>

<h3 id="해결-방법-4">해결 방법</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 오래된 바이너리 로그 삭제</span>
mysql <span class="nt">-e</span> <span class="s2">"PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY);"</span>

<span class="c"># 자동 삭제 설정</span>
<span class="c"># /etc/mysql/mysql.conf.d/mysqld.cnf</span>
expire_logs_days <span class="o">=</span> 7
<span class="c"># MySQL 8.0+</span>
binlog_expire_logs_seconds <span class="o">=</span> 604800
</code></pre></div></div>

<hr />

<h2 id="10-업그레이드-및-마이그레이션-문제">10. 업그레이드 및 마이그레이션 문제</h2>

<p>MySQL 5.7에서 8.0으로, 또는 MariaDB로 전환할 때 호환성 문제가 발생할 수 있습니다.</p>

<h3 id="업그레이드-전-체크리스트">업그레이드 전 체크리스트</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># MySQL 업그레이드 체커 실행</span>
mysqlcheck <span class="nt">--all-databases</span> <span class="nt">--check-upgrade</span>

<span class="c"># MySQL 8.0 업그레이드 체커</span>
mysql_upgrade_checker

<span class="c"># 현재 사용 중인 deprecated 기능 확인</span>
mysql <span class="nt">-e</span> <span class="s2">"SHOW WARNINGS;"</span> 2&gt;&amp;1 | <span class="nb">grep</span> <span class="nt">-i</span> deprecated

<span class="c"># 현재 버전 확인</span>
mysql <span class="nt">-V</span>
</code></pre></div></div>

<h3 id="안전한-마이그레이션-순서">안전한 마이그레이션 순서</h3>

<ol>
  <li><strong>백업</strong> — 반드시 풀 백업 후 복구 테스트까지 완료</li>
  <li><strong>스테이징 테스트</strong> — 동일 환경에서 먼저 업그레이드 테스트</li>
  <li><strong>호환성 확인</strong> — 쿼리 문법, 기본값 변경사항 확인</li>
  <li><strong>점검 시간 확보</strong> — 충분한 유지보수 시간 확보 후 진행</li>
  <li><strong>롤백 계획</strong> — 실패 시 원복 절차 준비</li>
</ol>

<hr />

<h2 id="마무리--안정적인-db-운영을-위한-핵심-원칙">마무리 — 안정적인 DB 운영을 위한 핵심 원칙</h2>

<table>
  <thead>
    <tr>
      <th>원칙</th>
      <th>설명</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>모니터링 자동화</strong></td>
      <td>Prometheus + Grafana 또는 최소 cron + 알림 스크립트</td>
    </tr>
    <tr>
      <td><strong>백업 + 복구 테스트</strong></td>
      <td>백업만으로는 부족, 정기 복구 테스트 필수</td>
    </tr>
    <tr>
      <td><strong>보안 기본기</strong></td>
      <td>bind-address, 방화벽, 권한 최소화</td>
    </tr>
    <tr>
      <td><strong>리소스 여유 확보</strong></td>
      <td>CPU, 메모리, 디스크 모두 70% 이하 유지</td>
    </tr>
    <tr>
      <td><strong>변경 관리</strong></td>
      <td>설정 변경 전 반드시 백업, 기록, 테스트</td>
    </tr>
  </tbody>
</table>

<p>리눅스 서버에서 데이터베이스를 안정적으로 운영하려면 지속적인 모니터링과 선제적 대응이 필수입니다. 문제가 발생한 뒤 대응하는 것보다, 미리 감지하고 예방하는 것이 훨씬 효과적입니다.</p>

<p>서버 환경에 맞는 최적의 DB 구성이 필요하시면 <a href="https://tcp-80.net/support/">TCP-80.NET에 문의</a>해 주세요. NVMe SSD 기반의 일본 서버에서 안정적인 데이터베이스 운영을 지원합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[리눅스 서버에서 MySQL, MariaDB, PostgreSQL 등 데이터베이스를 운영할 때 자주 발생하는 성능 저하, 장애, 보안 문제와 실전 해결 방법을 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버호스팅 자주 묻는 질문 (FAQ) 총정리 2026</title><link href="https://tcp-80.net/blog/2026/03/26/japan-server-faq/" rel="alternate" type="text/html" title="일본 서버호스팅 자주 묻는 질문 (FAQ) 총정리 2026" /><published>2026-03-26T00:00:00+09:00</published><updated>2026-03-26T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/03/26/japan-server-faq</id><content type="html" xml:base="https://tcp-80.net/blog/2026/03/26/japan-server-faq/"><![CDATA[<p>일본 서버호스팅을 처음 알아보는 분들부터 이미 사용 중이신 분들까지, 자주 묻는 질문을 모아 답변합니다.</p>

<hr />

<h2 id="서비스-기본-질문">서비스 기본 질문</h2>

<p><strong>Q. 일본 서버와 한국 서버, 무엇이 다른가요?</strong></p>

<p>일본 서버는 물리적으로 일본 도쿄 데이터센터에 위치한 서버입니다. 한국과의 지리적 거리가 가까워 왕복 지연(RTT)이 20~40ms 수준입니다. 일본 IP 주소를 가지므로 일본 현지 서비스 이용, 일본 대상 웹 서비스 운영에 유리합니다.</p>

<hr />

<p><strong>Q. 전용서버와 VPS의 차이가 무엇인가요?</strong></p>

<ul>
  <li><strong>VPS</strong>: 물리 서버를 가상화로 나눠 여러 사용자가 공유. 가격이 저렴하고 소규모 서비스에 적합</li>
  <li><strong>전용서버</strong>: 물리 서버 전체를 혼자 사용. 높은 성능, 안정성, 보안이 필요한 서비스에 적합</li>
</ul>

<p>자세한 비교는 <a href="/blog/2025/06/02/japan-dedicated-vs-vps/">전용서버 vs VPS 비교 글</a>을 참고하세요.</p>

<hr />

<p><strong>Q. 서버 개설 후 얼마나 빨리 이용할 수 있나요?</strong></p>

<ul>
  <li><strong>VPS</strong>: 결제 확인 후 당일 ~ 익일 내 개설</li>
  <li><strong>전용서버</strong>: 결제 확인 후 1~2 영업일 내 개설 (하드웨어 준비 시간 필요)</li>
  <li><strong>가상 데스크톱</strong>: 결제 확인 후 당일 내 개설</li>
</ul>

<hr />

<p><strong>Q. 어떤 OS를 선택할 수 있나요?</strong></p>

<p>Linux 계열:</p>
<ul>
  <li>Ubuntu 22.04 LTS, 20.04 LTS</li>
  <li>Debian 12, 11</li>
  <li>CentOS 7 (지원 종료, 비권장)</li>
</ul>

<p>Windows 계열:</p>
<ul>
  <li>Windows Server 2019</li>
  <li>Windows Server 2022</li>
</ul>

<p>원하는 OS가 있으면 텔레그램으로 문의해 주세요.</p>

<hr />

<h2 id="가격-및-결제-질문">가격 및 결제 질문</h2>

<p><strong>Q. 일본 VPS 가격이 어떻게 되나요?</strong></p>

<p>TCP-80.NET 일본 VPS는 <a href="/virtual-server/">월 ₩100,000부터</a> 시작하며, 4개 플랜을 제공합니다. 전용서버는 <a href="/dedicated-server/">월 ₩300,000부터</a> 5개 플랜이 있습니다.</p>

<hr />

<p><strong>Q. 결제 방법은 무엇을 지원하나요?</strong></p>

<p>텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의하시면 결제 방법을 안내해 드립니다.</p>

<hr />

<p><strong>Q. 환불은 가능한가요?</strong></p>

<p>서비스 시작일로부터 7일 이내에 취소 요청 시 전액 환불이 가능합니다. 자세한 내용은 <a href="/return-policy/">환불 정책</a>을 확인해 주세요.</p>

<hr />

<h2 id="기술적인-질문">기술적인 질문</h2>

<p><strong>Q. 서버에 root 권한이 제공되나요?</strong></p>

<p>네, 전용서버와 VPS 모두 root 권한이 기본 제공됩니다. 서버를 완전히 자유롭게 관리할 수 있습니다.</p>

<hr />

<p><strong>Q. 관리형 서비스(OS 설치 지원 등)를 제공하나요?</strong></p>

<p>TCP-80.NET은 OS 설치와 기본 설정에 대한 한국어 기술 지원을 텔레그램으로 제공합니다. 기본 서버 설정, Nginx·Apache 설치, 방화벽 설정 등을 지원합니다.</p>

<hr />

<p><strong>Q. 대역폭 한도가 있나요?</strong></p>

<p>기본 제공되는 네트워크 포트와 트래픽 정책에 대한 자세한 내용은 텔레그램으로 문의해 주세요.</p>

<hr />

<p><strong>Q. 서버 재부팅은 직접 할 수 있나요?</strong></p>

<ul>
  <li><strong>VPS</strong>: 텔레그램 요청으로 재부팅 지원</li>
  <li><strong>전용서버</strong>: IPMI를 통해 직접 원격 재부팅 가능</li>
</ul>

<hr />

<h2 id="보안-질문">보안 질문</h2>

<p><strong>Q. DDoS 방어가 포함되어 있나요?</strong></p>

<p>네, 모든 서버에 네트워크 레이어(L3/L4) DDoS 방어가 무료로 기본 포함됩니다. 더 강력한 보호가 필요하다면 <a href="/ddos-security/">전용 DDoS 방어 서비스</a>를 별도로 이용할 수 있습니다.</p>

<hr />

<p><strong>Q. 서버가 해킹당했을 때 지원해 주나요?</strong></p>

<p>TCP-80.NET의 <a href="/hacking-security/">해킹 방지 보안 서비스</a>를 이용하시면 전문적인 보안 대응을 받을 수 있습니다. 기본 서버는 고객이 직접 관리하며, 보안 설정에 대한 일반적인 안내는 텔레그램으로 제공합니다.</p>

<hr />

<p><strong>Q. 일본 법률상 문제가 되는 서비스에는 사용할 수 없나요?</strong></p>

<p>불법 콘텐츠 배포, 스팸, 해킹 등 일본 또는 국제 법률에 위반되는 서비스는 이용 약관에 따라 서비스가 즉시 해지됩니다.</p>

<hr />

<h2 id="기타-질문">기타 질문</h2>

<p><strong>Q. 한국어 지원이 가능한가요?</strong></p>

<p>네, TCP-80.NET은 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>을 통해 24시간 365일 한국어 지원을 제공합니다.</p>

<hr />

<p><strong>Q. 서버 위치를 변경할 수 있나요?</strong></p>

<p>현재 TCP-80.NET은 일본 도쿄 데이터센터를 운영합니다. 다른 위치로의 이전은 지원하지 않습니다.</p>

<hr />

<p><strong>Q. 장기 계약 할인이 있나요?</strong></p>

<p>장기 계약 또는 다수 서버 이용 시 할인에 대한 문의는 텔레그램으로 주세요. 상황에 따라 협의가 가능합니다.</p>

<hr />

<p><strong>Q. 업타임(가동률) 보장이 있나요?</strong></p>

<p>TCP-80.NET은 이중화 네트워크와 UPS를 갖춘 도쿄 데이터센터에서 99.9% 이상의 네트워크 가동률을 목표로 운영합니다.</p>

<hr />

<p>더 궁금한 사항이 있으시면 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 언제든지 문의해 주세요. 24시간 한국어로 답변드립니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅을 처음 시작하거나 이전을 고려할 때 자주 묻는 질문과 답변을 모았습니다. 가격, 설정, 보안, 환불 정책까지 궁금한 것을 한 번에 해결하세요.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 로그 관리 완전 가이드 — 문제 추적과 보안 감사의 핵심</title><link href="https://tcp-80.net/blog/2026/03/25/japan-server-log-management/" rel="alternate" type="text/html" title="일본 서버 로그 관리 완전 가이드 — 문제 추적과 보안 감사의 핵심" /><published>2026-03-25T00:00:00+09:00</published><updated>2026-03-25T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/03/25/japan-server-log-management</id><content type="html" xml:base="https://tcp-80.net/blog/2026/03/25/japan-server-log-management/"><![CDATA[<p>일본 서버를 운영할 때 로그는 문제 발생 시 원인을 추적하고, 보안 이벤트를 감지하며, 서비스 성능을 분석하는 핵심 데이터입니다. 이 글에서는 일본 서버의 주요 로그 파일 위치와 분석 방법, 자동 로테이션 설정을 안내합니다.</p>

<h2 id="주요-로그-파일-위치">주요 로그 파일 위치</h2>

<table>
  <thead>
    <tr>
      <th>로그 종류</th>
      <th>파일 경로</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>시스템 로그</td>
      <td><code class="language-plaintext highlighter-rouge">/var/log/syslog</code></td>
    </tr>
    <tr>
      <td>커널 로그</td>
      <td><code class="language-plaintext highlighter-rouge">/var/log/kern.log</code></td>
    </tr>
    <tr>
      <td>인증 로그</td>
      <td><code class="language-plaintext highlighter-rouge">/var/log/auth.log</code></td>
    </tr>
    <tr>
      <td>Nginx 접속 로그</td>
      <td><code class="language-plaintext highlighter-rouge">/var/log/nginx/access.log</code></td>
    </tr>
    <tr>
      <td>Nginx 에러 로그</td>
      <td><code class="language-plaintext highlighter-rouge">/var/log/nginx/error.log</code></td>
    </tr>
    <tr>
      <td>MySQL 에러 로그</td>
      <td><code class="language-plaintext highlighter-rouge">/var/log/mysql/error.log</code></td>
    </tr>
    <tr>
      <td>MySQL 슬로우 쿼리</td>
      <td><code class="language-plaintext highlighter-rouge">/var/log/mysql/slow.log</code></td>
    </tr>
    <tr>
      <td>PHP-FPM 로그</td>
      <td><code class="language-plaintext highlighter-rouge">/var/log/php8.1-fpm.log</code></td>
    </tr>
    <tr>
      <td>Fail2Ban 로그</td>
      <td><code class="language-plaintext highlighter-rouge">/var/log/fail2ban.log</code></td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="시스템-로그-분석">시스템 로그 분석</h2>

<h3 id="실시간-로그-확인">실시간 로그 확인</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 실시간 시스템 로그 모니터링</span>
journalctl <span class="nt">-f</span>

<span class="c"># 특정 서비스 로그</span>
journalctl <span class="nt">-u</span> nginx <span class="nt">-f</span>
journalctl <span class="nt">-u</span> mariadb <span class="nt">-f</span>

<span class="c"># 최근 N줄 확인</span>
journalctl <span class="nt">-u</span> nginx <span class="nt">--lines</span><span class="o">=</span>50
</code></pre></div></div>

<h3 id="부팅-오류-확인">부팅 오류 확인</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 마지막 부팅의 커널 로그</span>
dmesg | <span class="nb">grep</span> <span class="nt">-i</span> error
dmesg | <span class="nb">grep</span> <span class="nt">-i</span> fail

<span class="c"># 시스템 부팅 로그</span>
journalctl <span class="nt">-b</span>
</code></pre></div></div>

<hr />

<h2 id="nginx-로그-분석">Nginx 로그 분석</h2>

<h3 id="접속-통계-분석">접속 통계 분석</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 가장 많이 접속한 IP TOP 20</span>
<span class="nb">awk</span> <span class="s1">'{print $1}'</span> /var/log/nginx/access.log | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># HTTP 상태 코드 분포</span>
<span class="nb">awk</span> <span class="s1">'{print $9}'</span> /var/log/nginx/access.log | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span>

<span class="c"># 404 에러 URL 목록</span>
<span class="nb">awk</span> <span class="s1">'$9 == "404" {print $7}'</span> /var/log/nginx/access.log | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># 500 에러 발생 시각</span>
<span class="nb">grep</span> <span class="s1">' 500 '</span> /var/log/nginx/access.log | <span class="nb">awk</span> <span class="s1">'{print $4}'</span> | <span class="nb">cut</span> <span class="nt">-d</span>: <span class="nt">-f1-2</span>

<span class="c"># 가장 많이 요청된 URL TOP 10</span>
<span class="nb">awk</span> <span class="s1">'{print $7}'</span> /var/log/nginx/access.log | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-10</span>

<span class="c"># 오늘의 총 요청 수</span>
<span class="nb">grep</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">date</span> <span class="s1">'+%d/%b/%Y'</span><span class="si">)</span><span class="s2">"</span> /var/log/nginx/access.log | <span class="nb">wc</span> <span class="nt">-l</span>
</code></pre></div></div>

<h3 id="봇-트래픽-감지">봇 트래픽 감지</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 비정상 User-Agent 확인</span>
<span class="nb">awk</span> <span class="nt">-F</span><span class="s1">'"'</span> <span class="s1">'{print $6}'</span> /var/log/nginx/access.log | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># 스캐너·봇 IP 확인 (단시간 다수 요청)</span>
<span class="nb">awk</span> <span class="s1">'{print $1}'</span> /var/log/nginx/access.log | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">awk</span> <span class="s1">'$1 &gt; 1000 {print}'</span>
</code></pre></div></div>

<hr />

<h2 id="인증-로그-보안-분석">인증 로그 보안 분석</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SSH 로그인 실패 IP 목록</span>
<span class="nb">grep</span> <span class="s2">"Failed password"</span> /var/log/auth.log | <span class="nb">awk</span> <span class="s1">'{print $11}'</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># 성공적인 SSH 로그인 기록</span>
<span class="nb">grep</span> <span class="s2">"Accepted"</span> /var/log/auth.log | <span class="nb">tail</span> <span class="nt">-20</span>

<span class="c"># sudo 사용 기록</span>
<span class="nb">grep</span> <span class="s2">"sudo"</span> /var/log/auth.log | <span class="nb">tail</span> <span class="nt">-20</span>

<span class="c"># 무차별 공격 감지 (분당 10회 이상 실패)</span>
<span class="nb">grep</span> <span class="s2">"Failed password"</span> /var/log/auth.log | <span class="nb">awk</span> <span class="s1">'{print $1,$2,$3}'</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-10</span>
</code></pre></div></div>

<hr />

<h2 id="logrotate로-로그-자동-관리">logrotate로 로그 자동 관리</h2>

<p>로그 파일이 계속 쌓이면 디스크가 가득 찹니다. logrotate로 자동으로 압축·삭제합니다.</p>

<h3 id="기본-설정-확인">기본 설정 확인</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> /etc/logrotate.conf
<span class="nb">ls</span> /etc/logrotate.d/
</code></pre></div></div>

<h3 id="커스텀-로그-로테이션-설정">커스텀 로그 로테이션 설정</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/logrotate.d/myapp
</span><span class="na">/var/log/myapp/*.log</span><span class="w"> </span><span class="na">{</span><span class="w">
    </span><span class="na">daily</span><span class="w">           </span><span class="c"># 매일 로테이션
</span><span class="w">    </span><span class="na">rotate</span><span class="w"> </span><span class="na">30</span><span class="w">       </span><span class="c"># 30개 보관
</span><span class="w">    </span><span class="na">compress</span><span class="w">        </span><span class="c"># gzip 압축
</span><span class="w">    </span><span class="na">delaycompress</span><span class="w">   </span><span class="c"># 최신 1개는 압축 보류
</span><span class="w">    </span><span class="na">missingok</span><span class="w">       </span><span class="c"># 파일 없어도 에러 없음
</span><span class="w">    </span><span class="na">notifempty</span><span class="w">      </span><span class="c"># 빈 파일은 로테이션 건너뜀
</span><span class="w">    </span><span class="na">create</span><span class="w"> </span><span class="na">0640</span><span class="w"> </span><span class="na">www-data</span><span class="w"> </span><span class="na">adm</span><span class="w">  </span><span class="c"># 새 파일 권한
</span><span class="w">    </span><span class="na">postrotate</span><span class="w">
        </span><span class="na">nginx</span><span class="w"> </span><span class="na">-s</span><span class="w"> </span><span class="na">reopen</span><span class="w">  </span><span class="c"># Nginx에 로그 파일 재열기 신호
</span><span class="w">    </span><span class="na">endscript</span><span class="w">
</span><span class="na">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="logrotate-즉시-실행-테스트">logrotate 즉시 실행 (테스트)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>logrotate <span class="nt">-d</span> /etc/logrotate.d/nginx  <span class="c"># dry-run</span>
logrotate <span class="nt">-f</span> /etc/logrotate.d/nginx  <span class="c"># 강제 실행</span>
</code></pre></div></div>

<hr />

<h2 id="디스크-용량-모니터링">디스크 용량 모니터링</h2>

<p>로그가 디스크를 가득 채우지 않도록 정기적으로 확인합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 디스크 사용량</span>
<span class="nb">df</span> <span class="nt">-h</span>

<span class="c"># 가장 큰 파일 찾기</span>
<span class="nb">du</span> <span class="nt">-sh</span> /var/log/<span class="k">*</span> | <span class="nb">sort</span> <span class="nt">-rh</span> | <span class="nb">head</span> <span class="nt">-10</span>

<span class="c"># 큰 로그 파일 즉시 비우기 (파일 삭제 X, 내용만 비움)</span>
<span class="o">&gt;</span> /var/log/nginx/access.log
</code></pre></div></div>

<hr />

<h2 id="중앙화-로그-관리-선택">중앙화 로그 관리 (선택)</h2>

<p>여러 서버를 운영하거나 로그 분석을 고도화하려면 중앙화 로그 시스템을 도입합니다:</p>

<ul>
  <li><strong>rsyslog</strong>: 로그를 원격 서버로 전송</li>
  <li><strong>ELK Stack</strong>: Elasticsearch + Logstash + Kibana로 대용량 로그 분석</li>
  <li><strong>Loki + Grafana</strong>: 경량 로그 집계 및 시각화</li>
</ul>

<hr />

<h2 id="마치며">마치며</h2>

<p>로그는 서버 운영의 블랙박스입니다. 평소에 로그를 점검하는 습관을 들이면 장애 발생 시 원인을 빠르게 파악하고, 보안 침해를 사전에 감지할 수 있습니다. 일본 서버 로그 설정에 대한 문의는 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="보안" /><summary type="html"><![CDATA[일본 서버호스팅에서 시스템 로그와 Nginx·MySQL 로그를 효과적으로 관리하는 방법을 안내합니다. 로그 분석, 자동 로테이션, 보안 이벤트 감지까지 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-security.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-security.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 전용서버 IPMI 활용 가이드 — 원격 하드웨어 관리 완전 정복</title><link href="https://tcp-80.net/blog/2026/03/23/japan-server-ipmi-guide/" rel="alternate" type="text/html" title="일본 전용서버 IPMI 활용 가이드 — 원격 하드웨어 관리 완전 정복" /><published>2026-03-23T00:00:00+09:00</published><updated>2026-03-23T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/03/23/japan-server-ipmi-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/03/23/japan-server-ipmi-guide/"><![CDATA[<p>일본 전용서버를 사용하면 VPS와 달리 물리 서버를 단독으로 사용합니다. 이때 서버가 응답하지 않거나 OS 문제가 발생했을 때 데이터센터에 직접 가지 않고도 하드웨어를 원격으로 제어할 수 있는 기능이 <strong>IPMI</strong>입니다.</p>

<h2 id="ipmi란">IPMI란?</h2>

<p>IPMI(Intelligent Platform Management Interface)는 서버 메인보드에 내장된 독립적인 관리 컨트롤러입니다. 서버의 전원이 꺼져 있거나 OS가 응답하지 않는 상태에서도 작동합니다.</p>

<p>주요 기능:</p>
<ul>
  <li><strong>원격 전원 제어</strong>: 서버 전원 켜기/끄기/재시작</li>
  <li><strong>원격 콘솔(KVM)</strong>: 마치 물리적으로 모니터를 연결한 것처럼 서버 화면 제어</li>
  <li><strong>OS 재설치</strong>: 원격에서 ISO 이미지를 마운트해 OS 재설치</li>
  <li><strong>하드웨어 상태 모니터링</strong>: CPU 온도, 팬 속도, 전원 상태 확인</li>
  <li><strong>시스템 이벤트 로그</strong>: 하드웨어 이상 이벤트 기록 확인</li>
</ul>

<hr />

<h2 id="ipmi-접근-방법">IPMI 접근 방법</h2>

<p>전용서버를 받으면 별도의 IPMI IP 주소, 포트, 사용자/비밀번호가 제공됩니다.</p>

<h3 id="웹-브라우저-접속">웹 브라우저 접속</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://IPMI-IP주소/
</code></pre></div></div>

<p>브라우저에서 IPMI 웹 인터페이스에 접속합니다. 일반적으로 Java 또는 HTML5 기반 KVM 뷰어를 제공합니다.</p>

<h3 id="ipmitool-명령줄-도구">ipmitool 명령줄 도구</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 설치</span>
apt <span class="nb">install </span>ipmitool <span class="nt">-y</span>

<span class="c"># 서버 상태 확인</span>
ipmitool <span class="nt">-I</span> lanplus <span class="nt">-H</span> IPMI-IP <span class="nt">-U</span> admin <span class="nt">-P</span> 비밀번호 chassis status

<span class="c"># 전원 관리</span>
ipmitool <span class="nt">-I</span> lanplus <span class="nt">-H</span> IPMI-IP <span class="nt">-U</span> admin <span class="nt">-P</span> 비밀번호 chassis power status
ipmitool <span class="nt">-I</span> lanplus <span class="nt">-H</span> IPMI-IP <span class="nt">-U</span> admin <span class="nt">-P</span> 비밀번호 chassis power on
ipmitool <span class="nt">-I</span> lanplus <span class="nt">-H</span> IPMI-IP <span class="nt">-U</span> admin <span class="nt">-P</span> 비밀번호 chassis power off
ipmitool <span class="nt">-I</span> lanplus <span class="nt">-H</span> IPMI-IP <span class="nt">-U</span> admin <span class="nt">-P</span> 비밀번호 chassis power reset

<span class="c"># 하드웨어 센서 정보</span>
ipmitool <span class="nt">-I</span> lanplus <span class="nt">-H</span> IPMI-IP <span class="nt">-U</span> admin <span class="nt">-P</span> 비밀번호 sdr

<span class="c"># 시스템 이벤트 로그</span>
ipmitool <span class="nt">-I</span> lanplus <span class="nt">-H</span> IPMI-IP <span class="nt">-U</span> admin <span class="nt">-P</span> 비밀번호 sel list
</code></pre></div></div>

<hr />

<h2 id="주요-활용-시나리오">주요 활용 시나리오</h2>

<h3 id="시나리오-1-ssh-접속이-안-될-때">시나리오 1: SSH 접속이 안 될 때</h3>

<p>OS는 실행 중인데 SSH가 응답하지 않는 경우, IPMI KVM으로 서버 화면에 직접 접속해 원인을 확인하고 SSH 서비스를 재시작할 수 있습니다.</p>

<ol>
  <li>IPMI 웹 접속 → Remote Control → KVM 콘솔 실행</li>
  <li>서버 화면 확인 (로그인 프롬프트 또는 패닉 메시지)</li>
  <li>직접 로그인해 SSH 서비스 재시작</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart sshd
</code></pre></div></div>

<h3 id="시나리오-2-서버가-완전히-응답하지-않을-때">시나리오 2: 서버가 완전히 응답하지 않을 때</h3>

<p>OS 크래시나 커널 패닉으로 서버가 완전히 굳은 경우:</p>

<ol>
  <li>IPMI에서 전원 강제 리셋
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ipmitool ... chassis power reset
</code></pre></div>    </div>
  </li>
  <li>서버 재시작 후 원인 파악 (dmesg, /var/log/syslog)</li>
</ol>

<h3 id="시나리오-3-os-재설치">시나리오 3: OS 재설치</h3>

<p>잘못된 설정이나 심각한 보안 침해 시 OS를 처음부터 재설치해야 할 때:</p>

<ol>
  <li>IPMI 웹 → Virtual Media → ISO 이미지 마운트</li>
  <li>서버를 해당 ISO로 부팅 설정</li>
  <li>KVM 콘솔에서 OS 설치 진행</li>
</ol>

<h3 id="시나리오-4-하드웨어-이상-감지">시나리오 4: 하드웨어 이상 감지</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># CPU 온도 확인</span>
ipmitool <span class="nt">-I</span> lanplus <span class="nt">-H</span> IPMI-IP <span class="nt">-U</span> admin <span class="nt">-P</span> 비밀번호 sdr | <span class="nb">grep </span>Temp

<span class="c"># 팬 속도 확인</span>
ipmitool <span class="nt">-I</span> lanplus <span class="nt">-H</span> IPMI-IP <span class="nt">-U</span> admin <span class="nt">-P</span> 비밀번호 sdr | <span class="nb">grep </span>Fan

<span class="c"># 전원 공급 상태</span>
ipmitool <span class="nt">-I</span> lanplus <span class="nt">-H</span> IPMI-IP <span class="nt">-U</span> admin <span class="nt">-P</span> 비밀번호 sdr | <span class="nb">grep </span>Power
</code></pre></div></div>

<hr />

<h2 id="ipmi-보안-설정">IPMI 보안 설정</h2>

<p>IPMI는 강력한 하드웨어 제어 권한을 가지므로 보안이 중요합니다.</p>

<ol>
  <li><strong>기본 비밀번호 변경</strong>: IPMI 웹 인터페이스에서 즉시 변경</li>
  <li><strong>접근 IP 제한</strong>: IPMI 포트(623, 443 등)에 대한 접근을 특정 IP로 제한</li>
  <li><strong>강력한 비밀번호 사용</strong>: 16자 이상 복잡한 비밀번호 설정</li>
  <li><strong>불필요한 서비스 비활성화</strong>: 사용하지 않는 IPMI 기능 비활성화</li>
</ol>

<hr />

<h2 id="vps와의-차이">VPS와의 차이</h2>

<p>VPS는 가상화 환경이라 IPMI 대신 호스팅 업체의 관리 패널에서 전원 제어와 콘솔 접속을 제공합니다. 전용서버의 IPMI는 물리 하드웨어를 직접 제어하므로 더 강력하고 안정적입니다.</p>

<p>TCP-80.NET의 <a href="/dedicated-server/">일본 전용서버</a>에는 IPMI가 기본으로 포함됩니다. IPMI 접속 정보는 서버 개설 시 함께 제공됩니다.</p>

<hr />

<h2 id="마치며">마치며</h2>

<p>IPMI는 일본 전용서버를 물리적 접근 없이도 완전하게 관리할 수 있게 해주는 핵심 기능입니다. 서버가 응답하지 않는 상황에서도 원격으로 복구할 수 있어 운영 안정성이 크게 높아집니다. IPMI 설정과 활용에 대한 문의는 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 전용서버의 IPMI(원격 하드웨어 관리 인터페이스)를 활용하는 방법을 안내합니다. OS 재설치, 서버 재시작, 원격 콘솔 접속 등 IPMI로 할 수 있는 모든 것을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버호스팅 비용 완전 비교 — AWS·클라우드 대비 전용서버·VPS 가격 분석</title><link href="https://tcp-80.net/blog/2026/03/21/japan-server-cost-comparison/" rel="alternate" type="text/html" title="일본 서버호스팅 비용 완전 비교 — AWS·클라우드 대비 전용서버·VPS 가격 분석" /><published>2026-03-21T00:00:00+09:00</published><updated>2026-03-21T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/03/21/japan-server-cost-comparison</id><content type="html" xml:base="https://tcp-80.net/blog/2026/03/21/japan-server-cost-comparison/"><![CDATA[<p>일본 서버호스팅을 검토할 때 “AWS나 구글 클라우드는 어떨까?”라는 의문이 생기는 경우가 많습니다. 이 글에서는 일본 전용서버·VPS와 주요 클라우드 서비스의 비용을 객관적으로 비교합니다.</p>

<h2 id="서버-유형별-특징-요약">서버 유형별 특징 요약</h2>

<table>
  <thead>
    <tr>
      <th>유형</th>
      <th>전용서버</th>
      <th>VPS</th>
      <th>퍼블릭 클라우드</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>리소스</td>
      <td>단독 점유</td>
      <td>가상화 공유</td>
      <td>가상화 공유</td>
    </tr>
    <tr>
      <td>가격</td>
      <td>고정 월정액</td>
      <td>고정 월정액</td>
      <td>사용량 기반</td>
    </tr>
    <tr>
      <td>확장성</td>
      <td>서버 교체 필요</td>
      <td>플랜 업그레이드</td>
      <td>즉시 스케일링</td>
    </tr>
    <tr>
      <td>관리</td>
      <td>직접 관리</td>
      <td>직접 관리</td>
      <td>관리형 옵션 있음</td>
    </tr>
    <tr>
      <td>예측 비용</td>
      <td>예측 가능</td>
      <td>예측 가능</td>
      <td>트래픽 급증 시 비용 폭증</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="비용-비교-동일-스펙-기준">비용 비교: 동일 스펙 기준</h2>

<h3 id="중급-웹-서버-스펙-기준-4-vcore-8gb-ram-200gb-ssd">중급 웹 서버 스펙 기준 (4 vCore, 8GB RAM, 200GB SSD)</h3>

<table>
  <thead>
    <tr>
      <th>서비스</th>
      <th>월 비용</th>
      <th>특이사항</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>TCP-80.NET VPS (일본)</td>
      <td>₩250,000</td>
      <td>고정 비용, DDoS 방어 포함</td>
    </tr>
    <tr>
      <td>AWS EC2 c6a.xlarge (도쿄)</td>
      <td>₩350,000~</td>
      <td>트래픽 요금 별도, 지원 비용 별도</td>
    </tr>
    <tr>
      <td>Google Cloud (도쿄)</td>
      <td>₩320,000~</td>
      <td>트래픽 요금 별도</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p>※ 클라우드 요금은 트래픽, 스토리지 I/O, 지원 플랜 등 추가 비용이 발생합니다.</p>
</blockquote>

<h3 id="고성능-서버-스펙-기준-8코어-32gb-ram-nvme">고성능 서버 스펙 기준 (8코어, 32GB RAM, NVMe)</h3>

<table>
  <thead>
    <tr>
      <th>서비스</th>
      <th>월 비용</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>TCP-80.NET 전용서버 (일본)</td>
      <td>₩600,000</td>
    </tr>
    <tr>
      <td>AWS EC2 m6a.2xlarge (도쿄)</td>
      <td>₩700,000~900,000 (트래픽 포함 시)</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="클라우드가-유리한-경우">클라우드가 유리한 경우</h2>

<ol>
  <li><strong>트래픽 예측 불가능</strong>: 갑자기 트래픽이 폭증했다가 다시 줄어드는 서비스</li>
  <li><strong>짧은 운영 기간</strong>: 이벤트성 서비스로 수일~수주만 운영</li>
  <li><strong>글로벌 멀티리전</strong>: 여러 국가에 동시에 서버가 필요한 경우</li>
  <li><strong>관리형 서비스 필요</strong>: RDS, Elastic Cache 등 관리형 DB·캐시 사용</li>
  <li><strong>팀 규모가 크고 DevOps 조직이 있는 경우</strong></li>
</ol>

<hr />

<h2 id="전용서버vps가-유리한-경우">전용서버·VPS가 유리한 경우</h2>

<ol>
  <li><strong>안정적인 트래픽</strong>: 예측 가능한 트래픽으로 월정액이 경제적</li>
  <li><strong>장기 운영</strong>: 1년 이상 안정적으로 운영하는 서비스</li>
  <li><strong>게임서버·채팅 서버</strong>: 네트워크 I/O가 많고 지연이 중요한 서비스</li>
  <li><strong>대용량 스토리지</strong>: 클라우드 스토리지 비용이 높을 때</li>
  <li><strong>DDoS 방어 필요</strong>: TCP-80.NET은 기본 DDoS 방어 무료 포함</li>
  <li><strong>비용 예측 중요</strong>: 스타트업이나 소규모 팀</li>
</ol>

<hr />

<h2 id="숨겨진-클라우드-비용-항목">숨겨진 클라우드 비용 항목</h2>

<p>클라우드는 기본 인스턴스 요금 외에 추가 비용이 많습니다:</p>

<ul>
  <li><strong>트래픽(Egress) 비용</strong>: AWS 도쿄 리전 기준 GB당 약 $0.114
    <ul>
      <li>월 1TB 트래픽 = 약 $114 (약 ₩150,000) 추가</li>
    </ul>
  </li>
  <li><strong>스토리지 I/O</strong>: EBS IO2 등 고성능 스토리지 사용 시 별도 과금</li>
  <li><strong>로드밸런서</strong>: ALB 기본 약 $16~25/월 + 처리 데이터 요금</li>
  <li><strong>지원 플랜</strong>: Developer 지원 $29/월, Business 지원 월 사용량의 10%</li>
  <li><strong>NAT Gateway</strong>: 내부 트래픽 라우팅에도 과금</li>
</ul>

<hr />

<h2 id="실제-예산-시뮬레이션">실제 예산 시뮬레이션</h2>

<h3 id="소규모-웹-서비스-월-트래픽-500gb-기준">소규모 웹 서비스 (월 트래픽 500GB 기준)</h3>

<p><strong>TCP-80.NET VPS (일본)</strong></p>
<ul>
  <li>서버 비용: ₩150,000/월</li>
  <li>추가 비용: 없음 (DDoS 방어 포함)</li>
  <li><strong>합계: ₩150,000/월</strong></li>
</ul>

<p><strong>AWS EC2 + RDS (도쿄)</strong></p>
<ul>
  <li>EC2 t3.medium: 약 ₩50,000/월</li>
  <li>RDS db.t3.small: 약 ₩80,000/월</li>
  <li>트래픽 500GB: 약 ₩70,000/월</li>
  <li><strong>합계: 약 ₩200,000/월 (+ 지원 비용)</strong></li>
</ul>

<hr />

<h2 id="결론-무엇을-선택해야-할까">결론: 무엇을 선택해야 할까?</h2>

<p><strong>1~2년 이상 안정적으로 운영하는 서비스</strong>라면 전용서버·VPS가 대부분 비용 효율적입니다. 월 고정 비용이 예측 가능하고, 동일 스펙 대비 클라우드보다 저렴한 경우가 많습니다.</p>

<p><strong>트래픽 변동이 극심하거나 글로벌 멀티리전이 필요한 서비스</strong>는 클라우드가 유리합니다.</p>

<p>TCP-80.NET은 <a href="/virtual-server/">일본 VPS</a>와 <a href="/dedicated-server/">전용서버</a>를 월정액 고정 비용으로 제공하며, 예산 계획에 도움이 필요하면 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅 비용을 AWS, 클라우드 서비스와 비교 분석합니다. 전용서버와 VPS가 클라우드 대비 어떤 경우에 비용 효율적인지, 실제 예산 시뮬레이션을 통해 알아보세요.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 PHP-FPM 최적화 가이드 — WordPress·Laravel 성능 극대화</title><link href="https://tcp-80.net/blog/2026/03/19/japan-server-php-fpm-guide/" rel="alternate" type="text/html" title="일본 서버 PHP-FPM 최적화 가이드 — WordPress·Laravel 성능 극대화" /><published>2026-03-19T00:00:00+09:00</published><updated>2026-03-19T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/03/19/japan-server-php-fpm-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/03/19/japan-server-php-fpm-guide/"><![CDATA[<p>일본 서버에서 WordPress, Laravel, CodeIgniter 등 PHP 기반 서비스를 운영할 때 PHP-FPM(FastCGI Process Manager) 설정이 성능에 큰 영향을 미칩니다. 잘못된 설정은 메모리 낭비나 요청 처리 지연으로 이어집니다. 이 글에서는 서버 스펙에 맞는 PHP-FPM 최적화 방법을 안내합니다.</p>

<h2 id="php-fpm이란">PHP-FPM이란?</h2>

<p>PHP-FPM은 PHP 요청을 처리하는 FastCGI 프로세스 관리자입니다. Nginx에서 PHP 요청이 오면 Unix 소켓 또는 TCP 소켓으로 PHP-FPM에 전달되어 처리됩니다.</p>

<p>주요 설정 파라미터:</p>
<ul>
  <li><strong>pm</strong>: 프로세스 관리 방식 (static, dynamic, ondemand)</li>
  <li><strong>pm.max_children</strong>: 최대 PHP 워커 프로세스 수</li>
  <li><strong>pm.start_servers</strong>: 시작 시 생성할 프로세스 수</li>
  <li><strong>pm.min_spare_servers</strong>: 최소 유휴 프로세스 수</li>
  <li><strong>pm.max_spare_servers</strong>: 최대 유휴 프로세스 수</li>
</ul>

<hr />

<h2 id="php-fpm-설정-파일-위치">PHP-FPM 설정 파일 위치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Ubuntu 22.04 기준</span>
/etc/php/8.1/fpm/pool.d/www.conf     <span class="c"># 풀 설정</span>
/etc/php/8.1/fpm/php.ini             <span class="c"># PHP 설정</span>
/etc/php/8.1/fpm/php-fpm.conf        <span class="c"># FPM 전체 설정</span>
</code></pre></div></div>

<hr />

<h2 id="스펙별-pmmax_children-계산">스펙별 pm.max_children 계산</h2>

<p><code class="language-plaintext highlighter-rouge">pm.max_children</code>을 너무 크게 설정하면 RAM이 부족해지고, 너무 작게 설정하면 요청이 대기합니다.</p>

<p>계산 공식:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pm.max_children = (가용 RAM - OS 사용 RAM) / PHP 워커당 평균 RAM
</code></pre></div></div>

<p>PHP 워커 하나가 사용하는 평균 RAM은 50~100MB입니다.</p>

<table>
  <thead>
    <tr>
      <th>서버 RAM</th>
      <th>OS 사용</th>
      <th>가용 RAM</th>
      <th>권장 max_children</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>2GB</td>
      <td>500MB</td>
      <td>1.5GB</td>
      <td>15~20</td>
    </tr>
    <tr>
      <td>4GB</td>
      <td>800MB</td>
      <td>3.2GB</td>
      <td>30~40</td>
    </tr>
    <tr>
      <td>8GB</td>
      <td>1GB</td>
      <td>7GB</td>
      <td>50~80</td>
    </tr>
  </tbody>
</table>

<p>현재 PHP 워커 RAM 사용량 확인:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ps aux | <span class="nb">grep </span>php-fpm | <span class="nb">awk</span> <span class="s1">'{print $6}'</span> | <span class="nb">sort</span> <span class="nt">-n</span> | <span class="nb">tail</span> <span class="nt">-5</span>
</code></pre></div></div>

<hr />

<h2 id="php-fpm-풀-설정-최적화">PHP-FPM 풀 설정 최적화</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">; /etc/php/8.1/fpm/pool.d/www.conf
</span><span class="w">
</span><span class="nn">[www]</span><span class="w">
</span><span class="py">user</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">www-data</span>
<span class="py">group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">www-data</span>
<span class="py">listen</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/run/php/php8.1-fpm.sock</span>
<span class="w">
</span><span class="c">; 프로세스 관리 방식
; - static: 고정 프로세스 수 (고트래픽에 적합)
; - dynamic: 트래픽에 따라 동적 조절
; - ondemand: 요청이 있을 때만 생성 (저트래픽)
</span><span class="py">pm</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">dynamic</span>
<span class="w">
</span><span class="c">; 4GB RAM 서버 기준
</span><span class="py">pm.max_children</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">40</span>
<span class="py">pm.start_servers</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">8</span>
<span class="py">pm.min_spare_servers</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">5</span>
<span class="py">pm.max_spare_servers</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">15</span>
<span class="w">
</span><span class="c">; 메모리 누수 방지: 일정 요청 처리 후 재시작
</span><span class="py">pm.max_requests</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">500</span>
<span class="w">
</span><span class="c">; 요청 타임아웃
</span><span class="py">request_terminate_timeout</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">60s</span>
<span class="w">
</span><span class="c">; 느린 로그 (2초 이상 소요 요청 기록)
</span><span class="py">slowlog</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/php-fpm/slow.log</span>
<span class="py">request_slowlog_timeout</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2s</span>
<span class="w">
</span><span class="c">; 프로세스 상태 페이지 (Nginx에서 내부적으로만 허용)
</span><span class="py">pm.status_path</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/php-fpm-status</span>
</code></pre></div></div>

<hr />

<h2 id="phpini-성능-설정">PHP.ini 성능 설정</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">; /etc/php/8.1/fpm/php.ini
</span><span class="w">
</span><span class="c">; 메모리 제한
</span><span class="py">memory_limit</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">256M</span>
<span class="w">
</span><span class="c">; 업로드 제한
</span><span class="py">upload_max_filesize</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">50M</span>
<span class="py">post_max_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">50M</span>
<span class="w">
</span><span class="c">; 실행 시간 제한
</span><span class="py">max_execution_time</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">60</span>
<span class="py">max_input_time</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">60</span>
<span class="w">
</span><span class="c">; 에러 표시 (프로덕션에서는 off)
</span><span class="py">display_errors</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">Off</span>
<span class="py">log_errors</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">On</span>
<span class="py">error_log</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/php/error.log</span>
</code></pre></div></div>

<hr />

<h2 id="opcache-활성화-필수">OPcache 활성화 (필수)</h2>

<p>OPcache는 PHP 스크립트를 컴파일된 형태로 메모리에 저장해, 매 요청마다 파싱·컴파일하는 오버헤드를 제거합니다. <strong>활성화만으로 PHP 성능이 2~5배 향상</strong>됩니다.</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">; OPcache 설정
</span><span class="py">opcache.enable</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1</span>
<span class="py">opcache.enable_cli</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">0</span>
<span class="py">opcache.memory_consumption</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">128    ; 메모리 할당 (MB)</span>
<span class="py">opcache.interned_strings_buffer</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">8</span>
<span class="py">opcache.max_accelerated_files</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10000</span>
<span class="py">opcache.validate_timestamps</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1     ; 파일 변경 감지 (개발 환경: 1, 프로덕션: 0)</span>
<span class="py">opcache.revalidate_freq</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">60        ; 변경 확인 주기 (초)</span>
<span class="py">opcache.fast_shutdown</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1</span>
</code></pre></div></div>

<p>OPcache 상태 확인:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>
<span class="nv">$status</span> <span class="o">=</span> <span class="nb">opcache_get_status</span><span class="p">();</span>
<span class="k">echo</span> <span class="s2">"Hit rate: "</span> <span class="mf">.</span> <span class="nv">$status</span><span class="p">[</span><span class="s1">'opcache_statistics'</span><span class="p">][</span><span class="s1">'opcache_hit_rate'</span><span class="p">]</span> <span class="mf">.</span> <span class="s2">"%"</span><span class="p">;</span>
</code></pre></div></div>

<hr />

<h2 id="php-fpm-상태-모니터링">PHP-FPM 상태 모니터링</h2>

<p>Nginx에서 PHP-FPM 상태 페이지를 내부 접근으로 노출:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">location</span> <span class="n">/php-fpm-status</span> <span class="p">{</span>
    <span class="kn">fastcgi_pass</span> <span class="s">unix:/run/php/php8.1-fpm.sock</span><span class="p">;</span>
    <span class="kn">fastcgi_index</span> <span class="s">index.php</span><span class="p">;</span>
    <span class="kn">include</span> <span class="s">fastcgi_params</span><span class="p">;</span>
    <span class="kn">fastcgi_param</span> <span class="s">SCRIPT_FILENAME</span> <span class="nv">$document_root$fastcgi_script_name</span><span class="p">;</span>
    <span class="kn">allow</span> <span class="mf">127.0</span><span class="s">.0.1</span><span class="p">;</span>
    <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl http://localhost/php-fpm-status
<span class="c"># 출력: pool, process manager, active processes, total requests 등</span>
</code></pre></div></div>

<hr />

<h2 id="설정-적용-및-확인">설정 적용 및 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># PHP-FPM 설정 테스트</span>
php-fpm8.1 <span class="nt">-t</span>

<span class="c"># 재시작</span>
systemctl restart php8.1-fpm

<span class="c"># 상태 확인</span>
systemctl status php8.1-fpm
</code></pre></div></div>

<hr />

<h2 id="마치며">마치며</h2>

<p>PHP-FPM 최적화는 서버 업그레이드 없이 성능을 크게 향상시킬 수 있는 방법입니다. 특히 OPcache 활성화는 모든 PHP 서비스에서 반드시 해야 하는 설정입니다. 일본 서버 PHP 환경 최적화에 대한 문의는 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅에서 PHP-FPM을 최적화해 WordPress, Laravel 등 PHP 기반 서비스 성능을 높이는 방법을 안내합니다. 프로세스 수 설정, OPcache 활성화, 메모리 최적화까지 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 Redis 캐시 서버 구축 가이드 — 응답 속도 극적으로 개선하기</title><link href="https://tcp-80.net/blog/2026/03/17/japan-server-redis-guide/" rel="alternate" type="text/html" title="일본 서버 Redis 캐시 서버 구축 가이드 — 응답 속도 극적으로 개선하기" /><published>2026-03-17T00:00:00+09:00</published><updated>2026-03-17T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/03/17/japan-server-redis-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/03/17/japan-server-redis-guide/"><![CDATA[<p>Redis는 인메모리 데이터 구조 저장소로, 일본 서버에서 웹 서비스 성능을 크게 향상시킬 수 있는 도구입니다. DB 쿼리 결과를 캐싱하고, 세션을 저장하며, 메시지 대기열을 구현하는 데 널리 사용됩니다.</p>

<h2 id="redis가-필요한-이유">Redis가 필요한 이유</h2>

<p>웹 서비스에서 데이터베이스는 대부분 디스크에서 데이터를 읽습니다. Redis는 데이터를 메모리(RAM)에 저장하므로 조회 속도가 데이터베이스 대비 수십~수백 배 빠릅니다.</p>

<p>대표적인 활용 사례:</p>
<ul>
  <li><strong>오브젝트 캐시</strong>: DB 쿼리 결과를 Redis에 저장해 반복 쿼리 제거</li>
  <li><strong>세션 저장</strong>: PHP, Node.js 세션을 Redis에 저장</li>
  <li><strong>속도 제한(Rate Limiting)</strong>: API 요청 횟수 제한</li>
  <li><strong>메시지 대기열</strong>: 비동기 작업 처리</li>
  <li><strong>실시간 기능</strong>: 채팅, 알림 등 Pub/Sub 구현</li>
</ul>

<hr />

<h2 id="1단계-redis-설치">1단계: Redis 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update
apt <span class="nb">install </span>redis-server <span class="nt">-y</span>

<span class="c"># 서비스 시작 및 자동 시작</span>
systemctl <span class="nb">enable </span>redis-server
systemctl start redis-server

<span class="c"># 버전 확인</span>
redis-server <span class="nt">--version</span>

<span class="c"># 동작 테스트</span>
redis-cli ping
<span class="c"># 응답: PONG</span>
</code></pre></div></div>

<hr />

<h2 id="2단계-redis-기본-설정">2단계: Redis 기본 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/redis/redis.conf
</code></pre></div></div>

<h3 id="메모리-제한-설정">메모리 제한 설정</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 최대 메모리 설정 (서버 RAM의 25~30%)
</span><span class="na">maxmemory</span><span class="w"> </span><span class="na">512mb</span><span class="w">

</span><span class="c"># 메모리 초과 시 정책 (캐시 용도라면 allkeys-lru)
</span><span class="na">maxmemory-policy</span><span class="w"> </span><span class="na">allkeys-lru</span><span class="w">
</span></code></pre></div></div>

<h3 id="보안-설정-비밀번호">보안 설정 (비밀번호)</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 비밀번호 설정
</span><span class="na">requirepass</span><span class="w"> </span><span class="na">강력한비밀번호</span><span class="w">

</span><span class="c"># 외부 접근 차단 (로컬만 허용)
</span><span class="na">bind</span><span class="w"> </span><span class="na">127.0.0.1</span><span class="w"> </span><span class="na">::1</span><span class="w">
</span></code></pre></div></div>

<h3 id="영속성-설정-선택">영속성 설정 (선택)</h3>

<p>캐시 목적이라면 영속성을 비활성화해 성능을 높일 수 있습니다:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># RDB 스냅샷 비활성화 (캐시 전용)
</span><span class="na">save</span><span class="w"> </span><span class="na">""</span><span class="w">

</span><span class="c"># AOF 비활성화
</span><span class="na">appendonly</span><span class="w"> </span><span class="na">no</span><span class="w">
</span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart redis-server
</code></pre></div></div>

<hr />

<h2 id="3단계-주요-redis-명령어">3단계: 주요 Redis 명령어</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Redis CLI 접속</span>
redis-cli <span class="nt">-a</span> 비밀번호

<span class="c"># 기본 조작</span>
SET key value          <span class="c"># 값 저장</span>
GET key                <span class="c"># 값 조회</span>
DEL key                <span class="c"># 키 삭제</span>
EXISTS key             <span class="c"># 키 존재 확인</span>
EXPIRE key 3600        <span class="c"># TTL 설정 (초)</span>
TTL key                <span class="c"># 남은 TTL 확인</span>

<span class="c"># 문자열</span>
SET user:1:name <span class="s2">"홍길동"</span>
GET user:1:name

<span class="c"># 해시 (오브젝트 저장)</span>
HSET user:1 name <span class="s2">"홍길동"</span> email <span class="s2">"hong@example.com"</span>
HGET user:1 name
HGETALL user:1

<span class="c"># 리스트 (대기열)</span>
RPUSH queue:email <span class="s2">"task1"</span>
LPOP queue:email

<span class="c"># 모니터링</span>
INFO memory         <span class="c"># 메모리 사용량</span>
INFO stats          <span class="c"># 통계</span>
DBSIZE              <span class="c"># 총 키 수</span>
</code></pre></div></div>

<hr />

<h2 id="4단계-언어별-redis-연동">4단계: 언어별 Redis 연동</h2>

<h3 id="php-wordpress-오브젝트-캐시">PHP (WordPress 오브젝트 캐시)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>php8.1-redis <span class="nt">-y</span>
systemctl restart php8.1-fpm
</code></pre></div></div>

<p>WordPress에서 <strong>Redis Object Cache</strong> 플러그인 설치 후 <code class="language-plaintext highlighter-rouge">wp-config.php</code>에 추가:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">define</span><span class="p">(</span><span class="s1">'WP_REDIS_HOST'</span><span class="p">,</span> <span class="s1">'127.0.0.1'</span><span class="p">);</span>
<span class="nb">define</span><span class="p">(</span><span class="s1">'WP_REDIS_PASSWORD'</span><span class="p">,</span> <span class="s1">'비밀번호'</span><span class="p">);</span>
<span class="nb">define</span><span class="p">(</span><span class="s1">'WP_REDIS_DATABASE'</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="nodejs-ioredis">Node.js (ioredis)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install </span>ioredis
</code></pre></div></div>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">Redis</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">ioredis</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">redis</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Redis</span><span class="p">({</span>
  <span class="na">host</span><span class="p">:</span> <span class="dl">'</span><span class="s1">127.0.0.1</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">port</span><span class="p">:</span> <span class="mi">6379</span><span class="p">,</span>
  <span class="na">password</span><span class="p">:</span> <span class="dl">'</span><span class="s1">비밀번호</span><span class="dl">'</span><span class="p">,</span>
<span class="p">});</span>

<span class="c1">// 캐시 패턴</span>
<span class="k">async</span> <span class="kd">function</span> <span class="nf">getUser</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">cached</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">redis</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="s2">`user:</span><span class="p">${</span><span class="nx">id</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
  <span class="k">if </span><span class="p">(</span><span class="nx">cached</span><span class="p">)</span> <span class="k">return</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">cached</span><span class="p">);</span>

  <span class="kd">const</span> <span class="nx">user</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">db</span><span class="p">.</span><span class="nf">findUser</span><span class="p">(</span><span class="nx">id</span><span class="p">);</span>  <span class="c1">// DB 조회</span>
  <span class="k">await</span> <span class="nx">redis</span><span class="p">.</span><span class="nf">setex</span><span class="p">(</span><span class="s2">`user:</span><span class="p">${</span><span class="nx">id</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span> <span class="mi">3600</span><span class="p">,</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">user</span><span class="p">));</span>  <span class="c1">// 1시간 캐시</span>
  <span class="k">return</span> <span class="nx">user</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="python-redis-py">Python (redis-py)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>redis
</code></pre></div></div>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">redis</span>
<span class="kn">import</span> <span class="n">json</span>

<span class="n">r</span> <span class="o">=</span> <span class="n">redis</span><span class="p">.</span><span class="nc">Redis</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="sh">'</span><span class="s">127.0.0.1</span><span class="sh">'</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">6379</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="sh">'</span><span class="s">비밀번호</span><span class="sh">'</span><span class="p">,</span> <span class="n">decode_responses</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">get_cached_data</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">fetch_func</span><span class="p">,</span> <span class="n">ttl</span><span class="o">=</span><span class="mi">3600</span><span class="p">):</span>
    <span class="n">cached</span> <span class="o">=</span> <span class="n">r</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">cached</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">json</span><span class="p">.</span><span class="nf">loads</span><span class="p">(</span><span class="n">cached</span><span class="p">)</span>

    <span class="n">data</span> <span class="o">=</span> <span class="nf">fetch_func</span><span class="p">()</span>
    <span class="n">r</span><span class="p">.</span><span class="nf">setex</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">ttl</span><span class="p">,</span> <span class="n">json</span><span class="p">.</span><span class="nf">dumps</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">ensure_ascii</span><span class="o">=</span><span class="bp">False</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">data</span>
</code></pre></div></div>

<hr />

<h2 id="5단계-세션-저장소로-활용">5단계: 세션 저장소로 활용</h2>

<h3 id="php-세션을-redis에-저장">PHP 세션을 Redis에 저장</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>php8.1-redis <span class="nt">-y</span>
</code></pre></div></div>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/php/8.1/fpm/php.ini
</span><span class="py">session.save_handler</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">redis</span>
<span class="py">session.save_path</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"tcp://127.0.0.1:6379?auth=비밀번호"</span>
</code></pre></div></div>

<p>세션 관리가 Redis로 이관되어 여러 서버 간 세션 공유도 가능해집니다.</p>

<hr />

<h2 id="redis-성능-확인">Redis 성능 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 성능 벤치마크</span>
redis-benchmark <span class="nt">-a</span> 비밀번호 <span class="nt">-q</span> <span class="nt">-n</span> 100000

<span class="c"># 히트율 확인 (keyspace_hits / (keyspace_hits + keyspace_misses))</span>
redis-cli <span class="nt">-a</span> 비밀번호 info stats | <span class="nb">grep </span>keyspace
</code></pre></div></div>

<p>캐시 히트율이 80% 이상이면 Redis가 효과적으로 동작하는 것입니다.</p>

<hr />

<h2 id="마치며">마치며</h2>

<p>Redis를 일본 서버에 도입하면 데이터베이스 부하를 크게 줄이고 응답 속도를 개선할 수 있습니다. 특히 트래픽이 많은 서비스에서 효과가 두드러집니다. Redis 설정에 대한 문의는 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅에 Redis를 설치하고 웹 서비스 캐시로 활용하는 방법을 안내합니다. 세션 저장, 오브젝트 캐시, 대기열 구현까지 Redis 활용법을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 게임서버 호스팅 추천 — 낮은 핑으로 쾌적한 플레이 환경 구축하기</title><link href="https://tcp-80.net/blog/2026/03/15/japan-game-server-hosting/" rel="alternate" type="text/html" title="일본 게임서버 호스팅 추천 — 낮은 핑으로 쾌적한 플레이 환경 구축하기" /><published>2026-03-15T00:00:00+09:00</published><updated>2026-03-15T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/03/15/japan-game-server-hosting</id><content type="html" xml:base="https://tcp-80.net/blog/2026/03/15/japan-game-server-hosting/"><![CDATA[<p>게임서버의 성능은 플레이어 경험에 직결됩니다. 핑(Ping)이 높으면 캐릭터가 버벅이고, 서버가 불안정하면 게임 도중 연결이 끊깁니다. 이 글에서는 일본 게임서버 호스팅을 선택하는 이유와 구축 시 핵심 고려사항을 안내합니다.</p>

<h2 id="왜-일본에-게임서버를-두나요">왜 일본에 게임서버를 두나요?</h2>

<h3 id="1-한일-간-낮은-레이턴시">1. 한·일 간 낮은 레이턴시</h3>

<p>서울에서 도쿄까지의 물리적 거리는 약 1,200km입니다. 광케이블로 연결되는 한·일 인터넷 회선은 왕복 지연(RTT)이 일반적으로 <strong>20~40ms</strong> 수준입니다. 대부분의 실시간 게임에서 40ms 이하는 ‘쾌적한’ 수준으로 분류됩니다.</p>

<p>반면 미국 서버(약 150~200ms)나 유럽 서버(약 250~300ms)는 체감 지연이 훨씬 큽니다.</p>

<h3 id="2-아시아-전역-커버">2. 아시아 전역 커버</h3>

<p>일본 도쿄는 아시아 인터넷 허브입니다. 한국뿐 아니라 일본, 대만, 홍콩, 동남아시아 플레이어도 비교적 낮은 핑으로 접속할 수 있어 아시아 유저 대상 글로벌 게임서버에 적합합니다.</p>

<h3 id="3-안정적인-인프라">3. 안정적인 인프라</h3>

<p>일본 도쿄 데이터센터는 이중화된 전력 공급(UPS + 발전기)과 네트워크 이중화를 갖추고 있습니다. 게임서버는 24시간 365일 무중단 운영이 기본이기 때문에 이 안정성이 중요합니다.</p>

<hr />

<h2 id="게임서버-호스팅-서버-선택-가이드">게임서버 호스팅 서버 선택 가이드</h2>

<h3 id="소규모-게임서버-1030명-vps">소규모 게임서버 (10~30명): VPS</h3>

<p>Minecraft 사설서버, 소규모 FPS 서버, 친목용 게임서버는 VPS로 충분합니다.</p>

<ul>
  <li><strong>권장 스펙</strong>: 2 vCore 이상, RAM 4GB 이상, 100GB SSD</li>
  <li><strong>예상 비용</strong>: 월 ₩150,000~250,000</li>
  <li><strong>적합한 게임</strong>: Minecraft, Terraria, 소규모 FPS</li>
</ul>

<p>TCP-80.NET <a href="/virtual-server/">일본 VPS</a>는 최대 4 vCore, 12GB RAM까지 지원합니다.</p>

<h3 id="중대규모-게임서버-50명-이상-전용서버">중·대규모 게임서버 (50명 이상): 전용서버</h3>

<p>MMO, 배틀로얄, 대규모 멀티플레이어 게임은 전용서버가 필요합니다. 물리 서버를 단독으로 사용하기 때문에 리소스 경합 없이 안정적인 성능을 보장합니다.</p>

<ul>
  <li><strong>권장 스펙</strong>: Intel Xeon 멀티코어, RAM 32GB 이상</li>
  <li><strong>예상 비용</strong>: 월 ₩300,000~1,200,000</li>
  <li><strong>적합한 게임</strong>: MMORPG, 대규모 배틀로얄, 게임 호스팅 플랫폼</li>
</ul>

<p>TCP-80.NET <a href="/dedicated-server/">일본 전용서버</a>는 Eco부터 High-End까지 5개 플랜을 제공합니다.</p>

<hr />

<h2 id="게임서버-호스팅-시-반드시-확인해야-할-3가지">게임서버 호스팅 시 반드시 확인해야 할 3가지</h2>

<h3 id="1-ddos-방어">1. DDoS 방어</h3>

<p>게임서버는 DDoS 공격의 주요 표적입니다. 특히 경쟁이 치열한 게임에서는 악의적인 플레이어나 경쟁 서버 운영자가 DDoS를 시도하는 경우가 있습니다.</p>

<p>TCP-80.NET은 모든 서버에 네트워크 레이어(L3/L4) DDoS 방어를 무료로 제공합니다. 더 강력한 보호가 필요하다면 <a href="/ddos-security/">전용 DDoS 방어 서비스</a>를 추가할 수 있습니다.</p>

<h3 id="2-포트-개방과-방화벽-설정">2. 포트 개방과 방화벽 설정</h3>

<p>게임마다 사용하는 포트가 다릅니다. 서버 호스팅 업체가 포트 개방과 방화벽 설정을 지원하는지 확인하세요. TCP-80.NET은 OS 설치 후 필요한 포트 설정을 텔레그램으로 지원합니다.</p>

<h3 id="3-ipmi-하드웨어-원격-관리">3. IPMI 하드웨어 원격 관리</h3>

<p>전용서버의 경우 OS 문제나 서버 다운 시 하드웨어 레벨에서 원격 접근할 수 있는 IPMI가 필수입니다. TCP-80.NET 전용서버에는 IPMI가 기본으로 포함됩니다.</p>

<hr />

<h2 id="게임서버-구축-시-추천-os">게임서버 구축 시 추천 OS</h2>

<table>
  <thead>
    <tr>
      <th>게임 엔진 / 서버</th>
      <th>권장 OS</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Minecraft Java</td>
      <td>Ubuntu 22.04 LTS</td>
    </tr>
    <tr>
      <td>Minecraft Bedrock</td>
      <td>Ubuntu 22.04 LTS</td>
    </tr>
    <tr>
      <td>Unreal Engine 서버</td>
      <td>Ubuntu 20.04 / Windows Server</td>
    </tr>
    <tr>
      <td>Unity Mirror 서버</td>
      <td>Ubuntu 20.04 LTS</td>
    </tr>
    <tr>
      <td>CS2 / TF2 서버</td>
      <td>Ubuntu 22.04 LTS</td>
    </tr>
    <tr>
      <td>자체 개발 게임</td>
      <td>개발 환경에 맞게 선택</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 게임서버 호스팅은 한국과 아시아 유저 모두에게 안정적인 레이턴시를 제공합니다. 서버 규모와 예산에 맞게 VPS 또는 전용서버를 선택하고, DDoS 방어는 처음부터 챙겨두는 것이 좋습니다.</p>

<p>게임서버 구성에 대한 문의는 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 연락해 주세요. 서버 개설부터 OS 설치, 방화벽 설정까지 24시간 한국어로 지원합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[게임서버를 일본에 두면 얼마나 빠를까요? 일본 게임서버 호스팅의 장점과 Minecraft, 서든어택, 배틀그라운드 등 게임서버 구축 시 고려사항을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본서버호스팅 완벽 가이드 — 전용서버·VPS·가상데스크톱 선택 방법</title><link href="https://tcp-80.net/blog/2026/03/10/japan-server-hosting-guide/" rel="alternate" type="text/html" title="일본서버호스팅 완벽 가이드 — 전용서버·VPS·가상데스크톱 선택 방법" /><published>2026-03-10T00:00:00+09:00</published><updated>2026-03-10T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/03/10/japan-server-hosting-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/03/10/japan-server-hosting-guide/"><![CDATA[<p>일본 서버 호스팅 서비스를 처음 고려하는 분들이 가장 많이 하는 질문이 있습니다. “전용서버와 VPS 중 무엇을 선택해야 하나요?” 이 글에서는 일본서버호스팅의 종류별 특징과 용도에 맞는 선택 방법을 정리합니다.</p>

<h2 id="일본서버호스팅이란">일본서버호스팅이란?</h2>

<p>일본서버호스팅은 일본 현지 데이터센터(IDC)에 위치한 서버를 임대해 웹사이트, 게임서버, 데이터베이스, 업무 시스템 등을 운영하는 서비스입니다.</p>

<p>한국에서 일본 서버를 사용하는 주요 이유는 다음과 같습니다:</p>

<ul>
  <li><strong>낮은 레이턴시</strong>: 한국과 일본은 지리적으로 가까워 왕복 지연이 20~30ms 수준</li>
  <li><strong>일본 IP 주소</strong>: 일본 현지 서비스 이용, 인터넷 뱅킹, 마케팅 등에 활용</li>
  <li><strong>안정적인 인프라</strong>: 일본 도쿄 데이터센터는 높은 전력 안정성과 네트워크 이중화를 갖춤</li>
  <li><strong>DDoS 방어</strong>: 전문 일본서버호스팅 업체들은 DDoS 방어 서비스를 기본 제공</li>
</ul>

<h2 id="일본서버호스팅-종류별-비교">일본서버호스팅 종류별 비교</h2>

<h3 id="1-일본-vps-가상-서버">1. 일본 VPS (가상 서버)</h3>

<p>VPS는 물리 서버를 가상화 기술로 분할한 서버 환경입니다. 독립된 OS와 리소스를 제공하면서도 전용서버보다 비용이 저렴합니다.</p>

<p><strong>적합한 용도:</strong></p>
<ul>
  <li>소규모~중규모 웹사이트 및 쇼핑몰</li>
  <li>스타트업·1인 개발자의 개발 서버</li>
  <li>블로그, 커뮤니티, 소규모 API 서버</li>
  <li>Node.js, Python, PHP 기반 웹 서비스</li>
</ul>

<p><strong>장점:</strong></p>
<ul>
  <li>월 10만원 수준의 합리적인 가격</li>
  <li>빠른 서버 개설 (당일 개설 가능)</li>
  <li>다양한 OS 선택 (Ubuntu, Debian, CentOS, Windows Server)</li>
</ul>

<p><strong>단점:</strong></p>
<ul>
  <li>물리 서버 리소스를 다른 VPS와 공유</li>
  <li>대규모 트래픽 처리에 한계</li>
</ul>

<p>TCP-80.NET 일본 VPS는 <a href="/virtual-server/">1 vCore부터 4 vCore까지 4개 플랜</a>을 제공하며 월 ₩100,000부터 시작합니다.</p>

<hr />

<h3 id="2-일본-전용서버-dedicated-server">2. 일본 전용서버 (Dedicated Server)</h3>

<p>전용서버는 물리 서버 하드웨어 전체를 단독으로 사용하는 서비스입니다. 최고 성능이 필요한 서비스에 적합합니다.</p>

<p><strong>적합한 용도:</strong></p>
<ul>
  <li>대규모 웹 서비스 및 트래픽이 많은 커머스</li>
  <li><strong>게임서버 호스팅</strong> (MMORPG, FPS, 샌드박스 등)</li>
  <li>고성능 데이터베이스 서버</li>
  <li>영상 스트리밍, 대용량 파일 서버</li>
  <li>금융·결제 서비스처럼 높은 안정성이 요구되는 환경</li>
</ul>

<p><strong>장점:</strong></p>
<ul>
  <li>CPU, RAM, 스토리지를 100% 단독 점유</li>
  <li>예측 가능한 성능 (리소스 경합 없음)</li>
  <li>IPMI 하드웨어 원격 관리 기본 제공</li>
  <li>Dell, HP 등 정품 벤더 서버 사용</li>
</ul>

<p><strong>단점:</strong></p>
<ul>
  <li>VPS보다 상대적으로 높은 비용</li>
</ul>

<p>TCP-80.NET 일본 전용서버는 <a href="/dedicated-server/">Intel Xeon 기반 5개 플랜</a>으로 월 ₩300,000부터 제공합니다.</p>

<hr />

<h3 id="3-일본-가상-데스크톱-rdp">3. 일본 가상 데스크톱 (RDP)</h3>

<p>일본 IP를 가진 Windows 가상 데스크톱으로, RDP(원격 데스크톱 프로토콜)로 접속해 일반 PC처럼 사용합니다.</p>

<p><strong>적합한 용도:</strong></p>
<ul>
  <li>일본 인터넷 뱅킹·금융 서비스 이용</li>
  <li>일본 한정 소프트웨어 또는 앱 사용</li>
  <li>업무용 Windows 프로그램 원격 실행</li>
  <li>일본 IP가 필요한 마케팅·광고 운영</li>
</ul>

<p>TCP-80.NET <a href="/virtual-desktop/">일본 가상 데스크톱</a>은 월 ₩150,000부터 시작합니다.</p>

<hr />

<h2 id="일본서버호스팅-선택-기준-요약">일본서버호스팅 선택 기준 요약</h2>

<table>
  <thead>
    <tr>
      <th>구분</th>
      <th>VPS</th>
      <th>전용서버</th>
      <th>가상 데스크톱</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>가격</td>
      <td>₩100,000~/월</td>
      <td>₩300,000~/월</td>
      <td>₩150,000~/월</td>
    </tr>
    <tr>
      <td>성능</td>
      <td>중간</td>
      <td>최고</td>
      <td>중간</td>
    </tr>
    <tr>
      <td>OS 환경</td>
      <td>Linux/Windows CLI</td>
      <td>Linux/Windows CLI</td>
      <td>Windows GUI</td>
    </tr>
    <tr>
      <td>주요 용도</td>
      <td>웹서비스, API</td>
      <td>게임서버, 대규모 DB</td>
      <td>인터넷 뱅킹, 업무</td>
    </tr>
    <tr>
      <td>서버 공유</td>
      <td>가상화 공유</td>
      <td>단독 점유</td>
      <td>가상화 공유</td>
    </tr>
  </tbody>
</table>

<h2 id="ddos-방어와-보안은-필수">DDoS 방어와 보안은 필수</h2>

<p>어떤 서버를 선택하든 DDoS 방어와 해킹 보안은 반드시 확인해야 합니다. TCP-80.NET은 모든 서버에 네트워크 레이어 DDoS 차단을 무료로 기본 제공합니다. 추가 보안이 필요하다면 <a href="/hacking-security/">WAF(웹방화벽)·해킹 보안 서비스</a>와 <a href="/ddos-security/">전용 DDoS 방어존</a>을 별도로 이용할 수 있습니다.</p>

<h2 id="마치며">마치며</h2>

<p>일본서버호스팅을 선택할 때는 서비스 규모, 예상 트래픽, 필요한 OS 환경을 먼저 파악하는 것이 중요합니다. 소규모 서비스는 VPS로 시작해 트래픽이 늘면 전용서버로 업그레이드하는 방법도 효과적입니다.</p>

<p>TCP-80.NET은 일본 도쿄 데이터센터를 직접 운영하며 24시간 한국어 지원을 제공합니다. 서버 선택에 대한 궁금한 점은 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본서버호스팅을 처음 시작한다면? 전용서버, VPS, 가상데스크톱의 차이와 용도별 올바른 선택 방법을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 방화벽 설정 가이드 — UFW와 iptables로 서버 보호하기</title><link href="https://tcp-80.net/blog/2026/03/02/japan-server-firewall-guide/" rel="alternate" type="text/html" title="일본 서버 방화벽 설정 가이드 — UFW와 iptables로 서버 보호하기" /><published>2026-03-02T00:00:00+09:00</published><updated>2026-03-02T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/03/02/japan-server-firewall-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/03/02/japan-server-firewall-guide/"><![CDATA[<p>일본 서버호스팅으로 서버를 받으면 인터넷에 직접 노출된 상태입니다. 방화벽 설정 없이 서버를 운영하면 불필요한 포트가 열려 있어 해킹·스캔 공격의 표적이 됩니다. 이 글에서는 Ubuntu 서버에서 UFW(간편 방화벽)와 iptables를 사용해 방화벽을 설정하는 방법을 안내합니다.</p>

<h2 id="ufw-vs-iptables">UFW vs iptables</h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>UFW</th>
      <th>iptables</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>사용 편의성</td>
      <td>간단한 명령어</td>
      <td>복잡한 문법</td>
    </tr>
    <tr>
      <td>유연성</td>
      <td>기본 규칙</td>
      <td>세밀한 제어</td>
    </tr>
    <tr>
      <td>권장 대상</td>
      <td>일반 서버 운영</td>
      <td>고급 네트워크 제어</td>
    </tr>
    <tr>
      <td>Ubuntu 통합</td>
      <td>기본 포함</td>
      <td>별도 설치</td>
    </tr>
  </tbody>
</table>

<p>대부분의 일본 서버 운영에는 UFW로 충분합니다.</p>

<hr />

<h2 id="ufw-기본-설정">UFW 기본 설정</h2>

<h3 id="1-ufw-기본-정책-설정">1. UFW 기본 정책 설정</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 들어오는 트래픽 기본 차단</span>
ufw default deny incoming

<span class="c"># 나가는 트래픽 기본 허용</span>
ufw default allow outgoing
</code></pre></div></div>

<h3 id="2-필요한-포트-허용">2. 필요한 포트 허용</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SSH (포트 번호는 실제 설정한 번호로)</span>
ufw allow 22222/tcp

<span class="c"># 웹 서비스</span>
ufw allow 80/tcp
ufw allow 443/tcp

<span class="c"># 특정 포트 허용</span>
ufw allow 3306/tcp   <span class="c"># MySQL (필요한 경우만)</span>
ufw allow 6379/tcp   <span class="c"># Redis (필요한 경우만)</span>
</code></pre></div></div>

<h3 id="3-특정-ip에서만-허용">3. 특정 IP에서만 허용</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 특정 IP에서만 SSH 허용</span>
ufw allow from 123.456.789.0 to any port 22222

<span class="c"># 특정 IP 대역 허용</span>
ufw allow from 123.456.0.0/16 to any port 3306
</code></pre></div></div>

<h3 id="4-ufw-활성화">4. UFW 활성화</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ufw <span class="nb">enable
</span>ufw status verbose
</code></pre></div></div>

<hr />

<h2 id="ufw-주요-명령어">UFW 주요 명령어</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 규칙 목록 확인 (번호 포함)</span>
ufw status numbered

<span class="c"># 특정 번호 규칙 삭제</span>
ufw delete 3

<span class="c"># 특정 포트 차단</span>
ufw deny 8080/tcp

<span class="c"># 특정 IP 차단</span>
ufw deny from 192.168.1.100

<span class="c"># UFW 비활성화 (주의)</span>
ufw disable

<span class="c"># 모든 규칙 초기화 (주의)</span>
ufw reset
</code></pre></div></div>

<hr />

<h2 id="iptables-고급-설정">iptables 고급 설정</h2>

<p>UFW가 내부적으로 iptables를 사용하지만, 더 세밀한 제어가 필요한 경우 직접 iptables를 사용합니다.</p>

<h3 id="syn-flood-방어">SYN Flood 방어</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SYN 쿠키 활성화 (커널 레벨)</span>
<span class="nb">echo </span>1 <span class="o">&gt;</span> /proc/sys/net/ipv4/tcp_syncookies

<span class="c"># SYN 패킷 속도 제한</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--syn</span> <span class="nt">-m</span> limit <span class="nt">--limit</span> 1/s <span class="nt">--limit-burst</span> 3 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--syn</span> <span class="nt">-j</span> DROP
</code></pre></div></div>

<h3 id="포트-스캔-방어">포트 스캔 방어</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># NULL 패킷 차단</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--tcp-flags</span> ALL NONE <span class="nt">-j</span> DROP

<span class="c"># Xmas 패킷 차단</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--tcp-flags</span> ALL ALL <span class="nt">-j</span> DROP

<span class="c"># 비정상 패킷 차단</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-m</span> conntrack <span class="nt">--ctstate</span> INVALID <span class="nt">-j</span> DROP
</code></pre></div></div>

<h3 id="ip당-연결-수-제한">IP당 연결 수 제한</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 하나의 IP에서 최대 20개 연결 허용</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">-m</span> connlimit <span class="nt">--connlimit-above</span> 20 <span class="nt">-j</span> REJECT

<span class="c"># 분당 연결 속도 제한</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-m</span> limit <span class="nt">--limit</span> 30/min <span class="nt">--limit-burst</span> 50 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-j</span> DROP
</code></pre></div></div>

<h3 id="iptables-규칙-영구-저장">iptables 규칙 영구 저장</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>iptables-persistent <span class="nt">-y</span>
netfilter-persistent save
netfilter-persistent reload
</code></pre></div></div>

<hr />

<h2 id="스크립트로-규칙-관리">스크립트로 규칙 관리</h2>

<p>방화벽 규칙이 복잡해지면 스크립트로 관리하는 것이 편리합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /usr/local/bin/firewall.sh</span>

<span class="c"># 기존 규칙 초기화</span>
iptables <span class="nt">-F</span>
iptables <span class="nt">-X</span>

<span class="c"># 기본 정책</span>
iptables <span class="nt">-P</span> INPUT DROP
iptables <span class="nt">-P</span> FORWARD DROP
iptables <span class="nt">-P</span> OUTPUT ACCEPT

<span class="c"># loopback 허용</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-i</span> lo <span class="nt">-j</span> ACCEPT

<span class="c"># 기존 연결 허용</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-m</span> conntrack <span class="nt">--ctstate</span> ESTABLISHED,RELATED <span class="nt">-j</span> ACCEPT

<span class="c"># SSH (포트 22222)</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 22222 <span class="nt">-j</span> ACCEPT

<span class="c"># HTTP/HTTPS</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 443 <span class="nt">-j</span> ACCEPT

<span class="c"># ICMP (ping)</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> icmp <span class="nt">--icmp-type</span> echo-request <span class="nt">-m</span> limit <span class="nt">--limit</span> 1/s <span class="nt">-j</span> ACCEPT

<span class="nb">echo</span> <span class="s2">"방화벽 규칙 적용 완료"</span>
iptables <span class="nt">-L</span> <span class="nt">-n</span> <span class="nt">-v</span>
</code></pre></div></div>

<hr />

<h2 id="방화벽-설정-확인">방화벽 설정 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># UFW 상태</span>
ufw status verbose

<span class="c"># iptables 규칙 확인</span>
iptables <span class="nt">-L</span> <span class="nt">-n</span> <span class="nt">-v</span> <span class="nt">--line-numbers</span>

<span class="c"># 열린 포트 확인</span>
ss <span class="nt">-tnlp</span>

<span class="c"># 외부에서 포트 스캔 (다른 서버에서 실행)</span>
nmap <span class="nt">-sV</span> 서버IP
</code></pre></div></div>

<hr />

<h2 id="마치며">마치며</h2>

<p>방화벽은 일본 서버 보안의 첫 번째 방어선입니다. UFW로 기본 설정을 마친 후 필요에 따라 iptables로 세밀하게 조정하세요. TCP-80.NET은 서버 방화벽 설정 지원을 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 제공합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="보안" /><summary type="html"><![CDATA[일본 서버호스팅에서 UFW와 iptables를 이용해 방화벽을 설정하는 방법을 안내합니다. 포트 제어, IP 차단, 연결 제한까지 서버 보안의 기본을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-security.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-security.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 모니터링 완전 가이드 — 장애를 미리 감지하는 방법</title><link href="https://tcp-80.net/blog/2026/02/23/japan-server-monitoring-guide/" rel="alternate" type="text/html" title="일본 서버 모니터링 완전 가이드 — 장애를 미리 감지하는 방법" /><published>2026-02-23T00:00:00+09:00</published><updated>2026-02-23T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/02/23/japan-server-monitoring-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/02/23/japan-server-monitoring-guide/"><![CDATA[<p>일본 서버에서 서비스를 운영할 때 모니터링은 장애를 사전에 예방하고, 문제 발생 시 빠르게 대응하기 위한 핵심 도구입니다. 이 글에서는 일본 서버 모니터링을 위한 CLI 도구부터 웹 기반 모니터링 솔루션, 외부 업타임 모니터링까지 단계별로 안내합니다.</p>

<h2 id="모니터링이-필요한-이유">모니터링이 필요한 이유</h2>

<ul>
  <li><strong>CPU 과부하 사전 감지</strong>: 서버 다운 전에 알림 수신</li>
  <li><strong>메모리 부족 대응</strong>: OOM(Out of Memory) 킬러 발동 전 조치</li>
  <li><strong>디스크 용량 관리</strong>: 디스크 풀로 인한 서비스 중단 방지</li>
  <li><strong>서비스 다운 감지</strong>: 웹서버, DB 장애를 즉시 알림</li>
</ul>

<hr />

<h2 id="1-기본-cli-모니터링-도구">1. 기본 CLI 모니터링 도구</h2>

<h3 id="htop--cpu메모리-실시간-확인">htop — CPU·메모리 실시간 확인</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>htop <span class="nt">-y</span>
htop
</code></pre></div></div>

<ul>
  <li>F2: 설정 (CPU 표시 방식 등)</li>
  <li>F3: 프로세스 검색</li>
  <li>F9: 프로세스 종료 신호 전송</li>
</ul>

<h3 id="iostat--디스크-io-모니터링">iostat — 디스크 I/O 모니터링</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>sysstat <span class="nt">-y</span>
iostat <span class="nt">-x</span> 1    <span class="c"># 1초마다 갱신</span>
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">%util</code> 항목이 90% 이상이면 디스크 I/O 병목</li>
</ul>

<h3 id="nethogs--프로세스별-네트워크-사용량">nethogs — 프로세스별 네트워크 사용량</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>nethogs <span class="nt">-y</span>
nethogs eth0
</code></pre></div></div>

<p>특정 프로세스가 비정상적으로 많은 네트워크 대역폭을 사용하는지 확인할 수 있습니다.</p>

<h3 id="ss--네트워크-연결-상태">ss — 네트워크 연결 상태</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># ESTABLISHED 연결 수 확인</span>
ss <span class="nt">-s</span>

<span class="c"># 특정 포트 연결 확인</span>
ss <span class="nt">-tnp</span> | <span class="nb">grep</span> :80
ss <span class="nt">-tnp</span> | <span class="nb">grep</span> :3306
</code></pre></div></div>

<hr />

<h2 id="2-netdata--실시간-웹-기반-모니터링">2. Netdata — 실시간 웹 기반 모니터링</h2>

<p>Netdata는 설치가 간단하고 실시간으로 CPU, 메모리, 디스크, 네트워크, Nginx, MySQL 등 다양한 메트릭을 시각화합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 설치</span>
wget <span class="nt">-O</span> /tmp/netdata-kickstart.sh https://my-netdata.io/kickstart.sh
sh /tmp/netdata-kickstart.sh <span class="nt">--non-interactive</span>
</code></pre></div></div>

<p>설치 후 <code class="language-plaintext highlighter-rouge">http://서버IP:19999</code>에서 실시간 대시보드 확인이 가능합니다.</p>

<h3 id="외부-접근-시-보안-설정">외부 접근 시 보안 설정</h3>

<p>Netdata 포트는 외부에 노출되지 않도록 로컬 바인딩 후 Nginx로 프록시하거나, IP 제한을 설정하세요:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># UFW로 19999 포트 접근 제한</span>
ufw allow from 내IP주소 to any port 19999
</code></pre></div></div>

<hr />

<h2 id="3-알림-설정--문제-발생-시-즉시-통보">3. 알림 설정 — 문제 발생 시 즉시 통보</h2>

<h3 id="간단한-서버-상태-확인-스크립트">간단한 서버 상태 확인 스크립트</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /usr/local/bin/check-server.sh</span>

<span class="nv">CPU</span><span class="o">=</span><span class="si">$(</span>top <span class="nt">-bn1</span> | <span class="nb">grep</span> <span class="s2">"Cpu(s)"</span> | <span class="nb">awk</span> <span class="s1">'{print $2}'</span> | <span class="nb">cut</span> <span class="nt">-d</span><span class="s1">'%'</span> <span class="nt">-f1</span><span class="si">)</span>
<span class="nv">MEM</span><span class="o">=</span><span class="si">$(</span>free | <span class="nb">grep </span>Mem | <span class="nb">awk</span> <span class="s1">'{printf "%.0f", $3/$2 * 100}'</span><span class="si">)</span>
<span class="nv">DISK</span><span class="o">=</span><span class="si">$(</span><span class="nb">df</span> <span class="nt">-h</span> / | <span class="nb">awk</span> <span class="s1">'NR==2 {print $5}'</span> | <span class="nb">cut</span> <span class="nt">-d</span><span class="s1">'%'</span> <span class="nt">-f1</span><span class="si">)</span>

<span class="c"># 임계값 초과 시 알림 (텔레그램 봇 예시)</span>
<span class="nv">THRESHOLD_CPU</span><span class="o">=</span>80
<span class="nv">THRESHOLD_MEM</span><span class="o">=</span>85
<span class="nv">THRESHOLD_DISK</span><span class="o">=</span>90

<span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$CPU</span><span class="s2">"</span> <span class="nt">-gt</span> <span class="s2">"</span><span class="nv">$THRESHOLD_CPU</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"경고: CPU 사용률 </span><span class="k">${</span><span class="nv">CPU</span><span class="k">}</span><span class="s2">% 초과"</span> | mail <span class="nt">-s</span> <span class="s2">"서버 경고"</span> admin@example.com
<span class="k">fi</span>
</code></pre></div></div>

<h3 id="웹-서비스-업타임-확인">웹 서비스 업타임 확인</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># 웹 서비스 응답 확인</span>
<span class="nv">HTTP_CODE</span><span class="o">=</span><span class="si">$(</span>curl <span class="nt">-s</span> <span class="nt">-o</span> /dev/null <span class="nt">-w</span> <span class="s2">"%{http_code}"</span> https://yourdomain.com<span class="si">)</span>

<span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$HTTP_CODE</span><span class="s2">"</span> <span class="o">!=</span> <span class="s2">"200"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"사이트 다운! HTTP 코드: </span><span class="nv">$HTTP_CODE</span><span class="s2">"</span> | mail <span class="nt">-s</span> <span class="s2">"장애 알림"</span> admin@example.com
<span class="k">fi</span>
</code></pre></div></div>

<p>crontab에 등록:</p>

<pre><code class="language-cron">*/5 * * * * /usr/local/bin/check-server.sh
*/5 * * * * /usr/local/bin/check-uptime.sh
</code></pre>

<hr />

<h2 id="4-외부-업타임-모니터링-서비스">4. 외부 업타임 모니터링 서비스</h2>

<p>서버 자체의 모니터링 스크립트는 서버가 다운되면 알림을 보낼 수 없습니다. 외부 모니터링 서비스를 병행하세요.</p>

<p>추천 무료 서비스:</p>
<ul>
  <li><strong>UptimeRobot</strong>: 5분 간격으로 서비스 상태 확인, 이메일/텔레그램 알림</li>
  <li><strong>Freshping</strong>: 1분 간격 모니터링, 여러 위치에서 확인</li>
  <li><strong>HetrixTools</strong>: IP·도메인 블랙리스트 모니터링 포함</li>
</ul>

<h3 id="uptimerobot-설정-방법">UptimeRobot 설정 방법</h3>

<ol>
  <li>uptimerobot.com 가입</li>
  <li>Add New Monitor → HTTP(s) 선택</li>
  <li>URL 입력 및 알림 설정 (텔레그램 또는 이메일)</li>
  <li>5분 간격 자동 확인 시작</li>
</ol>

<hr />

<h2 id="5-로그-분석으로-문제-패턴-파악">5. 로그 분석으로 문제 패턴 파악</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 최근 Nginx 에러 로그 확인</span>
<span class="nb">tail</span> <span class="nt">-100</span> /var/log/nginx/error.log

<span class="c"># 가장 많이 접속한 IP TOP 10</span>
<span class="nb">awk</span> <span class="s1">'{print $1}'</span> /var/log/nginx/access.log | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-10</span>

<span class="c"># 500 에러 발생 URL</span>
<span class="nb">awk</span> <span class="s1">'$9 == "500" {print $7}'</span> /var/log/nginx/access.log | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span>

<span class="c"># 오늘의 접속 수</span>
<span class="nb">grep</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">date</span> <span class="s1">'+%d/%b/%Y'</span><span class="si">)</span><span class="s2">"</span> /var/log/nginx/access.log | <span class="nb">wc</span> <span class="nt">-l</span>
</code></pre></div></div>

<hr />

<h2 id="서버-상태-한눈에-보기">서버 상태 한눈에 보기</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 시스템 요약 정보</span>
<span class="nb">echo</span> <span class="s2">"=== CPU ==="</span> <span class="o">&amp;&amp;</span> top <span class="nt">-bn1</span> | <span class="nb">grep</span> <span class="s2">"Cpu(s)"</span>
<span class="nb">echo</span> <span class="s2">"=== Memory ==="</span> <span class="o">&amp;&amp;</span> free <span class="nt">-h</span>
<span class="nb">echo</span> <span class="s2">"=== Disk ==="</span> <span class="o">&amp;&amp;</span> <span class="nb">df</span> <span class="nt">-h</span> /
<span class="nb">echo</span> <span class="s2">"=== Load ==="</span> <span class="o">&amp;&amp;</span> <span class="nb">uptime
echo</span> <span class="s2">"=== Services ==="</span> <span class="o">&amp;&amp;</span> systemctl is-active nginx mariadb
</code></pre></div></div>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버를 24시간 안정적으로 운영하려면 모니터링은 필수입니다. Netdata로 실시간 상태를 확인하고, UptimeRobot으로 외부에서 업타임을 감시하면 대부분의 장애를 사전에 대응할 수 있습니다. 서버 모니터링 설정에 대한 문의는 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅 운영 시 서버 상태를 실시간으로 모니터링하는 방법을 안내합니다. 기본 CLI 도구부터 Netdata, 업타임 모니터링, 알림 설정까지 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 Nginx 설정 완전 가이드 — 웹서버 설치부터 성능 최적화까지</title><link href="https://tcp-80.net/blog/2026/02/16/japan-server-nginx-guide/" rel="alternate" type="text/html" title="일본 서버 Nginx 설정 완전 가이드 — 웹서버 설치부터 성능 최적화까지" /><published>2026-02-16T00:00:00+09:00</published><updated>2026-02-16T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/02/16/japan-server-nginx-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/02/16/japan-server-nginx-guide/"><![CDATA[<p>Nginx는 일본 서버호스팅에서 가장 많이 사용되는 웹서버입니다. Apache보다 높은 동시 접속 처리 성능과 낮은 메모리 사용으로 특히 트래픽이 많은 서비스에 적합합니다. 이 글에서는 Nginx 설치부터 성능 최적화, 보안 설정까지 완전하게 안내합니다.</p>

<h2 id="nginx-vs-apache-선택">Nginx vs Apache 선택</h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>Nginx</th>
      <th>Apache</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>동시 접속 처리</td>
      <td>이벤트 기반, 우수</td>
      <td>프로세스 기반, 보통</td>
    </tr>
    <tr>
      <td>메모리 사용</td>
      <td>낮음</td>
      <td>높음</td>
    </tr>
    <tr>
      <td>정적 파일 제공</td>
      <td>매우 빠름</td>
      <td>빠름</td>
    </tr>
    <tr>
      <td>.htaccess 지원</td>
      <td>미지원</td>
      <td>지원</td>
    </tr>
    <tr>
      <td>리버스 프록시</td>
      <td>우수</td>
      <td>보통</td>
    </tr>
    <tr>
      <td>권장 용도</td>
      <td>고트래픽, API, 리버스 프록시</td>
      <td>공유 호스팅, .htaccess 필요 시</td>
    </tr>
  </tbody>
</table>

<p>일본 서버에서 자체 서비스를 운영한다면 대부분의 경우 Nginx를 권장합니다.</p>

<hr />

<h2 id="1단계-nginx-설치">1단계: Nginx 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update
apt <span class="nb">install </span>nginx <span class="nt">-y</span>

systemctl <span class="nb">enable </span>nginx
systemctl start nginx

<span class="c"># 버전 및 설정 확인</span>
nginx <span class="nt">-v</span>
nginx <span class="nt">-t</span>
</code></pre></div></div>

<hr />

<h2 id="2단계-기본-설정-최적화">2단계: 기본 설정 최적화</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/nginx.conf</span>
<span class="k">user</span> <span class="s">www-data</span><span class="p">;</span>
<span class="k">worker_processes</span> <span class="s">auto</span><span class="p">;</span>
<span class="k">worker_rlimit_nofile</span> <span class="mi">65535</span><span class="p">;</span>
<span class="k">pid</span> <span class="n">/run/nginx.pid</span><span class="p">;</span>

<span class="k">events</span> <span class="p">{</span>
    <span class="kn">worker_connections</span> <span class="mi">4096</span><span class="p">;</span>
    <span class="kn">multi_accept</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">use</span> <span class="s">epoll</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">http</span> <span class="p">{</span>
    <span class="c1"># 기본 설정</span>
    <span class="kn">sendfile</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">tcp_nopush</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">tcp_nodelay</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">server_tokens</span> <span class="no">off</span><span class="p">;</span>  <span class="c1"># Nginx 버전 정보 숨김</span>

    <span class="c1"># 타임아웃</span>
    <span class="kn">keepalive_timeout</span> <span class="mi">30</span><span class="p">;</span>
    <span class="kn">keepalive_requests</span> <span class="mi">1000</span><span class="p">;</span>
    <span class="kn">client_body_timeout</span> <span class="mi">10</span><span class="p">;</span>
    <span class="kn">client_header_timeout</span> <span class="mi">10</span><span class="p">;</span>
    <span class="kn">send_timeout</span> <span class="mi">30</span><span class="p">;</span>

    <span class="c1"># 버퍼 설정</span>
    <span class="kn">client_body_buffer_size</span> <span class="mi">128k</span><span class="p">;</span>
    <span class="kn">client_max_body_size</span> <span class="mi">50m</span><span class="p">;</span>
    <span class="kn">client_header_buffer_size</span> <span class="mi">1k</span><span class="p">;</span>
    <span class="kn">large_client_header_buffers</span> <span class="mi">4</span> <span class="mi">16k</span><span class="p">;</span>

    <span class="c1"># MIME 타입</span>
    <span class="kn">include</span> <span class="n">/etc/nginx/mime.types</span><span class="p">;</span>
    <span class="kn">default_type</span> <span class="nc">application/octet-stream</span><span class="p">;</span>

    <span class="c1"># 로그</span>
    <span class="kn">access_log</span> <span class="n">/var/log/nginx/access.log</span><span class="p">;</span>
    <span class="kn">error_log</span> <span class="n">/var/log/nginx/error.log</span> <span class="s">warn</span><span class="p">;</span>

    <span class="c1"># Gzip 압축</span>
    <span class="kn">gzip</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">gzip_vary</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">gzip_proxied</span> <span class="s">any</span><span class="p">;</span>
    <span class="kn">gzip_comp_level</span> <span class="mi">6</span><span class="p">;</span>
    <span class="kn">gzip_min_length</span> <span class="mi">1000</span><span class="p">;</span>
    <span class="kn">gzip_types</span>
        <span class="nc">text/plain</span> <span class="nc">text/css</span> <span class="nc">text/xml</span> <span class="nc">text/javascript</span>
        <span class="nc">application/json</span> <span class="nc">application/javascript</span> <span class="nc">application/xml</span>
        <span class="nc">application/rss</span><span class="s">+xml</span> <span class="nc">font/truetype</span> <span class="nc">font/opentype</span>
        <span class="nc">image/svg</span><span class="s">+xml</span><span class="p">;</span>

    <span class="kn">include</span> <span class="n">/etc/nginx/conf.d/*.conf</span><span class="p">;</span>
    <span class="kn">include</span> <span class="n">/etc/nginx/sites-enabled/*</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="3단계-가상-호스트server-block-설정">3단계: 가상 호스트(Server Block) 설정</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/sites-available/mysite.conf</span>
<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
    <span class="kn">listen</span> <span class="s">[::]:80</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">yourdomain.com</span> <span class="s">www.yourdomain.com</span><span class="p">;</span>
    <span class="kn">root</span> <span class="n">/var/www/mysite</span><span class="p">;</span>
    <span class="kn">index</span> <span class="s">index.html</span> <span class="s">index.php</span><span class="p">;</span>

    <span class="c1"># 보안 헤더</span>
    <span class="kn">add_header</span> <span class="s">X-Frame-Options</span> <span class="s">"SAMEORIGIN"</span> <span class="s">always</span><span class="p">;</span>
    <span class="kn">add_header</span> <span class="s">X-Content-Type-Options</span> <span class="s">"nosniff"</span> <span class="s">always</span><span class="p">;</span>
    <span class="kn">add_header</span> <span class="s">X-XSS-Protection</span> <span class="s">"1</span><span class="p">;</span> <span class="kn">mode=block"</span> <span class="s">always</span><span class="p">;</span>
    <span class="kn">add_header</span> <span class="s">Referrer-Policy</span> <span class="s">"no-referrer-when-downgrade"</span> <span class="s">always</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">try_files</span> <span class="nv">$uri</span> <span class="nv">$uri</span><span class="n">/</span> <span class="p">=</span><span class="mi">404</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># PHP 처리 (PHP-FPM 사용 시)</span>
    <span class="kn">location</span> <span class="p">~</span> <span class="sr">\.php$</span> <span class="p">{</span>
        <span class="kn">fastcgi_pass</span> <span class="s">unix:/var/run/php/php8.1-fpm.sock</span><span class="p">;</span>
        <span class="kn">fastcgi_index</span> <span class="s">index.php</span><span class="p">;</span>
        <span class="kn">include</span> <span class="s">fastcgi_params</span><span class="p">;</span>
        <span class="kn">fastcgi_param</span> <span class="s">SCRIPT_FILENAME</span> <span class="nv">$document_root$fastcgi_script_name</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># 정적 파일 캐싱</span>
    <span class="kn">location</span> <span class="p">~</span><span class="sr">*</span> <span class="err">\</span><span class="s">.(jpg|jpeg|png|gif|webp|ico|svg|css|js|woff|woff2|ttf)</span>$ <span class="p">{</span>
        <span class="kn">expires</span> <span class="s">1y</span><span class="p">;</span>
        <span class="kn">add_header</span> <span class="s">Cache-Control</span> <span class="s">"public,</span> <span class="s">immutable"</span><span class="p">;</span>
        <span class="kn">access_log</span> <span class="no">off</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># 숨김 파일 차단 (.git, .env 등)</span>
    <span class="kn">location</span> <span class="p">~</span> <span class="sr">/\.</span> <span class="p">{</span>
        <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
        <span class="kn">access_log</span> <span class="no">off</span><span class="p">;</span>
        <span class="kn">log_not_found</span> <span class="no">off</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>설정 활성화:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> <span class="nt">-s</span> /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/
nginx <span class="nt">-t</span>
systemctl reload nginx
</code></pre></div></div>

<hr />

<h2 id="4단계-리버스-프록시-설정-nodejspython-앱">4단계: 리버스 프록시 설정 (Node.js/Python 앱)</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">upstream</span> <span class="s">myapp</span> <span class="p">{</span>
    <span class="kn">server</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">3000</span><span class="p">;</span>
    <span class="kn">keepalive</span> <span class="mi">32</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">api.yourdomain.com</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://myapp</span><span class="p">;</span>
        <span class="kn">proxy_http_version</span> <span class="mf">1.1</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Upgrade</span> <span class="nv">$http_upgrade</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Connection</span> <span class="s">"upgrade"</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-Proto</span> <span class="nv">$scheme</span><span class="p">;</span>
        <span class="kn">proxy_read_timeout</span> <span class="mi">90</span><span class="p">;</span>
        <span class="kn">proxy_connect_timeout</span> <span class="mi">90</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="5단계-접속-제한-설정-보안">5단계: 접속 제한 설정 (보안)</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">http</span> <span class="p">{</span>
    <span class="c1"># IP당 연결 속도 제한</span>
    <span class="kn">limit_req_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=general:10m</span> <span class="s">rate=30r/m</span><span class="p">;</span>
    <span class="kn">limit_req_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=login:10m</span> <span class="s">rate=5r/m</span><span class="p">;</span>
    <span class="kn">limit_conn_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=addr:10m</span><span class="p">;</span>

    <span class="kn">server</span> <span class="p">{</span>
        <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
            <span class="kn">limit_req</span> <span class="s">zone=general</span> <span class="s">burst=10</span> <span class="s">nodelay</span><span class="p">;</span>
            <span class="kn">limit_conn</span> <span class="s">addr</span> <span class="mi">20</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="c1"># 로그인 페이지 강화</span>
        <span class="kn">location</span> <span class="n">/login</span> <span class="p">{</span>
            <span class="kn">limit_req</span> <span class="s">zone=login</span> <span class="s">burst=5</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="유용한-nginx-명령어">유용한 Nginx 명령어</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx <span class="nt">-t</span>              <span class="c"># 설정 파일 문법 확인</span>
nginx <span class="nt">-s</span> reload       <span class="c"># 무중단 설정 재로드</span>
nginx <span class="nt">-s</span> stop         <span class="c"># 즉시 중지</span>
systemctl reload nginx <span class="c"># 설정 재로드 (권장)</span>

<span class="c"># 로그 실시간 모니터링</span>
<span class="nb">tail</span> <span class="nt">-f</span> /var/log/nginx/access.log
<span class="nb">tail</span> <span class="nt">-f</span> /var/log/nginx/error.log
</code></pre></div></div>

<hr />

<h2 id="마치며">마치며</h2>

<p>Nginx를 올바르게 설정하면 일본 서버에서 빠르고 안전한 웹 서비스를 운영할 수 있습니다. 설정에 어려움이 있으시면 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅에서 Nginx를 설치하고 최적화하는 방법을 안내합니다. 가상 호스트 설정, SSL, Gzip 압축, 캐시, 보안 헤더까지 Nginx 운영에 필요한 모든 것을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 MySQL·MariaDB 설치 및 보안 최적화 가이드</title><link href="https://tcp-80.net/blog/2026/02/09/japan-server-mysql-guide/" rel="alternate" type="text/html" title="일본 서버 MySQL·MariaDB 설치 및 보안 최적화 가이드" /><published>2026-02-09T00:00:00+09:00</published><updated>2026-02-09T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/02/09/japan-server-mysql-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/02/09/japan-server-mysql-guide/"><![CDATA[<p>일본 서버에서 웹 서비스를 운영하면 거의 모든 경우 데이터베이스가 필요합니다. MySQL 또는 MariaDB는 웹 서비스에 가장 많이 사용되는 RDBMS입니다. 이 글에서는 일본 서버(Ubuntu 22.04)에 MariaDB를 설치하고 보안 설정 및 성능 최적화하는 방법을 안내합니다.</p>

<h2 id="mariadb-vs-mysql-선택">MariaDB vs MySQL 선택</h2>

<p>MariaDB는 MySQL의 오픈소스 포크로, MySQL과 완전히 호환되며 성능 개선과 추가 기능을 제공합니다. Ubuntu 22.04의 기본 저장소에서 바로 설치할 수 있어 편리합니다.</p>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>MariaDB</th>
      <th>MySQL</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>라이선스</td>
      <td>GPL (완전 오픈소스)</td>
      <td>듀얼 라이선스</td>
    </tr>
    <tr>
      <td>성능</td>
      <td>일부 쿼리에서 더 빠름</td>
      <td>표준</td>
    </tr>
    <tr>
      <td>호환성</td>
      <td>MySQL과 완전 호환</td>
      <td>표준</td>
    </tr>
    <tr>
      <td>권장</td>
      <td>대부분의 웹 서비스</td>
      <td>엔터프라이즈</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="1단계-mariadb-설치">1단계: MariaDB 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update
apt <span class="nb">install </span>mariadb-server mariadb-client <span class="nt">-y</span>

<span class="c"># 서비스 시작 및 자동 시작 설정</span>
systemctl <span class="nb">enable </span>mariadb
systemctl start mariadb

<span class="c"># 버전 확인</span>
mysql <span class="nt">--version</span>
</code></pre></div></div>

<hr />

<h2 id="2단계-보안-초기-설정">2단계: 보안 초기 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysql_secure_installation
</code></pre></div></div>

<p>대화형 설정에서:</p>
<ul>
  <li><strong>root 비밀번호 설정</strong>: 강력한 비밀번호 설정 (Y)</li>
  <li><strong>익명 사용자 제거</strong>: Y</li>
  <li><strong>원격 root 로그인 차단</strong>: Y</li>
  <li><strong>test 데이터베이스 삭제</strong>: Y</li>
  <li><strong>권한 테이블 재로드</strong>: Y</li>
</ul>

<hr />

<h2 id="3단계-데이터베이스-및-사용자-생성">3단계: 데이터베이스 및 사용자 생성</h2>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- root로 접속</span>
<span class="n">mysql</span> <span class="o">-</span><span class="n">u</span> <span class="n">root</span> <span class="o">-</span><span class="n">p</span>

<span class="c1">-- 데이터베이스 생성</span>
<span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">myapp_db</span> <span class="nb">CHARACTER</span> <span class="k">SET</span> <span class="n">utf8mb4</span> <span class="k">COLLATE</span> <span class="n">utf8mb4_unicode_ci</span><span class="p">;</span>

<span class="c1">-- 전용 사용자 생성 (localhost만 허용)</span>
<span class="k">CREATE</span> <span class="k">USER</span> <span class="s1">'myapp_user'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="s1">'강력한패스워드'</span><span class="p">;</span>

<span class="c1">-- 권한 부여</span>
<span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">PRIVILEGES</span> <span class="k">ON</span> <span class="n">myapp_db</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">'myapp_user'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>

<span class="c1">-- 권한 적용</span>
<span class="n">FLUSH</span> <span class="k">PRIVILEGES</span><span class="p">;</span>

<span class="c1">-- 생성 확인</span>
<span class="k">SHOW</span> <span class="n">DATABASES</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="k">User</span><span class="p">,</span> <span class="k">Host</span> <span class="k">FROM</span> <span class="n">mysql</span><span class="p">.</span><span class="k">user</span><span class="p">;</span>
</code></pre></div></div>

<hr />

<h2 id="4단계-성능-튜닝-설정">4단계: 성능 튜닝 설정</h2>

<p>서버 RAM에 따라 MariaDB 설정을 최적화합니다.</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/mysql/mariadb.conf.d/99-optimize.cnf
</span><span class="w">
</span><span class="nn">[mysqld]</span><span class="w">
</span><span class="c"># InnoDB 버퍼 풀 (RAM의 50~70%)
# 4GB RAM 서버 기준
</span><span class="py">innodb_buffer_pool_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2G</span>
<span class="py">innodb_buffer_pool_instances</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2</span>
<span class="w">
</span><span class="c"># 로그 설정
</span><span class="py">innodb_log_file_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">256M</span>
<span class="py">innodb_flush_log_at_trx_commit</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2  # 성능 우선 (1은 안전 우선)</span>
<span class="w">
</span><span class="c"># 연결 수
</span><span class="py">max_connections</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">150</span>
<span class="py">thread_cache_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">16</span>
<span class="w">
</span><span class="c"># 쿼리 캐시 (MariaDB 10.4 이상에서는 비권장)
</span><span class="py">query_cache_type</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">0</span>
<span class="py">query_cache_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">0</span>
<span class="w">
</span><span class="c"># 임시 테이블
</span><span class="py">tmp_table_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">64M</span>
<span class="py">max_heap_table_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">64M</span>
<span class="w">
</span><span class="c"># 슬로우 쿼리 로그
</span><span class="py">slow_query_log</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1</span>
<span class="py">slow_query_log_file</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/mysql/slow.log</span>
<span class="py">long_query_time</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart mariadb
</code></pre></div></div>

<hr />

<h2 id="5단계-원격-접속-설정-선택사항">5단계: 원격 접속 설정 (선택사항)</h2>

<p>보안상 DB는 localhost에서만 접속하는 것이 원칙이지만, 개발 편의를 위해 특정 IP에서 원격 접속을 허용할 수 있습니다.</p>

<h3 id="mariadb-바인딩-설정">MariaDB 바인딩 설정</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/mysql/mariadb.conf.d/50-server.cnf
</span><span class="nn">[mysqld]</span><span class="w">
</span><span class="py">bind-address</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">0.0.0.0  # 모든 IP 허용 (방화벽으로 제한)</span>
</code></pre></div></div>

<h3 id="특정-ip-원격-접속-사용자-생성">특정 IP 원격 접속 사용자 생성</h3>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 특정 IP(예: 123.456.789.0)에서만 접속 허용</span>
<span class="k">CREATE</span> <span class="k">USER</span> <span class="s1">'remote_user'</span><span class="o">@</span><span class="s1">'123.456.789.0'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="s1">'강력한패스워드'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span><span class="p">,</span> <span class="k">INSERT</span><span class="p">,</span> <span class="k">UPDATE</span> <span class="k">ON</span> <span class="n">myapp_db</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">'remote_user'</span><span class="o">@</span><span class="s1">'123.456.789.0'</span><span class="p">;</span>
<span class="n">FLUSH</span> <span class="k">PRIVILEGES</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="방화벽에서-db-포트-제한">방화벽에서 DB 포트 제한</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 특정 IP에서만 3306 포트 허용</span>
ufw allow from 123.456.789.0 to any port 3306
</code></pre></div></div>

<hr />

<h2 id="6단계-데이터베이스-모니터링">6단계: 데이터베이스 모니터링</h2>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 현재 연결 수</span>
<span class="k">SHOW</span> <span class="n">STATUS</span> <span class="k">LIKE</span> <span class="s1">'Threads_connected'</span><span class="p">;</span>

<span class="c1">-- 슬로우 쿼리 수</span>
<span class="k">SHOW</span> <span class="n">STATUS</span> <span class="k">LIKE</span> <span class="s1">'Slow_queries'</span><span class="p">;</span>

<span class="c1">-- InnoDB 버퍼 풀 효율</span>
<span class="k">SHOW</span> <span class="n">STATUS</span> <span class="k">LIKE</span> <span class="s1">'Innodb_buffer_pool_read%'</span><span class="p">;</span>

<span class="c1">-- 실행 중인 쿼리 확인</span>
<span class="k">SHOW</span> <span class="n">PROCESSLIST</span><span class="p">;</span>
</code></pre></div></div>

<hr />

<h2 id="보안-체크리스트">보안 체크리스트</h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>확인</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>root 비밀번호 설정</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>익명 사용자 제거</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>원격 root 로그인 차단</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>애플리케이션 전용 사용자 사용</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>최소 권한 원칙 적용</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>정기 백업 설정</td>
      <td>☐</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버에서 MariaDB를 올바르게 설정하면 안전하고 빠른 데이터베이스 환경을 구축할 수 있습니다. DB 설정에 도움이 필요하시면 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅에 MySQL 또는 MariaDB를 설치하고 보안 설정 및 성능 최적화하는 방법을 안내합니다. 초기 설정부터 원격 접속, 성능 튜닝까지 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 트래픽 급증 대비 방법 — 스케일링 전략과 실전 설정</title><link href="https://tcp-80.net/blog/2026/02/02/japan-server-traffic-scaling/" rel="alternate" type="text/html" title="일본 서버 트래픽 급증 대비 방법 — 스케일링 전략과 실전 설정" /><published>2026-02-02T00:00:00+09:00</published><updated>2026-02-02T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/02/02/japan-server-traffic-scaling</id><content type="html" xml:base="https://tcp-80.net/blog/2026/02/02/japan-server-traffic-scaling/"><![CDATA[<p>일본 서버에서 서비스를 운영하다 보면 예상치 못한 트래픽 급증이 발생할 수 있습니다. 신제품 출시, 미디어 노출, 이벤트 시작 등으로 평소 대비 수십 배의 트래픽이 몰리면 서버가 다운될 수 있습니다. 이 글에서는 트래픽 급증에 대비하는 스케일링 전략을 안내합니다.</p>

<h2 id="서버-한계-파악하기">서버 한계 파악하기</h2>

<p>스케일링 전략을 세우기 전에 현재 서버의 병목 지점을 파악해야 합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># CPU 사용률 확인</span>
top
htop

<span class="c"># 메모리 사용률 확인</span>
free <span class="nt">-h</span>

<span class="c"># 디스크 I/O 확인</span>
iostat <span class="nt">-x</span> 1

<span class="c"># 네트워크 트래픽 확인</span>
iftop
nethogs

<span class="c"># Nginx 접속 수 확인</span>
nginx <span class="nt">-V</span> 2&gt;&amp;1 | <span class="nb">grep</span> <span class="nt">-o</span> with-http_stub_status_module
curl http://localhost/nginx_status
</code></pre></div></div>

<hr />

<h2 id="전략-1-수직-확장-scale-up">전략 1: 수직 확장 (Scale Up)</h2>

<p>현재 서버의 리소스를 늘리는 가장 간단한 방법입니다.</p>

<ul>
  <li><strong>VPS 업그레이드</strong>: 더 높은 vCore, RAM 플랜으로 변경</li>
  <li><strong>전용서버 업그레이드</strong>: 더 높은 사양의 전용서버로 이전</li>
</ul>

<p>장점: 설정 변경 없이 즉시 성능 향상
단점: 물리적 한계 존재, 비용 증가, 업그레이드 시 재시작 필요</p>

<p>TCP-80.NET은 서버 업그레이드 문의를 텔레그램으로 빠르게 처리합니다.</p>

<hr />

<h2 id="전략-2-캐시-최적화-가장-효과적">전략 2: 캐시 최적화 (가장 효과적)</h2>

<p>서버를 업그레이드하기 전에 캐시를 잘 활용하면 동일한 서버에서 몇 배 더 많은 트래픽을 처리할 수 있습니다.</p>

<h3 id="nginx-fastcgi-캐시-php-서비스">Nginx FastCGI 캐시 (PHP 서비스)</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">http</span> <span class="p">{</span>
    <span class="kn">fastcgi_cache_path</span> <span class="n">/tmp/nginx_cache</span>
        <span class="s">levels=1:2</span>
        <span class="s">keys_zone=MYAPP:100m</span>
        <span class="s">max_size=1g</span>
        <span class="s">inactive=60m</span>
        <span class="s">use_temp_path=off</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">fastcgi_cache_key</span> <span class="s">"</span><span class="nv">$scheme$request_method$host$request_uri</span><span class="s">"</span><span class="p">;</span>

    <span class="kn">location</span> <span class="p">~</span> <span class="sr">\.php$</span> <span class="p">{</span>
        <span class="kn">fastcgi_cache</span> <span class="s">MYAPP</span><span class="p">;</span>
        <span class="kn">fastcgi_cache_valid</span> <span class="mi">200</span> <span class="mi">60m</span><span class="p">;</span>
        <span class="kn">fastcgi_cache_bypass</span> <span class="nv">$skip_cache</span><span class="p">;</span>
        <span class="kn">fastcgi_no_cache</span> <span class="nv">$skip_cache</span><span class="p">;</span>

        <span class="kn">add_header</span> <span class="s">X-FastCGI-Cache</span> <span class="nv">$upstream_cache_status</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="redis-오브젝트-캐시">Redis 오브젝트 캐시</h3>

<p>데이터베이스 쿼리 결과를 Redis에 캐싱하면 DB 부하를 크게 줄입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>redis-server <span class="nt">-y</span>
</code></pre></div></div>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Nginx Proxy 캐시 (Node.js/Python 앱)</span>
<span class="k">proxy_cache_path</span> <span class="n">/tmp/proxy_cache</span> <span class="s">levels=1:2</span> <span class="s">keys_zone=PROXY:10m</span><span class="p">;</span>

<span class="k">location</span> <span class="n">/</span> <span class="p">{</span>
    <span class="kn">proxy_cache</span> <span class="s">PROXY</span><span class="p">;</span>
    <span class="kn">proxy_cache_valid</span> <span class="mi">200</span> <span class="mi">5m</span><span class="p">;</span>
    <span class="kn">proxy_pass</span> <span class="s">http://localhost:3000</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="전략-3-cdn-활용">전략 3: CDN 활용</h2>

<p>정적 파일(이미지, CSS, JS, 폰트)을 CDN에서 제공하면 서버 부하를 크게 줄일 수 있습니다. 일반적으로 웹 트래픽의 60~80%는 정적 파일 요청입니다.</p>

<h3 id="cloudflare-설정">Cloudflare 설정</h3>

<ol>
  <li>Cloudflare에 도메인 등록</li>
  <li>DNS를 Cloudflare로 변경</li>
  <li>캐싱 정책 설정:
    <ul>
      <li><strong>Browser Cache TTL</strong>: 1일 이상</li>
      <li><strong>Cache Level</strong>: Standard</li>
      <li><strong>Rocket Loader</strong>: JavaScript 비동기 로드</li>
    </ul>
  </li>
</ol>

<p>Cloudflare의 일본 PoP(도쿄 등)에서 정적 파일을 제공해 서버 부하를 줄이고 응답 속도를 높일 수 있습니다.</p>

<hr />

<h2 id="전략-4-nginx-연결-수-최적화">전략 4: Nginx 연결 수 최적화</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/nginx.conf</span>
<span class="k">worker_processes</span> <span class="s">auto</span><span class="p">;</span>  <span class="c1"># CPU 코어 수에 맞게 자동 설정</span>
<span class="k">worker_rlimit_nofile</span> <span class="mi">65535</span><span class="p">;</span>

<span class="k">events</span> <span class="p">{</span>
    <span class="kn">worker_connections</span> <span class="mi">4096</span><span class="p">;</span>
    <span class="kn">multi_accept</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">use</span> <span class="s">epoll</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">http</span> <span class="p">{</span>
    <span class="kn">keepalive_timeout</span> <span class="mi">30</span><span class="p">;</span>
    <span class="kn">keepalive_requests</span> <span class="mi">1000</span><span class="p">;</span>
    <span class="kn">client_body_timeout</span> <span class="mi">10</span><span class="p">;</span>
    <span class="kn">client_header_timeout</span> <span class="mi">10</span><span class="p">;</span>
    <span class="kn">send_timeout</span> <span class="mi">10</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="전략-5-데이터베이스-최적화">전략 5: 데이터베이스 최적화</h2>

<p>트래픽 급증 시 DB가 가장 먼저 병목이 됩니다.</p>

<h3 id="슬로우-쿼리-찾기">슬로우 쿼리 찾기</h3>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- MariaDB 슬로우 쿼리 로그 활성화</span>
<span class="k">SET</span> <span class="k">GLOBAL</span> <span class="n">slow_query_log</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">SET</span> <span class="k">GLOBAL</span> <span class="n">long_query_time</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="인덱스-최적화">인덱스 최적화</h3>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 자주 조회되는 컬럼에 인덱스 추가</span>
<span class="k">CREATE</span> <span class="k">INDEX</span> <span class="n">idx_user_email</span> <span class="k">ON</span> <span class="n">users</span><span class="p">(</span><span class="n">email</span><span class="p">);</span>
<span class="k">EXPLAIN</span> <span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">email</span> <span class="o">=</span> <span class="s1">'test@example.com'</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="read-replica-분리">Read Replica 분리</h3>

<p>읽기 쿼리가 많은 서비스는 별도 읽기 전용 DB 서버를 두어 부하를 분산합니다.</p>

<hr />

<h2 id="트래픽-급증-전-체크리스트">트래픽 급증 전 체크리스트</h2>

<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Nginx 설정 최적화 완료</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Redis 캐시 설정 완료</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />CDN 연동 완료</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />DB 인덱스 최적화 완료</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />모니터링 설정 (CPU/RAM/DB 알림)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />서버 업그레이드 옵션 확인</li>
</ul>

<hr />

<h2 id="마치며">마치며</h2>

<p>트래픽 급증은 좋은 신호이지만, 대비가 없으면 서비스 장애로 이어집니다. 먼저 캐시 최적화로 최대한 버티고, 필요하면 서버 업그레이드를 진행하세요. TCP-80.NET은 긴급 업그레이드와 기술 지원을 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 신속하게 처리합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅에서 트래픽 급증 상황을 대비하는 방법을 안내합니다. 수직 확장, 수평 확장, 캐시 최적화, CDN 활용까지 실전 스케일링 전략을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 백업 전략 완전 가이드 — 데이터 손실 없는 안전한 운영</title><link href="https://tcp-80.net/blog/2026/01/19/japan-server-backup-strategy/" rel="alternate" type="text/html" title="일본 서버 백업 전략 완전 가이드 — 데이터 손실 없는 안전한 운영" /><published>2026-01-19T00:00:00+09:00</published><updated>2026-01-19T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/01/19/japan-server-backup-strategy</id><content type="html" xml:base="https://tcp-80.net/blog/2026/01/19/japan-server-backup-strategy/"><![CDATA[<p>일본 서버호스팅으로 서비스를 운영할 때 백업은 가장 중요하면서도 가장 쉽게 놓치는 부분입니다. 하드웨어 장애, 랜섬웨어, 실수로 인한 파일 삭제 등 예상치 못한 상황에서 백업이 없으면 데이터를 복구할 수 없습니다. 이 글에서는 일본 서버의 체계적인 백업 전략을 안내합니다.</p>

<h2 id="백업의-3-2-1-원칙">백업의 3-2-1 원칙</h2>

<p>전문적인 백업 전략의 기본 원칙:</p>
<ul>
  <li><strong>3개 복사본</strong>: 원본 포함 3개의 데이터 복사본 유지</li>
  <li><strong>2가지 저장 매체</strong>: 서로 다른 유형의 저장소에 저장</li>
  <li><strong>1개 원격 저장</strong>: 최소 1개는 오프사이트(원격 위치)에 저장</li>
</ul>

<hr />

<h2 id="1-데이터베이스-백업">1. 데이터베이스 백업</h2>

<h3 id="mysql--mariadb-백업">MySQL / MariaDB 백업</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /usr/local/bin/backup-db.sh</span>

<span class="nv">DATE</span><span class="o">=</span><span class="si">$(</span><span class="nb">date</span> +%Y%m%d_%H%M%S<span class="si">)</span>
<span class="nv">BACKUP_DIR</span><span class="o">=</span><span class="s2">"/backup/db"</span>
<span class="nv">DB_NAME</span><span class="o">=</span><span class="s2">"myapp"</span>
<span class="nv">DB_USER</span><span class="o">=</span><span class="s2">"root"</span>
<span class="nv">DB_PASS</span><span class="o">=</span><span class="s2">"패스워드"</span>

<span class="nb">mkdir</span> <span class="nt">-p</span> <span class="nv">$BACKUP_DIR</span>

<span class="c"># 전체 데이터베이스 백업</span>
mysqldump <span class="nt">-u</span> <span class="nv">$DB_USER</span> <span class="nt">-p</span><span class="nv">$DB_PASS</span> <span class="se">\</span>
  <span class="nt">--single-transaction</span> <span class="se">\</span>
  <span class="nt">--quick</span> <span class="se">\</span>
  <span class="nt">--lock-tables</span><span class="o">=</span><span class="nb">false</span> <span class="se">\</span>
  <span class="nv">$DB_NAME</span> | <span class="nb">gzip</span> <span class="o">&gt;</span> <span class="nv">$BACKUP_DIR</span>/<span class="k">${</span><span class="nv">DB_NAME</span><span class="k">}</span>_<span class="k">${</span><span class="nv">DATE</span><span class="k">}</span>.sql.gz

<span class="c"># 30일 이상 된 백업 삭제</span>
find <span class="nv">$BACKUP_DIR</span> <span class="nt">-name</span> <span class="s2">"*.sql.gz"</span> <span class="nt">-mtime</span> +30 <span class="nt">-delete</span>

<span class="nb">echo</span> <span class="s2">"DB 백업 완료: </span><span class="k">${</span><span class="nv">DB_NAME</span><span class="k">}</span><span class="s2">_</span><span class="k">${</span><span class="nv">DATE</span><span class="k">}</span><span class="s2">.sql.gz"</span>
</code></pre></div></div>

<h3 id="postgresql-백업">PostgreSQL 백업</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> <span class="nt">-u</span> postgres pg_dump myapp | <span class="nb">gzip</span> <span class="o">&gt;</span> /backup/db/myapp_<span class="si">$(</span><span class="nb">date</span> +%Y%m%d<span class="si">)</span>.sql.gz
</code></pre></div></div>

<hr />

<h2 id="2-파일-백업-웹-루트-업로드-파일">2. 파일 백업 (웹 루트, 업로드 파일)</h2>

<h3 id="rsync를-이용한-로컬-백업">rsync를 이용한 로컬 백업</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># 웹 루트 백업</span>
rsync <span class="nt">-avz</span> <span class="nt">--delete</span> <span class="se">\</span>
  /var/www/html/ <span class="se">\</span>
  /backup/www/

<span class="c"># 업로드 파일 백업</span>
rsync <span class="nt">-avz</span> <span class="se">\</span>
  /var/www/html/uploads/ <span class="se">\</span>
  /backup/uploads/
</code></pre></div></div>

<h3 id="증분-백업-rsync--날짜-디렉토리">증분 백업 (rsync + 날짜 디렉토리)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">DATE</span><span class="o">=</span><span class="si">$(</span><span class="nb">date</span> +%Y%m%d<span class="si">)</span>
<span class="nv">YESTERDAY</span><span class="o">=</span><span class="si">$(</span><span class="nb">date</span> <span class="nt">-d</span> <span class="s2">"yesterday"</span> +%Y%m%d<span class="si">)</span>

rsync <span class="nt">-avz</span> <span class="nt">--delete</span> <span class="se">\</span>
  <span class="nt">--link-dest</span><span class="o">=</span>/backup/www/<span class="nv">$YESTERDAY</span> <span class="se">\</span>
  /var/www/html/ <span class="se">\</span>
  /backup/www/<span class="nv">$DATE</span>/
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">--link-dest</code> 옵션으로 변경된 파일만 새로 복사하고 나머지는 하드링크로 처리해 저장 공간을 절약합니다.</p>

<hr />

<h2 id="3-원격-백업-오프사이트">3. 원격 백업 (오프사이트)</h2>

<p>로컬 백업만으로는 서버 전체 장애나 데이터센터 문제 시 복구가 불가능합니다. 원격 위치에 추가 백업을 저장하세요.</p>

<h3 id="aws-s3-또는-호환-오브젝트-스토리지-업로드">AWS S3 또는 호환 오브젝트 스토리지 업로드</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>awscli <span class="nt">-y</span>
aws configure  <span class="c"># AWS 자격 증명 설정</span>

<span class="c"># S3에 업로드</span>
aws s3 <span class="nb">cp</span> /backup/db/ s3://my-backup-bucket/db/ <span class="nt">--recursive</span>
aws s3 <span class="nb">cp</span> /backup/www/ s3://my-backup-bucket/www/ <span class="nt">--recursive</span>
</code></pre></div></div>

<h3 id="rclone을-이용한-다양한-클라우드-업로드">rclone을 이용한 다양한 클라우드 업로드</h3>

<p>rclone은 AWS S3, Google Cloud Storage, Backblaze B2 등 다양한 클라우드 스토리지를 지원합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>rclone <span class="nt">-y</span>
rclone config  <span class="c"># 클라우드 스토리지 설정</span>

<span class="c"># 백업 업로드</span>
rclone copy /backup/db remote:my-backup/db
</code></pre></div></div>

<hr />

<h2 id="4-자동-백업-스케줄-설정">4. 자동 백업 스케줄 설정</h2>

<h3 id="crontab으로-자동화">crontab으로 자동화</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>crontab <span class="nt">-e</span>
</code></pre></div></div>

<pre><code class="language-cron"># 매일 새벽 2시 DB 백업
0 2 * * * /usr/local/bin/backup-db.sh &gt;&gt; /var/log/backup.log 2&gt;&amp;1

# 매일 새벽 3시 파일 백업
0 3 * * * rsync -avz /var/www/html/ /backup/www/ &gt;&gt; /var/log/backup.log 2&gt;&amp;1

# 매일 새벽 4시 원격 백업 (S3)
0 4 * * * aws s3 sync /backup/ s3://my-backup-bucket/ &gt;&gt; /var/log/backup.log 2&gt;&amp;1

# 매주 일요일 전체 DB 덤프
0 1 * * 0 mysqldump -u root myapp | gzip &gt; /backup/weekly/myapp_$(date +\%Y\%m\%d).sql.gz
</code></pre>

<hr />

<h2 id="5-백업-복구-테스트">5. 백업 복구 테스트</h2>

<p>백업은 복구가 가능해야 의미가 있습니다. 정기적으로 복구 테스트를 실시하세요.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># DB 복구 테스트 (테스트 DB에서 수행)</span>
<span class="nb">gunzip</span> <span class="nt">-c</span> /backup/db/myapp_20260119.sql.gz | mysql <span class="nt">-u</span> root test_restore

<span class="c"># 파일 복구 테스트</span>
rsync <span class="nt">-avz</span> /backup/www/ /tmp/restore_test/
</code></pre></div></div>

<hr />

<h2 id="백업-용량-계획">백업 용량 계획</h2>

<table>
  <thead>
    <tr>
      <th>데이터 유형</th>
      <th>백업 주기</th>
      <th>보관 기간</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>데이터베이스</td>
      <td>매일</td>
      <td>30일</td>
    </tr>
    <tr>
      <td>웹 파일</td>
      <td>매일</td>
      <td>14일</td>
    </tr>
    <tr>
      <td>사용자 업로드</td>
      <td>매일</td>
      <td>30일</td>
    </tr>
    <tr>
      <td>주간 전체 백업</td>
      <td>매주</td>
      <td>3개월</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버 운영에서 백업은 비용이 아니라 보험입니다. 백업 없이 운영하다가 장애가 발생하면 복구 비용이 훨씬 크게 발생합니다. 오늘 바로 백업 자동화를 설정하세요. 백업 설정이나 스토리지 구성에 대한 문의는 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅에서 데이터를 안전하게 보호하기 위한 백업 전략을 안내합니다. 데이터베이스 백업, 파일 백업, 원격 백업, 자동화 설정까지 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 SSL 인증서 설정 완전 가이드 — Let’s Encrypt 무료 인증서부터 와일드카드까지</title><link href="https://tcp-80.net/blog/2026/01/05/japan-server-ssl-guide/" rel="alternate" type="text/html" title="일본 서버 SSL 인증서 설정 완전 가이드 — Let’s Encrypt 무료 인증서부터 와일드카드까지" /><published>2026-01-05T00:00:00+09:00</published><updated>2026-01-05T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2026/01/05/japan-server-ssl-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2026/01/05/japan-server-ssl-guide/"><![CDATA[<p>일본 서버에서 웹 서비스를 운영할 때 SSL 인증서는 필수입니다. HTTPS가 없으면 브라우저에서 “안전하지 않음” 경고를 표시하고, 구글 검색 순위에도 불이익이 생깁니다. 이 글에서는 일본 서버(Ubuntu + Nginx 기준)에서 SSL 인증서를 설정하는 방법을 안내합니다.</p>

<h2 id="ssl-인증서가-필요한-이유">SSL 인증서가 필요한 이유</h2>

<ol>
  <li><strong>보안</strong>: 클라이언트와 서버 간 통신 암호화</li>
  <li><strong>SEO</strong>: 구글은 HTTPS 사이트를 검색 순위에서 우대</li>
  <li><strong>신뢰성</strong>: 브라우저 주소창의 자물쇠 아이콘</li>
  <li><strong>필수 요건</strong>: 결제 페이지, 로그인 페이지는 HTTPS 필수</li>
</ol>

<hr />

<h2 id="lets-encrypt-무료-ssl-인증서">Let’s Encrypt 무료 SSL 인증서</h2>

<p>Let’s Encrypt는 비영리 인증기관(CA)에서 제공하는 무료 SSL 인증서로, 90일마다 자동 갱신이 가능합니다. 상업용 유료 인증서와 동일한 수준의 보안을 제공합니다.</p>

<h3 id="certbot-설치">Certbot 설치</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>certbot python3-certbot-nginx <span class="nt">-y</span>
</code></pre></div></div>

<h3 id="단일-도메인-인증서-발급">단일 도메인 인증서 발급</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>certbot <span class="nt">--nginx</span> <span class="nt">-d</span> yourdomain.com <span class="nt">-d</span> www.yourdomain.com
</code></pre></div></div>

<p>Certbot이 자동으로:</p>
<ol>
  <li>도메인 소유권 확인 (Let’s Encrypt ACME 챌린지)</li>
  <li>인증서 발급</li>
  <li>Nginx 설정에 SSL 추가</li>
  <li>HTTP → HTTPS 리다이렉트 설정</li>
</ol>

<hr />

<h2 id="nginx-ssl-설정-최적화">Nginx SSL 설정 최적화</h2>

<p>Certbot이 자동으로 설정하지만, 보안 강도를 높이려면 다음 설정을 추가합니다:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span> <span class="s">http2</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">yourdomain.com</span><span class="p">;</span>

    <span class="c1"># 인증서 경로 (Certbot이 자동 설정)</span>
    <span class="kn">ssl_certificate</span> <span class="n">/etc/letsencrypt/live/yourdomain.com/fullchain.pem</span><span class="p">;</span>
    <span class="kn">ssl_certificate_key</span> <span class="n">/etc/letsencrypt/live/yourdomain.com/privkey.pem</span><span class="p">;</span>

    <span class="c1"># 강화된 SSL 설정</span>
    <span class="kn">ssl_protocols</span> <span class="s">TLSv1.2</span> <span class="s">TLSv1.3</span><span class="p">;</span>
    <span class="kn">ssl_ciphers</span> <span class="s">ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384</span><span class="p">;</span>
    <span class="kn">ssl_prefer_server_ciphers</span> <span class="no">off</span><span class="p">;</span>

    <span class="c1"># HSTS (HTTPS 강제)</span>
    <span class="kn">add_header</span> <span class="s">Strict-Transport-Security</span> <span class="s">"max-age=31536000</span><span class="p">;</span> <span class="kn">includeSubDomains"</span> <span class="s">always</span><span class="p">;</span>

    <span class="c1"># OCSP Stapling (인증서 검증 속도 향상)</span>
    <span class="kn">ssl_stapling</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">ssl_stapling_verify</span> <span class="no">on</span><span class="p">;</span>

    <span class="c1"># 세션 캐시 (TLS 핸드셰이크 재사용)</span>
    <span class="kn">ssl_session_cache</span> <span class="s">shared:SSL:10m</span><span class="p">;</span>
    <span class="kn">ssl_session_timeout</span> <span class="s">1d</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1"># HTTP → HTTPS 리다이렉트</span>
<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">yourdomain.com</span> <span class="s">www.yourdomain.com</span><span class="p">;</span>
    <span class="kn">return</span> <span class="mi">301</span> <span class="s">https://</span><span class="nv">$host$request_uri</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="와일드카드-ssl-인증서-yourdomaincom">와일드카드 SSL 인증서 (*.yourdomain.com)</h2>

<p>서브도메인이 여러 개인 경우(api.yourdomain.com, shop.yourdomain.com 등) 와일드카드 인증서 하나로 모두 커버할 수 있습니다.</p>

<p>와일드카드 인증서는 DNS TXT 레코드 챌린지 방식으로 발급합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>certbot certonly <span class="nt">--manual</span> <span class="nt">--preferred-challenges</span> dns <span class="se">\</span>
  <span class="nt">-d</span> yourdomain.com <span class="se">\</span>
  <span class="nt">-d</span> <span class="s2">"*.yourdomain.com"</span>
</code></pre></div></div>

<p>발급 과정에서 DNS 제공업체에서 TXT 레코드를 추가하라는 안내가 나옵니다. 추가 후 Enter를 누르면 인증서가 발급됩니다.</p>

<hr />

<h2 id="ssl-인증서-자동-갱신">SSL 인증서 자동 갱신</h2>

<p>Let’s Encrypt 인증서는 90일마다 갱신이 필요합니다. Certbot이 자동 갱신 타이머를 등록하지만, 정상 동작하는지 확인하세요:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 갱신 테스트 (실제로 갱신하지 않음)</span>
certbot renew <span class="nt">--dry-run</span>

<span class="c"># 갱신 타이머 상태 확인</span>
systemctl status certbot.timer
</code></pre></div></div>

<p>수동 갱신이 필요한 경우:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>certbot renew
systemctl reload nginx
</code></pre></div></div>

<p>crontab으로 추가 자동화:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># crontab -e</span>
0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> certbot renew <span class="nt">--quiet</span> <span class="o">&amp;&amp;</span> systemctl reload nginx
</code></pre></div></div>

<hr />

<h2 id="ssl-인증서-설정-확인">SSL 인증서 설정 확인</h2>

<p>설정이 완료되면 다음 도구로 검증하세요:</p>

<ul>
  <li><strong>SSL Labs</strong>: <code class="language-plaintext highlighter-rouge">https://www.ssllabs.com/ssltest/</code> — A+ 등급 목표</li>
  <li><strong>명령줄 테스트</strong>:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-I</span> https://yourdomain.com
openssl s_client <span class="nt">-connect</span> yourdomain.com:443 <span class="nt">-brief</span>
</code></pre></div>    </div>
  </li>
</ul>

<hr />

<h2 id="자주-발생하는-오류와-해결법">자주 발생하는 오류와 해결법</h2>

<table>
  <thead>
    <tr>
      <th>오류</th>
      <th>원인</th>
      <th>해결법</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ACME challenge failed</code></td>
      <td>포트 80 차단</td>
      <td>UFW에서 80 포트 허용 확인</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Certificate has expired</code></td>
      <td>자동 갱신 실패</td>
      <td><code class="language-plaintext highlighter-rouge">certbot renew</code> 수동 실행</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SSL_ERROR_RX_RECORD_TOO_LONG</code></td>
      <td>HTTP 포트에 HTTPS 연결</td>
      <td>Nginx 포트 설정 확인</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버에 SSL을 설정하면 보안과 SEO 두 가지를 동시에 챙길 수 있습니다. SSL 설정 과정에서 어려움이 있으시면 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅에서 SSL 인증서를 설정하는 방법을 단계별로 안내합니다. Let's Encrypt 무료 인증서, 와일드카드 인증서, 자동 갱신 설정까지 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 가상 데스크톱(RDP) 완전 활용 가이드 — 용도와 설정 방법</title><link href="https://tcp-80.net/blog/2025/12/22/japan-virtual-desktop-guide/" rel="alternate" type="text/html" title="일본 가상 데스크톱(RDP) 완전 활용 가이드 — 용도와 설정 방법" /><published>2025-12-22T00:00:00+09:00</published><updated>2025-12-22T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/12/22/japan-virtual-desktop-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2025/12/22/japan-virtual-desktop-guide/"><![CDATA[<p>일본 가상 데스크톱(Virtual Desktop)은 일본 도쿄 데이터센터에 위치한 Windows 서버를 원격으로 사용하는 서비스입니다. RDP(Remote Desktop Protocol)로 접속하면 일본 IP를 가진 Windows PC를 원격으로 사용하는 것과 동일한 환경을 이용할 수 있습니다.</p>

<h2 id="일본-가상-데스크톱이란">일본 가상 데스크톱이란?</h2>

<p>일본 데이터센터의 Windows Server에 RDP로 접속해 마치 내 PC처럼 사용하는 서비스입니다. 특징:</p>
<ul>
  <li><strong>일본 IP 주소</strong>: 일본 현지 서비스 이용 가능</li>
  <li><strong>Windows GUI 환경</strong>: 브라우저, 오피스 소프트웨어 등 모든 Windows 앱 사용</li>
  <li><strong>24시간 상시 운영</strong>: 내 PC를 끄더라도 서버는 계속 실행</li>
  <li><strong>원격 접속</strong>: 어디서든 인터넷만 있으면 접속 가능</li>
</ul>

<hr />

<h2 id="주요-활용-사례">주요 활용 사례</h2>

<h3 id="1-일본-인터넷-뱅킹">1. 일본 인터넷 뱅킹</h3>

<p>일본 은행(UFJ, 스미토모, 유초은행 등)은 해외 IP 접속 시 추가 인증이나 접속 제한이 생기는 경우가 있습니다. 일본 가상 데스크톱을 통해 접속하면 일본 IP로 인식돼 정상적으로 이용할 수 있습니다.</p>

<h3 id="2-일본-이커머스-관리">2. 일본 이커머스 관리</h3>

<p>Amazon.co.jp, 라쿠텐, 야후쇼핑 등 일본 이커머스 셀러 계정을 안전하게 관리할 수 있습니다. 해외 IP 접속으로 인한 계정 보안 경보를 방지합니다.</p>

<h3 id="3-일본-마케팅광고-운영">3. 일본 마케팅·광고 운영</h3>

<p>Yahoo! Japan 광고, 일본 SNS 마케팅 계정을 일본 IP로 운영해 계정 정지 리스크를 줄입니다.</p>

<h3 id="4-24시간-자동화-작업">4. 24시간 자동화 작업</h3>

<p>가상 데스크톱에서 매크로, 크롤러, 자동화 스크립트를 24시간 실행할 수 있습니다. 내 PC가 꺼져 있어도 서버에서 계속 작동합니다.</p>

<h3 id="5-일본-소프트웨어앱-사용">5. 일본 소프트웨어·앱 사용</h3>

<p>일본 한정으로 출시된 소프트웨어나 앱을 일본 환경에서 사용할 수 있습니다.</p>

<hr />

<h2 id="rdp-접속-방법">RDP 접속 방법</h2>

<h3 id="windows에서-접속">Windows에서 접속</h3>

<ol>
  <li><strong>시작</strong> → <strong>원격 데스크톱 연결</strong> 실행</li>
  <li>컴퓨터 항목에 서버 IP 입력</li>
  <li>사용자 이름과 비밀번호 입력</li>
  <li>연결</li>
</ol>

<p>또는 <code class="language-plaintext highlighter-rouge">Win + R</code> → <code class="language-plaintext highlighter-rouge">mstsc</code> 실행</p>

<h3 id="macos에서-접속">macOS에서 접속</h3>

<p>App Store에서 <strong>Microsoft Remote Desktop</strong> 앱을 설치 후:</p>
<ol>
  <li>앱 실행 → Add PC</li>
  <li>PC name에 서버 IP 입력</li>
  <li>사용자 계정 설정</li>
  <li>연결</li>
</ol>

<h3 id="모바일iosandroid에서-접속">모바일(iOS/Android)에서 접속</h3>

<p><strong>Microsoft Remote Desktop</strong> 앱을 설치 후 동일하게 연결 가능합니다. 스마트폰에서도 일본 가상 데스크톱을 이용할 수 있습니다.</p>

<hr />

<h2 id="rdp-보안-설정">RDP 보안 설정</h2>

<p>가상 데스크톱은 인터넷에 직접 노출되는 RDP 포트(기본 3389)를 사용하므로 보안 설정이 중요합니다.</p>

<h3 id="접속-ip-제한">접속 IP 제한</h3>

<p>가능하면 내 IP에서만 RDP 접속을 허용하도록 방화벽을 설정하세요:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Windows Defender 방화벽 → 인바운드 규칙 → 원격 데스크톱 → 원격 IP 주소 제한
</code></pre></div></div>

<h3 id="강력한-비밀번호-사용">강력한 비밀번호 사용</h3>

<p>Windows 계정 비밀번호는 반드시 영문 대소문자 + 숫자 + 특수문자 조합 12자 이상으로 설정하세요.</p>

<h3 id="rdp-포트-변경">RDP 포트 변경</h3>

<p>기본 3389 포트 대신 다른 포트로 변경하면 자동화 공격을 줄일 수 있습니다:</p>

<p>레지스트리 편집기 → <code class="language-plaintext highlighter-rouge">HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp</code> → <code class="language-plaintext highlighter-rouge">PortNumber</code> 변경</p>

<hr />

<h2 id="tcp-80net-일본-가상-데스크톱">TCP-80.NET 일본 가상 데스크톱</h2>

<ul>
  <li><a href="/virtual-desktop/">가상 데스크톱 서비스 안내</a></li>
  <li>월 ₩150,000부터 시작</li>
  <li>Windows Server 환경, 일본 도쿄 IP</li>
  <li>24시간 한국어 지원</li>
</ul>

<p>서비스 문의는 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 주세요.</p>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 가상 데스크톱은 일본 IP 주소가 필요한 다양한 업무에 활용할 수 있는 편리한 서비스입니다. 일본 인터넷 뱅킹부터 24시간 자동화 작업까지, 용도에 맞게 사용해보세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 가상 데스크톱(RDP) 서비스의 활용 방법과 접속 설정을 안내합니다. 일본 인터넷 뱅킹, 마케팅 운영, 업무 자동화 등 다양한 사용 사례를 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본서버 가격 비교 2025 — 일본서버호스팅 VPS·전용서버 선택 가이드</title><link href="https://tcp-80.net/blog/2025/12/08/japan-server-vps-price-guide/" rel="alternate" type="text/html" title="일본서버 가격 비교 2025 — 일본서버호스팅 VPS·전용서버 선택 가이드" /><published>2025-12-08T00:00:00+09:00</published><updated>2025-12-08T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/12/08/japan-server-vps-price-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2025/12/08/japan-server-vps-price-guide/"><![CDATA[<p>일본서버호스팅을 처음 알아볼 때 가장 많이 하는 질문이 “얼마짜리를 써야 하나요?”입니다. 스펙과 가격이 다양해서 처음에는 헷갈리기 쉽습니다. 이 글에서 2025년 기준 일본서버 가격대와 용도별 선택 기준을 정리합니다.</p>

<h2 id="일본서버-유형별-가격-범위">일본서버 유형별 가격 범위</h2>

<h3 id="일본-vps-가격">일본 VPS 가격</h3>

<p>일본 VPS는 가상화 기술로 물리 서버를 분할한 서버 환경입니다. 독립적인 OS 환경에서 자유롭게 서버를 운영할 수 있습니다.</p>

<table>
  <thead>
    <tr>
      <th>vCore</th>
      <th>RAM</th>
      <th>스토리지</th>
      <th>월 가격 (참고)</th>
      <th>적합한 용도</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1 vCore</td>
      <td>2~4GB</td>
      <td>50~100GB SSD</td>
      <td>₩100,000~</td>
      <td>소규모 웹, 블로그, 개발 서버</td>
    </tr>
    <tr>
      <td>2 vCore</td>
      <td>4~8GB</td>
      <td>100~200GB SSD</td>
      <td>₩150,000~200,000</td>
      <td>중규모 웹서비스, API 서버</td>
    </tr>
    <tr>
      <td>4 vCore</td>
      <td>8~12GB</td>
      <td>200~400GB SSD</td>
      <td>₩200,000~350,000</td>
      <td>대규모 웹서비스, 게임서버</td>
    </tr>
  </tbody>
</table>

<p>TCP-80.NET <a href="/virtual-server/">일본 VPS</a>는 1 vCore부터 4 vCore까지 4개 플랜으로 제공됩니다.</p>

<h3 id="일본-전용서버-가격">일본 전용서버 가격</h3>

<p>전용서버는 물리 서버 전체를 단독으로 사용하는 방식입니다. 리소스 경합이 없어 성능이 안정적입니다.</p>

<table>
  <thead>
    <tr>
      <th>CPU</th>
      <th>RAM</th>
      <th>스토리지</th>
      <th>월 가격 (참고)</th>
      <th>적합한 용도</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Xeon 4코어</td>
      <td>16GB</td>
      <td>1TB HDD</td>
      <td>₩300,000~</td>
      <td>중규모 서비스, 소규모 게임서버</td>
    </tr>
    <tr>
      <td>Xeon 8코어</td>
      <td>32GB</td>
      <td>2TB HDD</td>
      <td>₩500,000~</td>
      <td>대규모 DB, 게임서버</td>
    </tr>
    <tr>
      <td>Xeon 12코어+</td>
      <td>64GB+</td>
      <td>2TB+</td>
      <td>₩800,000~</td>
      <td>엔터프라이즈, 대규모 게임</td>
    </tr>
  </tbody>
</table>

<p>TCP-80.NET <a href="/dedicated-server/">일본 전용서버</a>는 Eco부터 High-End까지 5개 플랜을 운영합니다.</p>

<h3 id="일본-가상-데스크톱-가격">일본 가상 데스크톱 가격</h3>

<p>일본 IP 기반 Windows 환경이 필요한 경우 사용합니다.</p>

<ul>
  <li>기본형: 월 ₩150,000~</li>
  <li>고사양형: 월 ₩300,000~</li>
</ul>

<p><a href="/virtual-desktop/">일본 가상 데스크톱 자세히 보기</a></p>

<hr />

<h2 id="예산별-일본서버-추천">예산별 일본서버 추천</h2>

<h3 id="월-1015만-원대-입문자">월 10~15만 원대 (입문자)</h3>

<p>1 vCore VPS가 적합합니다. 소규모 웹사이트, 개인 프로젝트, 개발 테스트 서버에 충분합니다.</p>

<ul>
  <li>WordPress 사이트 운영 가능</li>
  <li>Node.js / Python Flask 소규모 API 서버</li>
  <li>개발 환경 구성</li>
</ul>

<h3 id="월-1530만-원대-중소규모-서비스">월 15~30만 원대 (중소규모 서비스)</h3>

<p>2~4 vCore VPS 또는 소규모 전용서버가 적합합니다.</p>

<ul>
  <li>중규모 쇼핑몰, 커뮤니티 서비스</li>
  <li>소규모 게임서버 (Minecraft, 소규모 FPS)</li>
  <li>데이터베이스 서버 분리 운영</li>
</ul>

<h3 id="월-30만-원-이상-상업용-서비스">월 30만 원 이상 (상업용 서비스)</h3>

<p>전용서버가 필요합니다. 리소스를 완전히 독점해 안정적인 성능을 보장합니다.</p>

<ul>
  <li>대규모 트래픽 웹 서비스</li>
  <li>MMORPG, FPS 게임서버</li>
  <li>고가용성 DB 클러스터</li>
  <li>스트리밍 서버</li>
</ul>

<hr />

<h2 id="일본서버호스팅-가격-외에-확인해야-할-것">일본서버호스팅 가격 외에 확인해야 할 것</h2>

<p>가격만 보고 결정하면 나중에 후회할 수 있습니다. 다음 항목도 반드시 확인하세요.</p>

<h3 id="1-ddos-방어-포함-여부">1. DDoS 방어 포함 여부</h3>

<p>일본서버는 DDoS 공격의 표적이 되기 쉽습니다. 기본 DDoS 방어가 포함되어 있는지, 아니면 추가 비용이 드는지 확인하세요.</p>

<p>TCP-80.NET은 <strong>모든 플랜에 L3/L4 DDoS 방어 무료 제공</strong>합니다.</p>

<h3 id="2-트래픽대역폭-정책">2. 트래픽(대역폭) 정책</h3>

<p>트래픽 한도가 있는지, 초과 시 추가 요금이 발생하는지 확인하세요. 일부 업체는 저렴한 가격을 내세우지만 트래픽 초과 비용이 상당합니다.</p>

<h3 id="3-환불-정책">3. 환불 정책</h3>

<p>서비스 품질이 기대에 미치지 못할 경우를 대비해 환불 정책이 있는지 확인하세요.</p>

<p>TCP-80.NET은 <strong>7일 전액 환불을 보장</strong>합니다.</p>

<h3 id="4-한국어-지원">4. 한국어 지원</h3>

<p>장애 발생 시 한국어로 즉시 소통 가능한지 확인하세요. 영어로만 지원하는 해외 업체는 장애 대응이 느릴 수 있습니다.</p>

<p>TCP-80.NET은 <strong>24시간 텔레그램 한국어 지원</strong>을 제공합니다.</p>

<hr />

<h2 id="일본서버호스팅-가격-대비-가치-체크리스트">일본서버호스팅 가격 대비 가치 체크리스트</h2>

<p>서버 비용이 합리적인지 판단하려면 아래 요소들을 종합해서 판단하세요.</p>

<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />스펙 대비 가격이 시장 평균 수준인가?</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />DDoS 방어가 포함되어 있는가?</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />한국어 지원이 가능한가?</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />환불 정책이 있는가?</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />OS 설치가 무료인가?</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />IPMI 접근이 가능한가? (전용서버)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />실제 일본 도쿄 IDC에 위치하는가?</li>
</ul>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본서버호스팅 가격은 VPS 기준 월 10만 원대부터 시작해 전용서버는 수십만 원까지 다양합니다. 중요한 것은 단순히 가격이 아니라 DDoS 방어, 지원 품질, 실제 서버 위치까지 종합적으로 판단하는 것입니다.</p>

<p>TCP-80.NET 일본서버 상담은 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 24시간 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본서버호스팅 가격이 궁금하다면? 2025년 기준 일본서버 VPS와 전용서버의 스펙별 가격대와 선택 기준을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 Docker 컨테이너 환경 구축 가이드</title><link href="https://tcp-80.net/blog/2025/11/24/japan-server-docker-guide/" rel="alternate" type="text/html" title="일본 서버 Docker 컨테이너 환경 구축 가이드" /><published>2025-11-24T00:00:00+09:00</published><updated>2025-11-24T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/11/24/japan-server-docker-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2025/11/24/japan-server-docker-guide/"><![CDATA[<p>일본 서버호스팅에 Docker를 활용하면 서비스 배포와 관리가 훨씬 편리해집니다. 컨테이너를 사용하면 개발 환경과 프로덕션 환경의 차이를 최소화하고, 여러 서비스를 하나의 서버에서 격리해 운영할 수 있습니다.</p>

<h2 id="docker가-일본-서버-운영에-유리한-이유">Docker가 일본 서버 운영에 유리한 이유</h2>

<ul>
  <li><strong>빠른 배포</strong>: 이미지 기반 배포로 서비스 교체 시간 단축</li>
  <li><strong>환경 격리</strong>: 여러 서비스가 하나의 서버에서 충돌 없이 공존</li>
  <li><strong>롤백 용이</strong>: 이전 버전 이미지로 즉시 복구</li>
  <li><strong>리소스 효율</strong>: VM보다 가볍게 격리된 환경 제공</li>
</ul>

<hr />

<h2 id="1단계-docker-설치-ubuntu-2204">1단계: Docker 설치 (Ubuntu 22.04)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 의존성 설치</span>
apt <span class="nb">install </span>ca-certificates curl gnupg <span class="nt">-y</span>

<span class="c"># Docker GPG 키 추가</span>
<span class="nb">install</span> <span class="nt">-m</span> 0755 <span class="nt">-d</span> /etc/apt/keyrings
curl <span class="nt">-fsSL</span> https://download.docker.com/linux/ubuntu/gpg | <span class="se">\</span>
  gpg <span class="nt">--dearmor</span> <span class="nt">-o</span> /etc/apt/keyrings/docker.gpg

<span class="c"># Docker 저장소 추가</span>
<span class="nb">echo</span> <span class="s2">"deb [arch=</span><span class="si">$(</span>dpkg <span class="nt">--print-architecture</span><span class="si">)</span><span class="s2"> signed-by=/etc/apt/keyrings/docker.gpg] </span><span class="se">\</span><span class="s2">
  https://download.docker.com/linux/ubuntu </span><span class="si">$(</span>lsb_release <span class="nt">-cs</span><span class="si">)</span><span class="s2"> stable"</span> | <span class="se">\</span>
  <span class="nb">tee</span> /etc/apt/sources.list.d/docker.list

<span class="c"># Docker 설치</span>
apt update
apt <span class="nb">install </span>docker-ce docker-ce-cli containerd.io docker-compose-plugin <span class="nt">-y</span>

<span class="c"># 버전 확인</span>
docker <span class="nt">--version</span>
docker compose version
</code></pre></div></div>

<p>일반 사용자에게 Docker 권한 부여:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>usermod <span class="nt">-aG</span> docker <span class="nv">$USER</span>
</code></pre></div></div>

<hr />

<h2 id="2단계-docker-compose-기본-구성">2단계: Docker Compose 기본 구성</h2>

<p>웹 서비스의 전형적인 구성(Nginx + App + DB + Redis)을 Docker Compose로 정의합니다.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># docker-compose.yml</span>
<span class="na">version</span><span class="pi">:</span> <span class="s1">'</span><span class="s">3.8'</span>

<span class="na">services</span><span class="pi">:</span>
  <span class="na">nginx</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">nginx:alpine</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">80:80"</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">443:443"</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">./nginx/conf.d:/etc/nginx/conf.d</span>
      <span class="pi">-</span> <span class="s">./certbot/www:/var/www/certbot</span>
      <span class="pi">-</span> <span class="s">./certbot/conf:/etc/letsencrypt</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">app</span>
    <span class="na">restart</span><span class="pi">:</span> <span class="s">always</span>

  <span class="na">app</span><span class="pi">:</span>
    <span class="na">build</span><span class="pi">:</span> <span class="s">./app</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">NODE_ENV=production</span>
      <span class="pi">-</span> <span class="s">DB_HOST=db</span>
      <span class="pi">-</span> <span class="s">REDIS_HOST=redis</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">db</span>
      <span class="pi">-</span> <span class="s">redis</span>
    <span class="na">restart</span><span class="pi">:</span> <span class="s">always</span>

  <span class="na">db</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">mariadb:10.11</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="na">MYSQL_ROOT_PASSWORD</span><span class="pi">:</span> <span class="s">${DB_ROOT_PASSWORD}</span>
      <span class="na">MYSQL_DATABASE</span><span class="pi">:</span> <span class="s">${DB_NAME}</span>
      <span class="na">MYSQL_USER</span><span class="pi">:</span> <span class="s">${DB_USER}</span>
      <span class="na">MYSQL_PASSWORD</span><span class="pi">:</span> <span class="s">${DB_PASSWORD}</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">db_data:/var/lib/mysql</span>
    <span class="na">restart</span><span class="pi">:</span> <span class="s">always</span>

  <span class="na">redis</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">redis:7-alpine</span>
    <span class="na">restart</span><span class="pi">:</span> <span class="s">always</span>

<span class="na">volumes</span><span class="pi">:</span>
  <span class="na">db_data</span><span class="pi">:</span>
</code></pre></div></div>

<p>환경 변수는 <code class="language-plaintext highlighter-rouge">.env</code> 파일에 관리:</p>

<pre><code class="language-env">DB_ROOT_PASSWORD=강력한패스워드
DB_NAME=myapp
DB_USER=myuser
DB_PASSWORD=사용자패스워드
</code></pre>

<hr />

<h2 id="3단계-서비스-시작-및-관리">3단계: 서비스 시작 및 관리</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 백그라운드 실행</span>
docker compose up <span class="nt">-d</span>

<span class="c"># 로그 확인</span>
docker compose logs <span class="nt">-f</span>

<span class="c"># 서비스 상태</span>
docker compose ps

<span class="c"># 서비스 재시작</span>
docker compose restart app

<span class="c"># 서비스 중지</span>
docker compose down
</code></pre></div></div>

<hr />

<h2 id="4단계-ssl-인증서-자동화-certbot--docker">4단계: SSL 인증서 자동화 (Certbot + Docker)</h2>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># docker-compose.yml에 추가</span>
  <span class="na">certbot</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">certbot/certbot</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">./certbot/www:/var/www/certbot</span>
      <span class="pi">-</span> <span class="s">./certbot/conf:/etc/letsencrypt</span>
    <span class="na">entrypoint</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/bin/sh</span><span class="nv"> </span><span class="s">-c</span><span class="nv"> </span><span class="s">'trap</span><span class="nv"> </span><span class="s">exit</span><span class="nv"> </span><span class="s">TERM;</span><span class="nv"> </span><span class="s">while</span><span class="nv"> </span><span class="s">:;</span><span class="nv"> </span><span class="s">do</span><span class="nv"> </span><span class="s">certbot</span><span class="nv"> </span><span class="s">renew;</span><span class="nv"> </span><span class="s">sleep</span><span class="nv"> </span><span class="s">12h</span><span class="nv"> </span><span class="s">&amp;</span><span class="nv"> </span><span class="s">wait</span><span class="nv"> </span><span class="s">$${!};</span><span class="nv"> </span><span class="s">done;'"</span>
</code></pre></div></div>

<p>최초 인증서 발급:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker compose run <span class="nt">--rm</span> certbot certonly <span class="nt">--webroot</span> <span class="se">\</span>
  <span class="nt">-w</span> /var/www/certbot <span class="se">\</span>
  <span class="nt">-d</span> yourdomain.com
</code></pre></div></div>

<hr />

<h2 id="5단계-컨테이너-이미지-업데이트-무중단-배포">5단계: 컨테이너 이미지 업데이트 (무중단 배포)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 새 이미지 빌드</span>
docker compose build app

<span class="c"># 롤링 업데이트</span>
docker compose up <span class="nt">-d</span> <span class="nt">--no-deps</span> app
</code></pre></div></div>

<hr />

<h2 id="일본-서버-docker-운영-팁">일본 서버 Docker 운영 팁</h2>

<h3 id="로그-크기-제한">로그 크기 제한</h3>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">services</span><span class="pi">:</span>
  <span class="na">app</span><span class="pi">:</span>
    <span class="na">logging</span><span class="pi">:</span>
      <span class="na">driver</span><span class="pi">:</span> <span class="s2">"</span><span class="s">json-file"</span>
      <span class="na">options</span><span class="pi">:</span>
        <span class="na">max-size</span><span class="pi">:</span> <span class="s2">"</span><span class="s">100m"</span>
        <span class="na">max-file</span><span class="pi">:</span> <span class="s2">"</span><span class="s">3"</span>
</code></pre></div></div>

<h3 id="자동-재시작">자동 재시작</h3>

<p><code class="language-plaintext highlighter-rouge">restart: always</code> 설정으로 컨테이너가 크래시되거나 서버가 재부팅되어도 자동으로 시작됩니다.</p>

<h3 id="볼륨-백업">볼륨 백업</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 데이터베이스 볼륨 백업</span>
docker <span class="nb">exec </span>db mysqldump <span class="nt">-u</span> root <span class="nt">-p</span> myapp | <span class="nb">gzip</span> <span class="o">&gt;</span> backup_<span class="si">$(</span><span class="nb">date</span> +%Y%m%d<span class="si">)</span>.sql.gz
</code></pre></div></div>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버에 Docker 환경을 구축하면 서비스 관리가 단순해지고 배포 속도가 빨라집니다. Docker 설치 및 설정에 어려움이 있으시면 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅에 Docker와 Docker Compose로 컨테이너 기반 서비스를 구축하는 방법을 안내합니다. Nginx, 앱 서버, 데이터베이스를 컨테이너로 운영하는 전체 구성을 다룹니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">싱가포르 서버호스팅 vs 일본 서버호스팅 — 한국 서비스에 맞는 선택은?</title><link href="https://tcp-80.net/blog/2025/11/17/singapore-server-hosting/" rel="alternate" type="text/html" title="싱가포르 서버호스팅 vs 일본 서버호스팅 — 한국 서비스에 맞는 선택은?" /><published>2025-11-17T00:00:00+09:00</published><updated>2025-11-17T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/11/17/singapore-server-hosting</id><content type="html" xml:base="https://tcp-80.net/blog/2025/11/17/singapore-server-hosting/"><![CDATA[<p>동남아시아 진출이나 글로벌 서비스를 위해 싱가포르 서버호스팅을 알아보는 분들이 늘고 있습니다. 싱가포르는 아시아 태평양 지역의 클라우드·IDC 허브로 자리 잡고 있습니다. 이 글에서는 싱가포르 서버와 일본 서버를 비교해 한국 서비스에 어떤 선택이 더 적합한지 정리합니다.</p>

<h2 id="싱가포르-서버호스팅의-특징">싱가포르 서버호스팅의 특징</h2>

<h3 id="동남아시아-it-허브">동남아시아 IT 허브</h3>

<p>싱가포르는 AWS, Google Cloud, Microsoft Azure 등 글로벌 클라우드 업체들이 아시아 태평양 리전 거점을 두는 핵심 도시입니다. Equinix SG, Global Switch, Keppel Data Centre 등 세계적 수준의 IDC가 집중되어 있습니다.</p>

<h3 id="싱가포르-서버-레이턴시">싱가포르 서버 레이턴시</h3>

<p>서울에서 싱가포르까지의 왕복 레이턴시는 <strong>70~100ms</strong> 수준입니다. 일본 도쿄(20~35ms)의 약 3배 수준입니다.</p>

<h3 id="법적-환경">법적 환경</h3>

<p>싱가포르는 영미법 기반의 안정적인 법체계를 갖추고 있으며, 기업 활동에 우호적인 환경으로 평가받습니다. 개인정보보호법(PDPA)도 체계적으로 운영됩니다.</p>

<hr />

<h2 id="싱가포르-서버가-적합한-경우">싱가포르 서버가 적합한 경우</h2>

<p>싱가포르 서버호스팅이 일본 서버보다 유리한 경우는 명확합니다.</p>

<h3 id="1-동남아시아-사용자-대상-서비스">1. 동남아시아 사용자 대상 서비스</h3>

<p>태국, 인도네시아, 말레이시아, 필리핀, 베트남 등 동남아 국가 사용자를 주요 타겟으로 하는 서비스라면 싱가포르 서버가 레이턴시 측면에서 유리합니다.</p>

<table>
  <thead>
    <tr>
      <th>지역</th>
      <th>싱가포르 레이턴시</th>
      <th>도쿄 레이턴시</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>방콕 (태국)</td>
      <td>~20ms</td>
      <td>~70ms</td>
    </tr>
    <tr>
      <td>자카르타 (인도네시아)</td>
      <td>~10ms</td>
      <td>~80ms</td>
    </tr>
    <tr>
      <td>쿠알라룸푸르 (말레이시아)</td>
      <td>~10ms</td>
      <td>~75ms</td>
    </tr>
    <tr>
      <td>마닐라 (필리핀)</td>
      <td>~30ms</td>
      <td>~45ms</td>
    </tr>
    <tr>
      <td>서울 (한국)</td>
      <td>70~100ms</td>
      <td>20~35ms</td>
    </tr>
  </tbody>
</table>

<h3 id="2-글로벌-cdn-및-분산-인프라">2. 글로벌 CDN 및 분산 인프라</h3>

<p>싱가포르는 주요 CDN 사업자의 동남아 POP(Point of Presence)가 집중된 지역입니다. 글로벌 분산 인프라를 구성할 때 동남아 노드로 활용하기 좋습니다.</p>

<h3 id="3-글로벌-saas-서비스">3. 글로벌 SaaS 서비스</h3>

<p>동남아를 포함한 아시아 태평양 전체를 커버하는 SaaS 서비스는 싱가포르 서버가 균형 잡힌 레이턴시를 제공합니다.</p>

<hr />

<h2 id="싱가포르-서버-vs-일본-서버-비교">싱가포르 서버 vs 일본 서버 비교</h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>싱가포르 서버</th>
      <th>일본 도쿄 서버</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>서울 레이턴시</td>
      <td>70~100ms</td>
      <td>20~35ms</td>
    </tr>
    <tr>
      <td>동남아 레이턴시</td>
      <td>10~30ms</td>
      <td>60~90ms</td>
    </tr>
    <tr>
      <td>법적 안정성</td>
      <td>우수</td>
      <td>우수</td>
    </tr>
    <tr>
      <td>한국어 지원 업체</td>
      <td>드묾</td>
      <td>TCP-80.NET 가능</td>
    </tr>
    <tr>
      <td>가격 수준</td>
      <td>보통~높음</td>
      <td>합리적</td>
    </tr>
    <tr>
      <td>중화권 접근성</td>
      <td>보통</td>
      <td>보통</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="한국-서비스라면-일본-서버가-압도적으로-유리">한국 서비스라면 일본 서버가 압도적으로 유리</h2>

<p>한국 사용자가 주요 타겟이거나, 한국에서 서비스를 관리하는 경우라면 싱가포르 서버보다 <strong>일본 도쿄 서버</strong>가 훨씬 나은 선택입니다.</p>

<p><strong>이유:</strong></p>
<ul>
  <li>서울~도쿄 레이턴시(20~35ms)는 서울~싱가포르(70~100ms)의 <strong>3분의 1 수준</strong></li>
  <li>한국어 지원 업체가 존재 (TCP-80.NET)</li>
  <li>동급 스펙 대비 가격 경쟁력 우수</li>
  <li>한국과 동일한 시간대(UTC+9)로 장애 대응 편리</li>
</ul>

<hr />

<h2 id="싱가포르--일본-멀티-리전-구성">싱가포르 + 일본 멀티 리전 구성</h2>

<p>규모가 있는 서비스라면 싱가포르와 일본을 함께 활용하는 <strong>멀티 리전 구성</strong>도 고려할 수 있습니다.</p>

<ul>
  <li><strong>일본 도쿄</strong>: 한국·일본·대만 사용자 처리</li>
  <li><strong>싱가포르</strong>: 동남아·인도 사용자 처리</li>
</ul>

<p>단, 멀티 리전 구성은 운영 복잡도가 올라가므로 초기 서비스라면 먼저 단일 리전으로 시작해 트래픽 패턴을 파악하는 것이 현실적입니다.</p>

<hr />

<h2 id="tcp-80net-일본-도쿄-서버">TCP-80.NET 일본 도쿄 서버</h2>

<p>싱가포르 서버호스팅을 검토하고 있다면 한국 기준으로 훨씬 빠른 일본 서버도 함께 비교해보세요.</p>

<ul>
  <li><strong><a href="/virtual-server/">일본 VPS</a></strong>: 월 ₩100,000~, 1~4 vCore</li>
  <li><strong><a href="/dedicated-server/">일본 전용서버</a></strong>: 월 ₩300,000~, Intel Xeon</li>
  <li><strong><a href="/virtual-desktop/">일본 가상 데스크톱</a></strong>: 월 ₩150,000~, 일본 IP Windows 환경</li>
  <li>DDoS 방어 기본 제공, 24시간 한국어 지원, 7일 환불 보장</li>
</ul>

<hr />

<h2 id="마치며">마치며</h2>

<p>싱가포르 서버호스팅은 동남아를 타겟으로 하는 서비스에 강점이 있지만, 한국 기반 서비스에는 일본 도쿄 서버가 레이턴시, 가격, 한국어 지원 면에서 더 합리적입니다.</p>

<p>어떤 서버가 내 서비스에 맞는지 궁금하다면 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 24시간 상담해드립니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="해외서버" /><summary type="html"><![CDATA[싱가포르 서버, 싱가포르 호스팅, 싱가포르 서버호스팅을 검토 중이라면? 레이턴시, 비용, 법적 안정성 측면에서 일본 서버와 비교해 최적의 선택을 도와드립니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 DDoS 공격 대응 완전 가이드 — 방어 원리부터 실전 설정까지</title><link href="https://tcp-80.net/blog/2025/11/03/japan-server-ddos-defense/" rel="alternate" type="text/html" title="일본 서버 DDoS 공격 대응 완전 가이드 — 방어 원리부터 실전 설정까지" /><published>2025-11-03T00:00:00+09:00</published><updated>2025-11-03T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/11/03/japan-server-ddos-defense</id><content type="html" xml:base="https://tcp-80.net/blog/2025/11/03/japan-server-ddos-defense/"><![CDATA[<p>일본 서버호스팅으로 웹 서비스나 게임서버를 운영하다 보면 DDoS 공격을 경험하는 경우가 있습니다. 특히 게임서버, 커뮤니티 사이트, 이커머스는 경쟁자나 악의적인 사용자에 의한 공격 대상이 되기 쉽습니다. 이 글에서는 DDoS 공격 유형과 서버 레벨 방어 방법, 전문 방어 서비스 활용법을 정리합니다.</p>

<h2 id="ddos-공격이란">DDoS 공격이란?</h2>

<p>DDoS(Distributed Denial of Service)는 다수의 출처에서 동시에 대량의 트래픽이나 요청을 보내 서버나 네트워크를 마비시키는 공격입니다. 단일 IP 차단으로는 막기 어렵고, 공격 규모에 따라 서버 업스트림 대역폭 자체가 포화될 수도 있습니다.</p>

<hr />

<h2 id="ddos-공격-주요-유형">DDoS 공격 주요 유형</h2>

<h3 id="l3l4-네트워크-레이어-공격">L3/L4 네트워크 레이어 공격</h3>

<ul>
  <li><strong>UDP Flood</strong>: 대량의 UDP 패킷을 전송해 대역폭을 소진</li>
  <li><strong>SYN Flood</strong>: TCP 연결 요청(SYN)을 대량으로 보내 서버의 연결 테이블을 가득 채움</li>
  <li><strong>ICMP Flood</strong>: 대량의 Ping 요청으로 대역폭 소진</li>
</ul>

<p>특징: 트래픽 볼륨이 크고(수십~수백 Gbps), 서버 업스트림 자체를 마비시킬 수 있습니다.</p>

<h3 id="l7-애플리케이션-레이어-공격">L7 애플리케이션 레이어 공격</h3>

<ul>
  <li><strong>HTTP Flood</strong>: 정상처럼 보이는 HTTP 요청을 대량으로 전송</li>
  <li><strong>Slowloris</strong>: 연결을 천천히 맺어 서버 연결 자원을 고갈</li>
  <li><strong>CC 공격</strong>: 동적 페이지 요청으로 DB 부하 유발</li>
</ul>

<p>특징: 트래픽 볼륨은 작지만 서버 리소스를 고갈시켜 서비스를 다운시킵니다.</p>

<hr />

<h2 id="서버-레벨-방어-설정">서버 레벨 방어 설정</h2>

<h3 id="iptables로-syn-flood-방어">iptables로 SYN Flood 방어</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SYN 쿠키 활성화</span>
<span class="nb">echo </span>1 <span class="o">&gt;</span> /proc/sys/net/ipv4/tcp_syncookies

<span class="c"># 연결 속도 제한</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--syn</span> <span class="nt">-m</span> limit <span class="nt">--limit</span> 1/s <span class="nt">--limit-burst</span> 3 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--syn</span> <span class="nt">-j</span> DROP

<span class="c"># ICMP Flood 방어</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> icmp <span class="nt">--icmp-type</span> echo-request <span class="nt">-m</span> limit <span class="nt">--limit</span> 1/s <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> icmp <span class="nt">--icmp-type</span> echo-request <span class="nt">-j</span> DROP
</code></pre></div></div>

<h3 id="nginx-http-flood-방어">Nginx HTTP Flood 방어</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">http</span> <span class="p">{</span>
    <span class="c1"># 연결 속도 제한</span>
    <span class="kn">limit_req_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=api:10m</span> <span class="s">rate=10r/s</span><span class="p">;</span>
    <span class="kn">limit_conn_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=conn:10m</span><span class="p">;</span>

    <span class="kn">server</span> <span class="p">{</span>
        <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
            <span class="kn">limit_req</span> <span class="s">zone=api</span> <span class="s">burst=20</span> <span class="s">nodelay</span><span class="p">;</span>
            <span class="kn">limit_conn</span> <span class="s">conn</span> <span class="mi">10</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="c1"># Slowloris 방어</span>
        <span class="kn">client_body_timeout</span> <span class="s">10s</span><span class="p">;</span>
        <span class="kn">client_header_timeout</span> <span class="s">10s</span><span class="p">;</span>
        <span class="kn">keepalive_timeout</span> <span class="mi">5</span> <span class="mi">5</span><span class="p">;</span>
        <span class="kn">send_timeout</span> <span class="s">10s</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="fail2ban으로-반복-공격-ip-차단">fail2ban으로 반복 공격 IP 차단</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/fail2ban/jail.local
</span><span class="nn">[nginx-limit-req]</span><span class="w">
</span><span class="py">enabled</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">true</span>
<span class="py">filter</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">nginx-limit-req</span>
<span class="py">logpath</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/nginx/error.log</span>
<span class="py">maxretry</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10</span>
<span class="py">bantime</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">3600</span>
</code></pre></div></div>

<hr />

<h2 id="서버-레벨-방어의-한계">서버 레벨 방어의 한계</h2>

<p>서버 레벨의 iptables나 Nginx 설정은 <strong>L7 소규모 공격</strong>에 효과적입니다. 그러나 L3/L4 대용량 공격(수십 Gbps 이상)은 트래픽 자체가 서버 업스트림 회선을 포화시켜 어떤 서버 설정으로도 막을 수 없습니다.</p>

<p>이런 경우에는 <strong>업스트림 레벨의 전문 DDoS 방어 서비스</strong>가 필요합니다.</p>

<hr />

<h2 id="tcp-80net-ddos-방어-서비스">TCP-80.NET DDoS 방어 서비스</h2>

<p>TCP-80.NET은 두 단계의 DDoS 방어를 제공합니다:</p>

<h3 id="1-기본-네트워크-레이어-방어-무료-포함">1. 기본 네트워크 레이어 방어 (무료 포함)</h3>

<p>모든 서버에 기본 포함되는 L3/L4 네트워크 레이어 DDoS 방어입니다. 일반적인 UDP Flood, SYN Flood 등을 자동으로 차단합니다.</p>

<h3 id="2-전용-ddos-방어-서비스-추가-옵션">2. 전용 DDoS 방어 서비스 (추가 옵션)</h3>

<p>더 강력한 보호가 필요한 경우 <a href="/ddos-security/">전용 DDoS 방어 서비스</a>를 이용할 수 있습니다:</p>
<ul>
  <li><strong>대용량 트래픽 완화</strong>: 더 높은 방어 용량</li>
  <li><strong>L7 WAF</strong>: 애플리케이션 레이어 공격 차단</li>
  <li><strong>24시간 모니터링</strong>: 실시간 공격 감지 및 대응</li>
</ul>

<hr />

<h2 id="ddos-공격-시-즉각-대응-절차">DDoS 공격 시 즉각 대응 절차</h2>

<ol>
  <li><strong>공격 유형 파악</strong>: <code class="language-plaintext highlighter-rouge">iftop</code>, <code class="language-plaintext highlighter-rouge">nethogs</code>, <code class="language-plaintext highlighter-rouge">netstat</code> 등으로 비정상 트래픽 확인</li>
  <li><strong>공격 IP 범위 차단</strong>: iptables로 주요 공격 IP 대역 임시 차단</li>
  <li><strong>업스트림 통보</strong>: 호스팅 업체에 공격 알림 (방어 서비스 활성화 요청)</li>
  <li><strong>서비스 임시 중단 또는 트래픽 분산</strong>: 공격 규모에 따라 판단</li>
</ol>

<p>TCP-80.NET 고객은 DDoS 공격 발생 시 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 즉시 알려주시면 24시간 내 대응합니다.</p>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버에서 서비스를 운영할 때 DDoS 방어는 선택이 아닌 필수입니다. 서버 레벨 설정으로 기본 방어를 갖추고, 전문 방어 서비스로 대용량 공격에 대비하세요. TCP-80.NET은 기본 DDoS 방어를 무료로 제공하며, 더 강력한 보호는 별도 서비스로 이용할 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="보안" /><summary type="html"><![CDATA[일본 서버에서 DDoS 공격을 받았을 때 대응하는 방법을 안내합니다. DDoS 공격 유형별 특징과 Nginx, iptables, 전문 방어 서비스를 이용한 방어 방법을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-security.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-security.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 쇼핑몰 운영 가이드 — 이커머스 서버 구성과 최적화</title><link href="https://tcp-80.net/blog/2025/10/20/japan-server-ecommerce-guide/" rel="alternate" type="text/html" title="일본 서버 쇼핑몰 운영 가이드 — 이커머스 서버 구성과 최적화" /><published>2025-10-20T00:00:00+09:00</published><updated>2025-10-20T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/10/20/japan-server-ecommerce-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2025/10/20/japan-server-ecommerce-guide/"><![CDATA[<p>일본 시장을 타깃으로 하는 쇼핑몰이나, 일본 사용자에게 빠른 쇼핑 경험을 제공하려는 경우 일본 서버호스팅이 최적의 선택입니다. 이 글에서는 일본 서버에서 이커머스를 운영하기 위한 서버 구성, 성능 최적화, 보안 설정을 설명합니다.</p>

<h2 id="이커머스에-일본-서버가-필요한-이유">이커머스에 일본 서버가 필요한 이유</h2>

<ol>
  <li><strong>낮은 레이턴시</strong>: 일본 소비자 기준 응답 속도 향상 → 장바구니 이탈률 감소</li>
  <li><strong>일본 결제 시스템 연동</strong>: 일본 IP에서 안정적인 결제 게이트웨이 연동</li>
  <li><strong>SEO</strong>: 일본 구글·야후 재팬에서 현지 서버로 인식, 검색 순위에 긍정적 영향</li>
  <li><strong>데이터 현지화</strong>: 일본 개인정보보호 규정 대응</li>
</ol>

<hr />

<h2 id="이커머스-서버-스펙-선택-가이드">이커머스 서버 스펙 선택 가이드</h2>

<table>
  <thead>
    <tr>
      <th>트래픽 규모</th>
      <th>권장 서버</th>
      <th>최소 스펙</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>소규모 (일 방문 1,000 이하)</td>
      <td>VPS</td>
      <td>2 vCore, 4GB RAM, 100GB SSD</td>
    </tr>
    <tr>
      <td>중규모 (일 방문 1만 이하)</td>
      <td>VPS 상위 또는 전용서버</td>
      <td>4 vCore, 8GB RAM, 200GB SSD</td>
    </tr>
    <tr>
      <td>대규모 (일 방문 1만 이상)</td>
      <td>전용서버</td>
      <td>Xeon 멀티코어, 32GB RAM, NVMe SSD</td>
    </tr>
  </tbody>
</table>

<p>이커머스는 상품 이미지 처리, 결제 프로세싱, 재고 DB 쿼리가 동시에 처리되므로 I/O 성능이 중요합니다. NVMe SSD가 포함된 서버를 선택하세요.</p>

<hr />

<h2 id="woocommerce-이커머스-서버-구성">WooCommerce 이커머스 서버 구성</h2>

<h3 id="기본-스택">기본 스택</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Nginx → PHP-FPM 8.1 → WooCommerce(WordPress) → MariaDB → Redis
</code></pre></div></div>

<h3 id="nginx-이커머스-최적화-설정">Nginx 이커머스 최적화 설정</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="c1"># Gzip 압축</span>
    <span class="kn">gzip</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">gzip_types</span> <span class="nc">text/plain</span> <span class="nc">application/json</span> <span class="nc">application/javascript</span> <span class="nc">text/css</span><span class="p">;</span>

    <span class="c1"># 정적 파일 캐싱</span>
    <span class="kn">location</span> <span class="p">~</span><span class="sr">*</span> <span class="err">\</span><span class="s">.(jpg|jpeg|png|gif|webp|ico|css|js|woff2)</span>$ <span class="p">{</span>
        <span class="kn">expires</span> <span class="s">1y</span><span class="p">;</span>
        <span class="kn">add_header</span> <span class="s">Cache-Control</span> <span class="s">"public,</span> <span class="s">immutable"</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># WooCommerce 장바구니·결제 페이지는 캐시 제외</span>
    <span class="kn">set</span> <span class="nv">$skip_cache</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kn">if</span> <span class="s">(</span><span class="nv">$request_uri</span> <span class="p">~</span><span class="sr">*</span> <span class="s">"/cart|/checkout|/my-account|/wc-api")</span> <span class="p">{</span>
        <span class="kn">set</span> <span class="nv">$skip_cache</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="mariadb-이커머스-최적화">MariaDB 이커머스 최적화</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/mysql/mariadb.conf.d/99-ecommerce.cnf
</span><span class="nn">[mysqld]</span><span class="w">
</span><span class="py">innodb_buffer_pool_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2G      # RAM의 50~70% 할당</span>
<span class="py">innodb_log_file_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">256M</span>
<span class="py">query_cache_type</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">0              # MariaDB 10.4 이상에서는 비활성화 권장</span>
<span class="py">max_connections</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">200</span>
</code></pre></div></div>

<hr />

<h2 id="이커머스-보안-필수-설정">이커머스 보안 필수 설정</h2>

<p>쇼핑몰은 결제 정보와 고객 개인정보를 다루므로 보안이 특히 중요합니다.</p>

<h3 id="1-ssltls-인증서-필수">1. SSL/TLS 인증서 (필수)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>certbot <span class="nt">--nginx</span> <span class="nt">-d</span> shop.yourdomain.com
</code></pre></div></div>

<p>결제 페이지는 반드시 HTTPS로만 접근 가능하도록 설정하세요.</p>

<h3 id="2-waf-웹방화벽-적용">2. WAF (웹방화벽) 적용</h3>

<p>SQL 인젝션, XSS 공격으로부터 쇼핑몰을 보호합니다. TCP-80.NET의 <a href="/hacking-security/">해킹 방지 보안 서비스</a>를 이용하면 전문적인 WAF 보호를 받을 수 있습니다.</p>

<h3 id="3-결제-페이지-ip-로깅">3. 결제 페이지 IP 로깅</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">log_format</span> <span class="s">checkout</span> <span class="s">'</span><span class="nv">$remote_addr</span> <span class="s">-</span> <span class="s">[</span><span class="nv">$time_local</span><span class="s">]</span> <span class="s">"</span><span class="nv">$request</span><span class="s">"</span> <span class="nv">$status</span><span class="s">'</span><span class="p">;</span>
<span class="k">access_log</span> <span class="n">/var/log/nginx/checkout.log</span> <span class="s">checkout</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="4-정기-백업">4. 정기 백업</h3>

<p>매일 자동 백업 스크립트를 설정하고, 백업 파일은 원격 스토리지에 저장하세요.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># crontab -e</span>
0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> mysqldump <span class="nt">-u</span> root wordpress_db | <span class="nb">gzip</span> <span class="o">&gt;</span> /backup/db_<span class="si">$(</span><span class="nb">date</span> +<span class="se">\%</span>Y<span class="se">\%</span>m<span class="se">\%</span>d<span class="si">)</span>.sql.gz
</code></pre></div></div>

<hr />

<h2 id="일본-결제-시스템-연동">일본 결제 시스템 연동</h2>

<p>일본 쇼핑몰에서 많이 사용하는 결제 수단:</p>
<ul>
  <li><strong>Stripe Japan</strong>: 신용카드 결제, 일본 IP에서 안정적 운영</li>
  <li><strong>PayPay</strong>: 일본 최대 모바일 결제</li>
  <li><strong>コンビニ決済 (편의점 결제)</strong>: 일본 특유의 결제 방식</li>
  <li><strong>代金引換 (착불)</strong>: 일본 소비자 선호도 높음</li>
</ul>

<p>일본 IP 서버에서 운영하면 결제 게이트웨이 이상 감지(fraud detection) 오작동을 줄일 수 있습니다.</p>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 이커머스 서버는 성능, 보안, 결제 안정성 세 가지를 모두 갖춰야 합니다. TCP-80.NET은 일본 도쿄 데이터센터에서 이커머스에 최적화된 전용서버와 VPS를 제공합니다. 쇼핑몰 서버 구성에 대한 문의는 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅으로 쇼핑몰을 운영하는 방법을 안내합니다. WooCommerce, 자사몰 등 이커머스 서버 구성, 성능 최적화, 보안 설정까지 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">홍콩 서버호스팅 vs 일본 서버호스팅 — 한국 서비스에 더 나은 선택은?</title><link href="https://tcp-80.net/blog/2025/10/06/hongkong-server-hosting/" rel="alternate" type="text/html" title="홍콩 서버호스팅 vs 일본 서버호스팅 — 한국 서비스에 더 나은 선택은?" /><published>2025-10-06T00:00:00+09:00</published><updated>2025-10-06T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/10/06/hongkong-server-hosting</id><content type="html" xml:base="https://tcp-80.net/blog/2025/10/06/hongkong-server-hosting/"><![CDATA[<p>아시아 서버 호스팅을 알아보다 보면 홍콩 서버와 일본 서버 사이에서 고민하는 경우가 많습니다. 홍콩 서버호스팅은 한때 아시아 IT 인프라의 핵심 거점이었지만, 최근 환경이 많이 변했습니다. 이 글에서는 한국 서비스 운영자 관점에서 홍콩 서버와 일본 서버를 비교합니다.</p>

<h2 id="홍콩-서버호스팅의-특징">홍콩 서버호스팅의 특징</h2>

<h3 id="아시아-인터넷-허브">아시아 인터넷 허브</h3>

<p>홍콩은 HKIX(홍콩 인터넷 교환소)를 비롯해 Equinix, Global Switch 등 세계적인 데이터센터 시설이 집중된 아시아 네트워크 허브입니다. 중국 본토와의 접근성이 상대적으로 좋아 중화권 서비스를 운영하는 기업들이 많이 사용했습니다.</p>

<h3 id="홍콩-서버-레이턴시">홍콩 서버 레이턴시</h3>

<p>서울에서 홍콩까지의 왕복 레이턴시는 <strong>40~65ms</strong> 수준입니다. 일본 도쿄(20~35ms)보다 약 2배 높습니다.</p>

<hr />

<h2 id="홍콩-서버호스팅의-현재-상황">홍콩 서버호스팅의 현재 상황</h2>

<h3 id="2020년-홍콩-국가보안법-이후-변화">2020년 홍콩 국가보안법 이후 변화</h3>

<p>2020년 홍콩 국가보안법(NSL) 시행 이후 홍콩 데이터센터 환경은 크게 달라졌습니다.</p>

<ul>
  <li><strong>다국적 기업 이탈</strong>: 법적 불확실성으로 인해 많은 글로벌 기업들이 홍콩 서버를 싱가포르, 일본 등으로 이전</li>
  <li><strong>데이터 보호 우려</strong>: 홍콩 당국의 데이터 요청 가능성에 대한 우려 증가</li>
  <li><strong>인터넷 자유 제한 우려</strong>: 일부 인터넷 서비스 접근 제한 가능성</li>
</ul>

<p>이런 배경으로 홍콩 서버호스팅보다 <strong>싱가포르 또는 일본</strong>을 선택하는 흐름이 뚜렷해졌습니다.</p>

<hr />

<h2 id="홍콩-서버-vs-일본-서버-직접-비교">홍콩 서버 vs 일본 서버 직접 비교</h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>홍콩 서버</th>
      <th>일본 도쿄 서버</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>서울 레이턴시</td>
      <td>40~65ms</td>
      <td>20~35ms</td>
    </tr>
    <tr>
      <td>한국어 지원 업체</td>
      <td>드묾</td>
      <td>TCP-80.NET 등 가능</td>
    </tr>
    <tr>
      <td>법적 안정성</td>
      <td>불확실성 증가</td>
      <td>안정적</td>
    </tr>
    <tr>
      <td>중국 접근성</td>
      <td>상대적 우수</td>
      <td>제한적</td>
    </tr>
    <tr>
      <td>DDoS 방어</td>
      <td>업체마다 다름</td>
      <td>업체마다 다름</td>
    </tr>
    <tr>
      <td>아시아 IX 접근성</td>
      <td>우수</td>
      <td>우수</td>
    </tr>
    <tr>
      <td>가격</td>
      <td>보통</td>
      <td>합리적</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="홍콩-서버가-유리한-경우">홍콩 서버가 유리한 경우</h2>

<p>홍콩 서버호스팅이 일본보다 나은 경우는 한정적입니다.</p>

<ul>
  <li><strong>중국 본토 사용자 대상 서비스</strong>: 중국과의 네트워크 접근성이 중요한 서비스 (단, 이 경우도 최근에는 싱가포르가 더 선호됨)</li>
  <li><strong>중화권 특화 서비스</strong>: 홍콩 현지 IP가 반드시 필요한 경우</li>
</ul>

<hr />

<h2 id="한국-기반-서비스라면-일본-서버가-낫습니다">한국 기반 서비스라면 일본 서버가 낫습니다</h2>

<p>한국 사용자 대상 서비스, 또는 아시아 전반을 커버하는 서비스라면 일본 도쿄 서버가 더 유리합니다.</p>

<p><strong>이유:</strong></p>
<ol>
  <li><strong>레이턴시가 절반</strong>: 서울~도쿄는 서울~홍콩보다 약 2배 빠름</li>
  <li><strong>안정적인 법적 환경</strong>: 일본은 데이터 보호 법체계가 안정적</li>
  <li><strong>한국어 지원</strong>: 일본 서버를 직영하면서 한국어로 지원하는 업체 존재</li>
  <li><strong>아시아 커버리지</strong>: 도쿄는 한국, 일본, 대만, 동남아 모두에 양호한 레이턴시</li>
</ol>

<hr />

<h2 id="tcp-80net-일본-서버로-홍콩-대안-찾기">TCP-80.NET 일본 서버로 홍콩 대안 찾기</h2>

<p>홍콩 서버호스팅을 검토하고 있다면 TCP-80.NET의 일본 도쿄 서버를 비교해보세요.</p>

<ul>
  <li><strong>일본 VPS</strong>: 월 ₩100,000부터, 1~4 vCore / 최대 12GB RAM</li>
  <li><strong>일본 전용서버</strong>: 월 ₩300,000부터, Intel Xeon 기반</li>
  <li><strong>DDoS 방어 기본 제공</strong>: L3/L4 네트워크 레이어 방어 무료 포함</li>
  <li><strong>24시간 한국어 지원</strong>: 텔레그램으로 즉시 응답</li>
  <li><strong>7일 환불 보장</strong>: 서비스 품질이 기대에 미치지 않으면 전액 환불</li>
</ul>

<p>자세한 스펙과 가격은 <a href="/dedicated-server/">전용서버 페이지</a>와 <a href="/virtual-server/">VPS 페이지</a>에서 확인하세요.</p>

<hr />

<h2 id="마치며">마치며</h2>

<p>홍콩 서버호스팅은 과거에는 아시아 서버의 강력한 선택지였지만, 법적 환경 변화와 상대적으로 높은 레이턴시로 인해 한국 사용자에게는 일본 서버가 더 합리적인 대안입니다.</p>

<p>서버 선택에 대한 상담은 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 24시간 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="해외서버" /><summary type="html"><![CDATA[홍콩 서버, 홍콩 서버호스팅, 홍콩 호스팅을 알아보고 있다면? 일본 서버와의 레이턴시, 가격, 안정성, 법적 환경을 비교해 한국 서비스에 최적화된 선택을 도와드립니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 레이턴시(핑) 완전 가이드 — 측정 방법과 최적화 팁</title><link href="https://tcp-80.net/blog/2025/09/29/japan-server-latency-guide/" rel="alternate" type="text/html" title="일본 서버 레이턴시(핑) 완전 가이드 — 측정 방법과 최적화 팁" /><published>2025-09-29T00:00:00+09:00</published><updated>2025-09-29T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/09/29/japan-server-latency-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2025/09/29/japan-server-latency-guide/"><![CDATA[<p>일본 서버호스팅을 선택하는 가장 큰 이유 중 하나가 낮은 레이턴시(지연 시간)입니다. 하지만 “일본 서버라서 빠르다”는 막연한 기대보다는, 실제 수치와 영향 요인을 이해하는 것이 중요합니다.</p>

<h2 id="레이턴시latency란">레이턴시(Latency)란?</h2>

<p>레이턴시는 데이터 패킷이 출발지에서 목적지까지 왕복하는 데 걸리는 시간으로, RTT(Round Trip Time)라고도 합니다. 단위는 밀리초(ms)이며, 숫자가 낮을수록 빠릅니다.</p>

<table>
  <thead>
    <tr>
      <th>레이턴시</th>
      <th>체감</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1~20ms</td>
      <td>거의 즉각적, 최상급</td>
    </tr>
    <tr>
      <td>20~50ms</td>
      <td>쾌적, 게임·실시간 서비스 적합</td>
    </tr>
    <tr>
      <td>50~100ms</td>
      <td>일반 웹서비스에는 충분</td>
    </tr>
    <tr>
      <td>100ms 이상</td>
      <td>실시간 서비스에 불편함 느낌</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="한국--일본-도쿄-레이턴시-실측값">한국 → 일본 도쿄 레이턴시 실측값</h2>

<p>일반적인 한국(서울) → 일본(도쿄) 레이턴시:</p>
<ul>
  <li><strong>가정용 인터넷(KT/SKT/LGU+)</strong>: 평균 30~50ms</li>
  <li><strong>기업용 전용회선</strong>: 평균 20~35ms</li>
  <li><strong>서버 간 통신 (데이터센터 기준)</strong>: 평균 15~30ms</li>
</ul>

<blockquote>
  <p>측정 환경과 시간대에 따라 수치는 달라질 수 있습니다.</p>
</blockquote>

<hr />

<h2 id="레이턴시에-영향을-미치는-요인">레이턴시에 영향을 미치는 요인</h2>

<h3 id="1-물리적-거리">1. 물리적 거리</h3>

<p>서울과 도쿄 사이의 직선 거리는 약 1,200km입니다. 광속에 의한 이론적 최소 지연은 약 4ms이며, 실제 회선은 해저 케이블을 통해 라우팅됩니다.</p>

<h3 id="2-라우팅-경로">2. 라우팅 경로</h3>

<p>인터넷 트래픽은 목적지까지 여러 라우터를 경유합니다. 업스트림 통신사(KT, SKT 등)와 일본 측 통신사(NTT, KDDI 등) 간의 피어링 품질이 레이턴시에 영향을 줍니다.</p>

<h3 id="3-데이터센터-내-네트워크">3. 데이터센터 내 네트워크</h3>

<p>데이터센터의 스위치, 라우터 품질과 네트워크 설계에 따라 내부 처리 지연이 달라집니다.</p>

<h3 id="4-서버-부하">4. 서버 부하</h3>

<p>서버 CPU, RAM 사용률이 높으면 요청 처리 시간이 늘어나 체감 레이턴시가 증가합니다. 전용서버는 리소스를 단독 점유하므로 VPS보다 일관된 레이턴시를 보입니다.</p>

<hr />

<h2 id="레이턴시-측정-방법">레이턴시 측정 방법</h2>

<h3 id="ping-명령어-기본">ping 명령어 (기본)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ping <span class="nt">-c</span> 10 서버IP
</code></pre></div></div>

<p>10회 평균값을 보면 기본적인 레이턴시를 알 수 있습니다.</p>

<h3 id="mtr--경로별-레이턴시-분석">mtr — 경로별 레이턴시 분석</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>mtr <span class="nt">-y</span>
mtr 서버IP
</code></pre></div></div>

<p>mtr은 traceroute와 ping을 결합해 각 홉(라우터)에서의 지연을 실시간으로 보여줍니다. 어느 구간에서 지연이 발생하는지 파악할 수 있습니다.</p>

<h3 id="http-응답-시간-측정">HTTP 응답 시간 측정</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-o</span> /dev/null <span class="nt">-s</span> <span class="nt">-w</span> <span class="s2">"Connect: %{time_connect}s</span><span class="se">\n</span><span class="s2">TTFB: %{time_starttransfer}s</span><span class="se">\n</span><span class="s2">Total: %{time_total}s</span><span class="se">\n</span><span class="s2">"</span> https://yourdomain.com
</code></pre></div></div>

<p>TTFB(Time To First Byte)는 실제 웹 서비스 응답 속도를 나타냅니다.</p>

<hr />

<h2 id="레이턴시-최적화-방법">레이턴시 최적화 방법</h2>

<h3 id="1-지리적으로-가까운-데이터센터-선택">1. 지리적으로 가까운 데이터센터 선택</h3>

<p>도쿄 내에서도 데이터센터 위치에 따라 10~15ms 차이가 날 수 있습니다. 특히 한국 트래픽은 도쿄 도심 데이터센터가 유리합니다.</p>

<h3 id="2-nginx-응답-압축-설정">2. Nginx 응답 압축 설정</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">gzip</span> <span class="no">on</span><span class="p">;</span>
<span class="k">gzip_types</span> <span class="nc">text/plain</span> <span class="nc">text/css</span> <span class="nc">application/json</span> <span class="nc">application/javascript</span><span class="p">;</span>
<span class="k">gzip_min_length</span> <span class="mi">1000</span><span class="p">;</span>
</code></pre></div></div>

<p>전송 데이터량을 줄여 체감 속도를 개선합니다.</p>

<h3 id="3-http2-또는-http3-활성화">3. HTTP/2 또는 HTTP/3 활성화</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">listen</span> <span class="mi">443</span> <span class="s">ssl</span> <span class="s">http2</span><span class="p">;</span>
</code></pre></div></div>

<p>HTTP/2는 멀티플렉싱으로 동시 요청을 효율적으로 처리해 레이턴시를 줄입니다.</p>

<h3 id="4-캐시-활용">4. 캐시 활용</h3>

<p>Redis, Nginx FastCGI 캐시를 활용해 서버 처리 시간을 단축합니다.</p>

<h3 id="5-cdn-연동">5. CDN 연동</h3>

<p>정적 파일(이미지, CSS, JS)은 Cloudflare 등 CDN을 통해 사용자 가까운 서버에서 제공합니다.</p>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버호스팅은 한국·아시아 사용자에게 낮은 레이턴시를 제공하는 최선의 선택 중 하나입니다. 서버 선택 전에 테스트 IP로 직접 핑을 측정해보는 것을 권장합니다. TCP-80.NET은 테스트 IP를 제공하며, 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의하시면 됩니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅의 레이턴시(핑)를 측정하고 최적화하는 방법을 정리했습니다. 한국에서 도쿄 서버까지의 실제 핑 수치와 레이턴시에 영향을 미치는 요인을 알아보세요.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 IP 주소가 필요한 이유 7가지 — 일본 서버 활용 사례 총정리</title><link href="https://tcp-80.net/blog/2025/09/15/japan-ip-address-uses/" rel="alternate" type="text/html" title="일본 IP 주소가 필요한 이유 7가지 — 일본 서버 활용 사례 총정리" /><published>2025-09-15T00:00:00+09:00</published><updated>2025-09-15T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/09/15/japan-ip-address-uses</id><content type="html" xml:base="https://tcp-80.net/blog/2025/09/15/japan-ip-address-uses/"><![CDATA[<p>일본 서버호스팅을 찾는 분들 중에는 단순히 서버 성능뿐 아니라 <strong>일본 IP 주소</strong> 자체가 필요한 경우가 많습니다. 이 글에서는 일본 IP가 필요한 7가지 구체적인 상황과 각 상황에 맞는 서버 선택 방법을 정리합니다.</p>

<h2 id="1-일본-인터넷-뱅킹-및-금융-서비스-이용">1. 일본 인터넷 뱅킹 및 금융 서비스 이용</h2>

<p>일본 은행(미쓰비시UFJ, 스미토모미쓰이, 유초은행 등)은 해외 IP에서의 접속을 제한하거나 추가 인증을 요구합니다. 일본 내 IP 주소를 가진 서버에서 접속하면 이런 제한을 피할 수 있습니다.</p>

<p><strong>적합한 서비스</strong>: <a href="/virtual-desktop/">일본 가상 데스크톱(RDP)</a> — Windows GUI 환경에서 인터넷 뱅킹 이용 가능</p>

<hr />

<h2 id="2-일본-한정-스트리밍콘텐츠-서비스">2. 일본 한정 스트리밍·콘텐츠 서비스</h2>

<p>일부 일본 동영상 서비스, 앱, 온라인 서비스는 <strong>일본 IP에서만 접속</strong>을 허용합니다. 일본 서버를 통해 이러한 서비스를 이용할 수 있습니다.</p>

<p><strong>적합한 서비스</strong>: 일본 가상 데스크톱 또는 일본 VPS + 브라우저 환경</p>

<hr />

<h2 id="3-일본-대상-웹-서비스앱-운영">3. 일본 대상 웹 서비스·앱 운영</h2>

<p>한국 기업이 일본 시장을 공략하는 경우, 서버를 일본에 두면 다음과 같은 이점이 있습니다:</p>
<ul>
  <li><strong>SEO</strong>: 일본 구글, 야후 재팬 검색 결과에서 국내 서비스로 인식</li>
  <li><strong>속도</strong>: 일본 사용자 기준 응답 속도 향상</li>
  <li><strong>법적 준수</strong>: 일본 개인정보보호법(个人情報保護法) 요건 중 일부는 데이터의 일본 내 저장을 선호</li>
</ul>

<p><strong>적합한 서비스</strong>: <a href="/virtual-server/">일본 VPS</a> 또는 <a href="/dedicated-server/">전용서버</a></p>

<hr />

<h2 id="4-일본-광고마케팅-운영">4. 일본 광고·마케팅 운영</h2>

<p>일본 광고 플랫폼(Yahoo! Japan 광고, 일본 SNS 마케팅 등)을 운영할 때 일본 IP를 사용하면 계정 관리와 광고 집행이 원활합니다. 해외 IP로 접속하면 계정 정지나 보안 알림이 발생하는 경우가 있습니다.</p>

<hr />

<h2 id="5-일본-이커머스-플랫폼-판매자-계정-관리">5. 일본 이커머스 플랫폼 판매자 계정 관리</h2>

<p>Amazon.co.jp, 라쿠텐, 야후쇼핑 등 일본 이커머스 플랫폼의 판매자 계정을 관리할 때 일본 IP가 유리합니다. 해외 IP 접속 시 계정 보안 알림이나 접근 제한이 생기는 경우가 있습니다.</p>

<p><strong>적합한 서비스</strong>: 일본 가상 데스크톱(Windows 환경)</p>

<hr />

<h2 id="6-일본-게임-서비스-및-사설-게임서버">6. 일본 게임 서비스 및 사설 게임서버</h2>

<p>일본 온라인 게임은 일본 서버에서 운영되는 경우 일본 플레이어에게 최저 핑을 제공합니다. 또한 한국·대만·동남아 플레이어도 아시아 허브인 도쿄를 통해 낮은 레이턴시로 접속할 수 있습니다.</p>

<p><strong>적합한 서비스</strong>: <a href="/dedicated-server/">전용서버</a> (고성능 CPU, RAM 단독 점유)</p>

<hr />

<h2 id="7-일본-법인사업자의-it-인프라">7. 일본 법인·사업자의 IT 인프라</h2>

<p>일본에 법인이 있거나 일본 파트너사와 협업하는 경우, 일본 서버를 IT 인프라로 사용하면 데이터 접근성과 보안을 모두 확보할 수 있습니다. 일본 국내 데이터 처리를 요구하는 계약 조건에도 부합합니다.</p>

<hr />

<h2 id="일본-ip-서비스-비교">일본 IP 서비스 비교</h2>

<table>
  <thead>
    <tr>
      <th>용도</th>
      <th>권장 서비스</th>
      <th>특징</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>인터넷 뱅킹·업무</td>
      <td>가상 데스크톱</td>
      <td>Windows GUI, 월 ₩150,000~</td>
    </tr>
    <tr>
      <td>웹 서비스 운영</td>
      <td>VPS / 전용서버</td>
      <td>Linux 서버 환경</td>
    </tr>
    <tr>
      <td>게임서버</td>
      <td>전용서버</td>
      <td>고성능 CPU, 월 ₩300,000~</td>
    </tr>
    <tr>
      <td>마케팅 운영</td>
      <td>가상 데스크톱</td>
      <td>Windows 브라우저 환경</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 IP 주소가 필요한 이유는 다양합니다. 용도에 맞는 서비스를 선택하는 것이 중요한데, 단순 인터넷 뱅킹이라면 가상 데스크톱, 웹 서비스 운영이라면 VPS나 전용서버가 적합합니다.</p>

<p>정확한 용도를 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 알려주시면 최적의 서비스를 안내해 드립니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 IP 주소가 필요한 구체적인 활용 사례를 정리했습니다. 일본 인터넷 뱅킹, 스트리밍 서비스, 마케팅 운영, 게임 서비스까지 일본 서버가 필요한 상황을 알아보세요.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 Node.js 웹 서비스 배포 가이드 — PM2 + Nginx 리버스 프록시 설정</title><link href="https://tcp-80.net/blog/2025/09/01/japan-server-nodejs-deploy/" rel="alternate" type="text/html" title="일본 서버 Node.js 웹 서비스 배포 가이드 — PM2 + Nginx 리버스 프록시 설정" /><published>2025-09-01T00:00:00+09:00</published><updated>2025-09-01T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/09/01/japan-server-nodejs-deploy</id><content type="html" xml:base="https://tcp-80.net/blog/2025/09/01/japan-server-nodejs-deploy/"><![CDATA[<p>일본 서버에 Node.js 기반 웹 서비스(Express, Fastify, Next.js 등)를 배포하는 방법을 안내합니다. PM2로 프로세스를 안정적으로 관리하고, Nginx를 리버스 프록시로 사용해 80/443 포트로 서비스하는 전체 구성을 다룹니다.</p>

<h2 id="왜-일본-서버에서-nodejs를-운영하나요">왜 일본 서버에서 Node.js를 운영하나요?</h2>

<p>Node.js 기반 API 서버, 실시간 채팅, 스트리밍 서비스를 일본 서버에서 운영하면 한국과 아시아 사용자 모두에게 낮은 레이턴시를 제공할 수 있습니다. 특히 WebSocket을 사용하는 실시간 서비스는 서버와 클라이언트 간의 지연이 사용자 경험에 직접적인 영향을 미치므로, 지리적으로 가까운 일본 서버 선택이 유리합니다.</p>

<hr />

<h2 id="1단계-nodejs-설치">1단계: Node.js 설치</h2>

<p>Ubuntu 22.04 LTS 기준으로 Node.js LTS 버전을 설치합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># NodeSource 저장소 추가 (Node.js 20 LTS)</span>
curl <span class="nt">-fsSL</span> https://deb.nodesource.com/setup_20.x | bash -
apt <span class="nb">install </span>nodejs <span class="nt">-y</span>

<span class="c"># 버전 확인</span>
node <span class="nt">--version</span>
npm <span class="nt">--version</span>
</code></pre></div></div>

<hr />

<h2 id="2단계-pm2-설치-및-앱-실행">2단계: PM2 설치 및 앱 실행</h2>

<p>PM2는 Node.js 프로세스 매니저로, 앱이 크래시되면 자동으로 재시작하고 서버 재부팅 시에도 자동으로 앱을 시작합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># PM2 전역 설치</span>
npm <span class="nb">install</span> <span class="nt">-g</span> pm2

<span class="c"># 앱 시작 (예: app.js)</span>
pm2 start app.js <span class="nt">--name</span> <span class="s2">"my-api"</span>

<span class="c"># 서버 재부팅 시 자동 시작 설정</span>
pm2 startup
pm2 save
</code></pre></div></div>

<h3 id="pm2-주요-명령어">PM2 주요 명령어</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pm2 list           <span class="c"># 실행 중인 프로세스 목록</span>
pm2 logs my-api    <span class="c"># 로그 확인</span>
pm2 restart my-api <span class="c"># 재시작</span>
pm2 stop my-api    <span class="c"># 중지</span>
pm2 monit          <span class="c"># 실시간 모니터링</span>
</code></pre></div></div>

<hr />

<h2 id="3단계-nginx-리버스-프록시-설정">3단계: Nginx 리버스 프록시 설정</h2>

<p>Node.js 앱은 3000번 포트에서 실행되고, Nginx가 80(HTTP)/443(HTTPS) 요청을 받아 내부적으로 전달하는 구조입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>nginx <span class="nt">-y</span>
</code></pre></div></div>

<p>Nginx 가상 호스트 파일 생성:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/sites-available/my-api</span>
<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">yourdomain.com</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://localhost:3000</span><span class="p">;</span>
        <span class="kn">proxy_http_version</span> <span class="mf">1.1</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Upgrade</span> <span class="nv">$http_upgrade</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Connection</span> <span class="s">'upgrade'</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
        <span class="kn">proxy_cache_bypass</span> <span class="nv">$http_upgrade</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> <span class="nt">-s</span> /etc/nginx/sites-available/my-api /etc/nginx/sites-enabled/
nginx <span class="nt">-t</span>
systemctl reload nginx
</code></pre></div></div>

<hr />

<h2 id="4단계-ssl-인증서-설정-lets-encrypt">4단계: SSL 인증서 설정 (Let’s Encrypt)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>certbot python3-certbot-nginx <span class="nt">-y</span>
certbot <span class="nt">--nginx</span> <span class="nt">-d</span> yourdomain.com
</code></pre></div></div>

<p>Certbot이 자동으로 Nginx 설정에 SSL을 추가하고 자동 갱신을 설정합니다.</p>

<hr />

<h2 id="5단계-websocket-지원-실시간-서비스">5단계: WebSocket 지원 (실시간 서비스)</h2>

<p>WebSocket을 사용하는 서비스(Socket.io 등)는 Nginx에 추가 설정이 필요합니다.</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">location</span> <span class="n">/socket.io/</span> <span class="p">{</span>
    <span class="kn">proxy_pass</span> <span class="s">http://localhost:3000</span><span class="p">;</span>
    <span class="kn">proxy_http_version</span> <span class="mf">1.1</span><span class="p">;</span>
    <span class="kn">proxy_set_header</span> <span class="s">Upgrade</span> <span class="nv">$http_upgrade</span><span class="p">;</span>
    <span class="kn">proxy_set_header</span> <span class="s">Connection</span> <span class="s">"upgrade"</span><span class="p">;</span>
    <span class="kn">proxy_read_timeout</span> <span class="mi">86400</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="6단계-환경-변수-관리">6단계: 환경 변수 관리</h2>

<p>PM2 ecosystem 파일로 환경 변수를 안전하게 관리합니다:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ecosystem.config.js</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">apps</span><span class="p">:</span> <span class="p">[{</span>
    <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">my-api</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">script</span><span class="p">:</span> <span class="dl">'</span><span class="s1">app.js</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">env</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">NODE_ENV</span><span class="p">:</span> <span class="dl">'</span><span class="s1">production</span><span class="dl">'</span><span class="p">,</span>
      <span class="na">PORT</span><span class="p">:</span> <span class="mi">3000</span><span class="p">,</span>
      <span class="na">DB_HOST</span><span class="p">:</span> <span class="dl">'</span><span class="s1">localhost</span><span class="dl">'</span><span class="p">,</span>
    <span class="p">}</span>
  <span class="p">}]</span>
<span class="p">};</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pm2 start ecosystem.config.js
</code></pre></div></div>

<hr />

<h2 id="성능-최적화-팁">성능 최적화 팁</h2>

<ol>
  <li><strong>클러스터 모드</strong>: PM2의 클러스터 모드로 CPU 코어를 모두 활용
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pm2 start app.js <span class="nt">-i</span> max
</code></pre></div>    </div>
  </li>
  <li><strong>Nginx Gzip 압축</strong>: 응답 데이터를 압축해 전송량 절감</li>
  <li><strong>Redis 세션 캐시</strong>: 세션 데이터를 Redis에 저장해 DB 부하 감소</li>
</ol>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버에 Node.js + PM2 + Nginx 조합은 안정적이고 성능 좋은 웹 서비스를 위한 검증된 스택입니다. 배포 과정에서 어려움이 있으시면 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅에 Node.js 웹 서비스를 배포하는 방법을 안내합니다. PM2로 프로세스를 관리하고 Nginx 리버스 프록시로 외부 트래픽을 연결하는 전체 과정을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">해외 데이터센터(해외 IDC) 선택 가이드 — 아시아 주요 거점 비교</title><link href="https://tcp-80.net/blog/2025/08/25/overseas-idc-datacenter/" rel="alternate" type="text/html" title="해외 데이터센터(해외 IDC) 선택 가이드 — 아시아 주요 거점 비교" /><published>2025-08-25T00:00:00+09:00</published><updated>2025-08-25T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/08/25/overseas-idc-datacenter</id><content type="html" xml:base="https://tcp-80.net/blog/2025/08/25/overseas-idc-datacenter/"><![CDATA[<p>해외 서버를 운영하기로 결정했다면 다음 질문은 “어느 나라 데이터센터를 써야 할까?”입니다. 이 글에서는 한국 사용자 관점에서 주요 해외 IDC(해외 데이터센터) 거점을 비교하고 선택 기준을 제시합니다.</p>

<h2 id="해외-idc-선택의-핵심-기준">해외 IDC 선택의 핵심 기준</h2>

<p>해외 데이터센터를 선택할 때 가장 먼저 고려해야 할 요소는 다음과 같습니다.</p>

<ol>
  <li><strong>레이턴시 (지연 시간)</strong>: 주요 사용자와의 물리적 거리</li>
  <li><strong>네트워크 품질</strong>: IX(인터넷 교환소) 접근성, 멀티홈 구성</li>
  <li><strong>법적 환경</strong>: 데이터 보호법, 서버 압수 리스크</li>
  <li><strong>가격</strong>: 동급 스펙 기준 월 비용</li>
  <li><strong>언어 지원</strong>: 장애 시 소통 가능 여부</li>
</ol>

<hr />

<h2 id="아시아-해외-idc-주요-거점-비교">아시아 해외 IDC 주요 거점 비교</h2>

<h3 id="일본-도쿄-idc">일본 도쿄 IDC</h3>

<p>한국 사용자에게 <strong>가장 가까운 해외 IDC</strong> 거점입니다.</p>

<ul>
  <li><strong>서울 → 도쿄 레이턴시</strong>: 20~35ms (RTT)</li>
  <li><strong>네트워크</strong>: JPIX, JPNAP 등 아시아 주요 IX 연결</li>
  <li><strong>법적 환경</strong>: 안정적인 법체계, 데이터 보호 강화</li>
  <li><strong>강점</strong>: 낮은 레이턴시, 안정적 인프라, 한국어 지원 업체 존재</li>
  <li><strong>약점</strong>: 홍콩 대비 중국 접근성 낮음</li>
</ul>

<p><strong>적합한 용도</strong>: 한국 사용자 대상 서비스, 일본 IP 필요 서비스, 아시아 전반 대상 게임서버</p>

<h3 id="홍콩-idc">홍콩 IDC</h3>

<p>아시아 인터넷의 또 다른 허브입니다.</p>

<ul>
  <li><strong>서울 → 홍콩 레이턴시</strong>: 40~65ms</li>
  <li><strong>네트워크</strong>: HKIX 등 아시아 핵심 IX 위치</li>
  <li><strong>법적 환경</strong>: 최근 홍콩 보안법 이후 일부 기업 이탈 추세</li>
  <li><strong>강점</strong>: 중국 본토 접근성 상대적으로 좋음</li>
  <li><strong>약점</strong>: 도쿄보다 높은 레이턴시, 법적 불확실성</li>
</ul>

<p><strong>적합한 용도</strong>: 중국 인접 서비스, 동남아·중화권 타겟 서비스</p>

<h3 id="싱가포르-idc">싱가포르 IDC</h3>

<p>동남아시아의 핵심 IDC 허브입니다.</p>

<ul>
  <li><strong>서울 → 싱가포르 레이턴시</strong>: 70~100ms</li>
  <li><strong>네트워크</strong>: SGIX, Equinix SG 등 글로벌 급 IX</li>
  <li><strong>법적 환경</strong>: 영미법 기반, 안정적, 기업 친화적</li>
  <li><strong>강점</strong>: 동남아 최대 IDC 허브, 글로벌 CDN 노드 집결</li>
  <li><strong>약점</strong>: 한국 기준 레이턴시 높음</li>
</ul>

<p><strong>적합한 용도</strong>: 동남아 타겟 서비스, 글로벌 분산 인프라</p>

<h3 id="미국-서부-로스앤젤레스--시애틀-idc">미국 서부 (로스앤젤레스 / 시애틀) IDC</h3>

<ul>
  <li><strong>서울 → LA 레이턴시</strong>: 140~180ms</li>
  <li><strong>강점</strong>: 저렴한 가격, 대규모 인프라</li>
  <li><strong>약점</strong>: 높은 레이턴시, 한국·아시아 사용자에게 부적합</li>
</ul>

<hr />

<h2 id="한국-서비스에-최적인-해외-idc는">한국 서비스에 최적인 해외 IDC는?</h2>

<p>한국 사용자를 대상으로 하는 서비스라면 <strong>일본 도쿄 IDC</strong>가 압도적으로 유리합니다.</p>

<table>
  <thead>
    <tr>
      <th>지역</th>
      <th>레이턴시</th>
      <th>한국어 지원</th>
      <th>가격</th>
      <th>추천 용도</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>일본 도쿄</strong></td>
      <td>★★★★★</td>
      <td>가능</td>
      <td>합리적</td>
      <td>한국·아시아 전반</td>
    </tr>
    <tr>
      <td>홍콩</td>
      <td>★★★★</td>
      <td>어려움</td>
      <td>보통</td>
      <td>중화권·동남아</td>
    </tr>
    <tr>
      <td>싱가포르</td>
      <td>★★★</td>
      <td>어려움</td>
      <td>보통~높음</td>
      <td>동남아 전용</td>
    </tr>
    <tr>
      <td>미국 서부</td>
      <td>★★</td>
      <td>어려움</td>
      <td>저렴</td>
      <td>미국 타겟</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="해외-idc-업체-선택-시-주의사항">해외 IDC 업체 선택 시 주의사항</h2>

<h3 id="1-일본-서버라고-광고하지만-실제는-다른-위치">1. “일본 서버”라고 광고하지만 실제는 다른 위치</h3>

<p>일부 업체는 일본 서버라고 광고하지만 실제 서버가 홍콩이나 다른 위치에 있는 경우가 있습니다. 계약 전 실제 레이턴시를 테스트해보세요.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Windows</span>
ping 서버IP <span class="nt">-n</span> 10

<span class="c"># Linux/macOS</span>
ping 서버IP <span class="nt">-c</span> 10
</code></pre></div></div>

<h3 id="2-공유-ip와-ddos-블랙홀-리스크">2. 공유 IP와 DDoS 블랙홀 리스크</h3>

<p>저렴한 해외 IDC는 한 IP 블록을 여러 고객이 공유합니다. 다른 고객의 DDoS로 인해 내 서버 IP가 블랙홀 라우팅되는 피해를 받을 수 있습니다. DDoS 방어 인프라가 갖춰진 업체를 선택하세요.</p>

<h3 id="3-데이터-주권-및-법적-리스크">3. 데이터 주권 및 법적 리스크</h3>

<p>서버 위치 국가의 법률이 적용됩니다. 예를 들어, 미국 서버는 미국 정부의 요청에 의해 데이터에 접근될 수 있습니다. 민감한 데이터를 다룬다면 법적 환경이 안정적인 국가를 선택하세요.</p>

<hr />

<h2 id="tcp-80net-일본-도쿄-idc-직영">TCP-80.NET 일본 도쿄 IDC 직영</h2>

<p>TCP-80.NET은 일본 도쿄 데이터센터를 직접 운영합니다. 중간 리셀러 없이 IDC 직영으로 서버를 제공하기 때문에 품질과 가격 모두 경쟁력이 있습니다.</p>

<ul>
  <li><a href="/virtual-server/">일본 VPS</a> — 월 ₩100,000부터</li>
  <li><a href="/dedicated-server/">일본 전용서버</a> — 월 ₩300,000부터</li>
  <li><a href="/virtual-desktop/">일본 가상 데스크톱</a> — 월 ₩150,000부터</li>
  <li>DDoS 방어 기본 제공, 24시간 한국어 지원</li>
</ul>

<hr />

<h2 id="마치며">마치며</h2>

<p>해외 IDC 선택은 단순히 가격이 아니라 레이턴시, 네트워크 품질, 법적 환경, 운영 지원을 종합적으로 고려해야 합니다. 한국 기반 서비스라면 일본 도쿄 IDC가 가장 합리적인 선택입니다.</p>

<p>궁금한 점은 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 24시간 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="데이터센터" /><summary type="html"><![CDATA[해외IDC, 해외 데이터센터를 선택할 때 어디가 좋을까요? 일본·홍콩·싱가포르·미국 주요 거점별 특징과 한국 서비스에 최적화된 해외 IDC 선택법을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 데이터센터(일본 IDC)란? — 시설 구조와 선택 기준 완전 정리</title><link href="https://tcp-80.net/blog/2025/07/07/japan-idc-datacenter/" rel="alternate" type="text/html" title="일본 데이터센터(일본 IDC)란? — 시설 구조와 선택 기준 완전 정리" /><published>2025-07-07T00:00:00+09:00</published><updated>2025-07-07T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/07/07/japan-idc-datacenter</id><content type="html" xml:base="https://tcp-80.net/blog/2025/07/07/japan-idc-datacenter/"><![CDATA[<p>서버 호스팅을 알아보다 보면 “IDC”라는 단어를 자주 접하게 됩니다. IDC는 Internet Data Center의 약자로, 서버들이 실제로 위치하는 전문 시설입니다. 이 글에서는 일본 데이터센터(일본 IDC)의 구조와 선택 기준을 정리합니다.</p>

<h2 id="일본-idc란">일본 IDC란?</h2>

<p>일본 IDC(일본 인터넷 데이터센터)는 일본 내에 위치한 서버 설비 전문 시설입니다. 단순히 서버를 놓는 창고가 아니라, 다음과 같은 핵심 인프라를 갖춘 전문 시설입니다.</p>

<ul>
  <li><strong>전력 이중화</strong>: UPS(무정전 전원장치)와 비상 발전기로 정전 시에도 서버가 계속 가동</li>
  <li><strong>항온항습</strong>: 서버 과열을 방지하는 정밀 공조 시스템</li>
  <li><strong>물리 보안</strong>: 출입통제, CCTV, 24시간 경비</li>
  <li><strong>네트워크 이중화</strong>: 복수의 ISP와 연결해 단일 회선 장애 시에도 연결 유지</li>
  <li><strong>소방 설비</strong>: 서버에 무해한 가스계 소화 설비</li>
</ul>

<hr />

<h2 id="데이터센터-등급-tier">데이터센터 등급 (Tier)</h2>

<p>데이터센터 품질은 Uptime Institute의 Tier 등급으로 분류됩니다.</p>

<table>
  <thead>
    <tr>
      <th>등급</th>
      <th>연간 가동률</th>
      <th>특징</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tier 1</td>
      <td>99.671%</td>
      <td>이중화 없음, 연간 28.8시간 다운타임 허용</td>
    </tr>
    <tr>
      <td>Tier 2</td>
      <td>99.741%</td>
      <td>일부 이중화, 연간 22시간</td>
    </tr>
    <tr>
      <td>Tier 3</td>
      <td>99.982%</td>
      <td>이중화 전원·냉각, 연간 1.6시간</td>
    </tr>
    <tr>
      <td>Tier 4</td>
      <td>99.995%</td>
      <td>완전 이중화, 연간 26분</td>
    </tr>
  </tbody>
</table>

<p>상업용 서버 호스팅은 최소 <strong>Tier 3 이상</strong> 시설을 사용하는 업체를 선택하는 것이 좋습니다.</p>

<hr />

<h2 id="일본-주요-데이터센터-지역">일본 주요 데이터센터 지역</h2>

<h3 id="도쿄-tokyo">도쿄 (Tokyo)</h3>

<p>일본 최대의 IDC 밀집 지역입니다. 한국과의 해저 광케이블 연결 지점이 가까워 <strong>한국 기준 레이턴시가 가장 낮습니다</strong> (평균 20~35ms).</p>

<ul>
  <li>아시아 인터넷 교환 지점(IX) 다수 위치</li>
  <li>IIJ, NTT, KDDI 등 주요 일본 ISP 집결</li>
  <li>대규모 지진 대비 내진 설계 기준 적용</li>
</ul>

<h3 id="오사카-osaka">오사카 (Osaka)</h3>

<p>도쿄 다음으로 IDC가 많은 지역입니다. 도쿄 데이터센터의 재해복구(DR) 거점으로 활용되는 경우가 많습니다.</p>

<h3 id="후쿠오카-fukuoka">후쿠오카 (Fukuoka)</h3>

<p>한국과 가장 가까운 일본 도시 중 하나로, 일부 호스팅 업체가 운영하고 있습니다. 단, 대형 IDC는 도쿄·오사카에 비해 적습니다.</p>

<hr />

<h2 id="일본-idc-선택-시-확인-항목">일본 IDC 선택 시 확인 항목</h2>

<h3 id="1-네트워크-품질">1. 네트워크 품질</h3>

<p>일본 IDC의 네트워크 품질은 연결된 ISP와 업링크 용량에 따라 크게 달라집니다.</p>

<ul>
  <li><strong>멀티홈 구성</strong> 여부 (복수 ISP 연결)</li>
  <li><strong>BGP 라우팅</strong> 지원 여부</li>
  <li>한국으로의 <strong>직접 피어링</strong> 여부</li>
</ul>

<h3 id="2-ddos-방어-인프라">2. DDoS 방어 인프라</h3>

<p>일본 IDC를 사용하는 서버는 DDoS 공격의 표적이 되기 쉽습니다. IDC 수준의 업스트림 DDoS 클리닝 능력이 있는지 확인하세요.</p>

<p>TCP-80.NET은 일본 도쿄 IDC에서 L3/L4 DDoS 방어를 모든 서버에 기본 제공합니다.</p>

<h3 id="3-물리-서버-접근-ipmi--remote-hands">3. 물리 서버 접근 (IPMI / Remote Hands)</h3>

<p>전용서버를 사용한다면 원격에서 서버를 제어할 수 있는 <strong>IPMI(iDRAC/iLO)</strong> 접근이 필요합니다. OS 설치, BIOS 접근, 서버 리셋 등이 원격으로 가능해야 합니다.</p>

<h3 id="4-실제-위치-확인">4. 실제 위치 확인</h3>

<p>“일본 IDC”라고 광고하지만 실제로는 주변 국가에 서버를 두는 경우도 있습니다. 실제 IP 위치와 레이턴시를 직접 확인하는 것이 좋습니다.</p>

<hr />

<h2 id="tcp-80net-일본-도쿄-idc">TCP-80.NET 일본 도쿄 IDC</h2>

<p>TCP-80.NET은 일본 도쿄 데이터센터를 <strong>직접 운영</strong>하고 있습니다.</p>

<ul>
  <li><strong>위치</strong>: 일본 도쿄 소재 IDC (Tier 3+ 수준 시설)</li>
  <li><strong>전원</strong>: UPS + 비상 발전기 이중화</li>
  <li><strong>네트워크</strong>: 업링크 이중화, 멀티홈 구성</li>
  <li><strong>DDoS 방어</strong>: L3/L4 클리닝 기본 제공, <a href="/ddos-security/">고급 방어존 선택 가능</a></li>
  <li><strong>서버 관리</strong>: IPMI 기본 제공 (전용서버 기준)</li>
  <li><strong>서버 장비</strong>: Dell, HP 등 정품 벤더 서버만 사용</li>
</ul>

<p><a href="/virtual-server/">일본 VPS</a> 월 ₩100,000부터, <a href="/dedicated-server/">일본 전용서버</a> 월 ₩300,000부터 이용 가능합니다.</p>

<hr />

<h2 id="일본-idc-vs-국내-idc">일본 IDC vs 국내 IDC</h2>

<table>
  <thead>
    <tr>
      <th>구분</th>
      <th>일본 IDC</th>
      <th>국내 IDC</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>해외 사용자 레이턴시</td>
      <td>낮음 (아시아 허브)</td>
      <td>높음</td>
    </tr>
    <tr>
      <td>일본 IP 주소</td>
      <td>제공</td>
      <td>불가</td>
    </tr>
    <tr>
      <td>가격 경쟁력</td>
      <td>동급 스펙 대비 합리적</td>
      <td>상대적으로 높음</td>
    </tr>
    <tr>
      <td>언어 지원</td>
      <td>업체에 따라 다름</td>
      <td>한국어 기본</td>
    </tr>
    <tr>
      <td>DDoS 방어</td>
      <td>업체에 따라 다름</td>
      <td>업체에 따라 다름</td>
    </tr>
  </tbody>
</table>

<p>TCP-80.NET처럼 일본 IDC를 직영하면서 한국어 지원을 제공하는 업체라면 두 가지 장점을 모두 누릴 수 있습니다.</p>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 데이터센터(일본 IDC)를 선택할 때는 단순히 가격만 보지 말고, 시설 등급, 네트워크 품질, DDoS 방어 수준, 한국어 지원 여부를 종합적으로 검토하세요.</p>

<p>TCP-80.NET 일본 IDC에 대한 문의는 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 24시간 한국어로 상담해드립니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="데이터센터" /><summary type="html"><![CDATA[일본IDC, 일본 데이터센터를 선택할 때 무엇을 확인해야 할까요? 데이터센터 등급, 위치, 인프라 기준부터 TCP-80.NET 도쿄 IDC까지 상세히 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 Ubuntu 초기 보안 설정 가이드 — 서버 개설 후 바로 해야 할 것들</title><link href="https://tcp-80.net/blog/2025/06/16/japan-server-ubuntu-setup/" rel="alternate" type="text/html" title="일본 서버 Ubuntu 초기 보안 설정 가이드 — 서버 개설 후 바로 해야 할 것들" /><published>2025-06-16T00:00:00+09:00</published><updated>2025-06-16T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/06/16/japan-server-ubuntu-setup</id><content type="html" xml:base="https://tcp-80.net/blog/2025/06/16/japan-server-ubuntu-setup/"><![CDATA[<p>일본 서버호스팅으로 Ubuntu 서버를 받았다면, 서비스를 올리기 전에 반드시 초기 보안 설정을 먼저 해야 합니다. 설정 없이 서버를 오픈하면 수 시간 내에 무차별 SSH 브루트포스 공격을 받게 됩니다. 이 글에서는 Ubuntu 22.04 LTS 기준으로 일본 서버 초기 보안 설정을 단계별로 안내합니다.</p>

<h2 id="1-root-계정-비밀번호-변경-및-일반-사용자-생성">1. root 계정 비밀번호 변경 및 일반 사용자 생성</h2>

<p>서버를 받으면 즉시 root 비밀번호를 강력한 것으로 변경하고, 일상 작업용 일반 사용자를 만드세요.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># root 비밀번호 변경</span>
passwd root

<span class="c"># 새 사용자 생성 및 sudo 권한 부여</span>
adduser myuser
usermod <span class="nt">-aG</span> <span class="nb">sudo </span>myuser
</code></pre></div></div>

<hr />

<h2 id="2-시스템-패키지-업데이트">2. 시스템 패키지 업데이트</h2>

<p>OS를 받은 직후 패키지를 최신 상태로 업데이트합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update <span class="o">&amp;&amp;</span> apt upgrade <span class="nt">-y</span>
apt autoremove <span class="nt">-y</span>
</code></pre></div></div>

<hr />

<h2 id="3-ssh-포트-변경">3. SSH 포트 변경</h2>

<p>기본 SSH 포트(22번)는 전 세계 봇이 스캔하는 대상입니다. 포트를 변경하는 것만으로 자동화 공격의 99%를 차단할 수 있습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/ssh/sshd_config
</code></pre></div></div>

<p>아래 항목을 수정합니다:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Port 22222         # 원하는 포트 번호로 변경 (1024~65535)
PermitRootLogin no # root 직접 로그인 차단
PasswordAuthentication no # 패스워드 인증 비활성화 (키 인증만 허용)
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart sshd
</code></pre></div></div>

<blockquote>
  <p><strong>주의</strong>: SSH 포트를 변경하기 전에 새 포트로 방화벽을 먼저 열고, 새 세션으로 접속이 되는지 확인한 후 기존 세션을 닫으세요.</p>
</blockquote>

<hr />

<h2 id="4-ssh-키-인증-설정">4. SSH 키 인증 설정</h2>

<p>패스워드 인증 대신 SSH 키 쌍을 사용하면 브루트포스 공격에 안전합니다.</p>

<p>로컬 PC에서 키 생성:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-C</span> <span class="s2">"japan-server"</span>
</code></pre></div></div>

<p>공개 키를 서버에 등록:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-copy-id <span class="nt">-p</span> 22222 myuser@서버IP
</code></pre></div></div>

<hr />

<h2 id="5-ufw-방화벽-설정">5. UFW 방화벽 설정</h2>

<p>Ubuntu의 기본 방화벽인 UFW를 설정해 필요한 포트만 허용합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># UFW 기본 정책: 모두 차단</span>
ufw default deny incoming
ufw default allow outgoing

<span class="c"># SSH 포트 허용 (변경한 포트 번호로)</span>
ufw allow 22222/tcp

<span class="c"># 웹 서비스 포트 허용</span>
ufw allow 80/tcp
ufw allow 443/tcp

<span class="c"># UFW 활성화</span>
ufw <span class="nb">enable
</span>ufw status verbose
</code></pre></div></div>

<hr />

<h2 id="6-fail2ban-설치--반복-접속-시도-자동-차단">6. Fail2Ban 설치 — 반복 접속 시도 자동 차단</h2>

<p>Fail2Ban은 SSH, Nginx 등에 반복 실패한 IP를 자동으로 차단합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>fail2ban <span class="nt">-y</span>
</code></pre></div></div>

<p>기본 설정 파일 복사:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp</span> /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
</code></pre></div></div>

<p>SSH 보호 설정 추가:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[sshd]</span><span class="w">
</span><span class="py">enabled</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">true</span>
<span class="py">port</span><span class="w">    </span><span class="p">=</span><span class="w"> </span><span class="s">22222</span>
<span class="py">maxretry</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">3</span>
<span class="py">bantime</span><span class="w">  </span><span class="p">=</span><span class="w"> </span><span class="s">3600</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl <span class="nb">enable </span>fail2ban
systemctl start fail2ban
</code></pre></div></div>

<hr />

<h2 id="7-자동-보안-업데이트-설정">7. 자동 보안 업데이트 설정</h2>

<p>운영 중에 보안 패치를 놓치지 않도록 자동 업데이트를 설정합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>unattended-upgrades <span class="nt">-y</span>
dpkg-reconfigure <span class="nt">--priority</span><span class="o">=</span>low unattended-upgrades
</code></pre></div></div>

<hr />

<h2 id="8-타임존-및-ntp-설정">8. 타임존 및 NTP 설정</h2>

<p>로그 분석을 위해 타임존을 맞추는 것도 중요합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>timedatectl set-timezone Asia/Tokyo  <span class="c"># 일본 서버이므로 도쿄 시간대</span>
<span class="c"># 또는 한국 시간대로 맞추려면:</span>
timedatectl set-timezone Asia/Seoul

apt <span class="nb">install </span>chrony <span class="nt">-y</span>
systemctl <span class="nb">enable </span>chrony
</code></pre></div></div>

<hr />

<h2 id="보안-설정-체크리스트">보안 설정 체크리스트</h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>완료 여부</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>root 비밀번호 변경</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>일반 사용자 생성</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>시스템 업데이트</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>SSH 포트 변경</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>root SSH 로그인 차단</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>SSH 키 인증 설정</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>UFW 방화벽 활성화</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>Fail2Ban 설치</td>
      <td>☐</td>
    </tr>
    <tr>
      <td>자동 보안 업데이트</td>
      <td>☐</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="마치며">마치며</h2>

<p>위 설정을 완료하면 일본 서버의 기본 보안 수준이 크게 높아집니다. TCP-80.NET은 서버 개설 후 초기 보안 설정에 대한 한국어 기술 지원을 제공합니다. 설정 과정에서 막히는 부분이 있다면 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 언제든지 문의하세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="보안" /><summary type="html"><![CDATA[일본 서버호스팅 후 Ubuntu 서버를 처음 받았을 때 반드시 해야 하는 초기 보안 설정을 순서대로 정리했습니다. SSH 포트 변경부터 방화벽 설정까지.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-security.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-security.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 전용서버 vs VPS 철저 비교 — 어떤 서버를 선택해야 할까?</title><link href="https://tcp-80.net/blog/2025/06/02/japan-dedicated-vs-vps/" rel="alternate" type="text/html" title="일본 전용서버 vs VPS 철저 비교 — 어떤 서버를 선택해야 할까?" /><published>2025-06-02T00:00:00+09:00</published><updated>2025-06-02T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/06/02/japan-dedicated-vs-vps</id><content type="html" xml:base="https://tcp-80.net/blog/2025/06/02/japan-dedicated-vs-vps/"><![CDATA[<p>일본 서버호스팅을 처음 알아볼 때 가장 많이 하는 질문이 “전용서버와 VPS 중 뭘 써야 하나요?”입니다. 둘 다 일본 데이터센터에 위치한 서버지만, 구조와 성능, 가격 면에서 큰 차이가 있습니다. 이 글에서는 일본 전용서버와 VPS를 5가지 기준으로 철저히 비교합니다.</p>

<h2 id="핵심-차이-하드웨어-공유-여부">핵심 차이: 하드웨어 공유 여부</h2>

<p><strong>VPS(가상 서버)</strong>는 물리 서버 한 대를 가상화 기술로 여러 개의 독립 서버처럼 나눈 것입니다. CPU, RAM, 스토리지를 다른 VPS 사용자와 물리적으로 공유하지만, 논리적으로는 독립된 환경입니다.</p>

<p><strong>전용서버(Dedicated Server)</strong>는 물리 서버 한 대 전체를 혼자 사용합니다. CPU, RAM, 스토리지, 네트워크 포트를 단독 점유하므로 리소스 경합이 없습니다.</p>

<hr />

<h2 id="비교-1-성능">비교 1: 성능</h2>

<h3 id="vps-성능">VPS 성능</h3>
<ul>
  <li>CPU, RAM, 디스크 I/O를 동일 물리 서버의 다른 VPS와 공유</li>
  <li>이웃 VPS가 과부하 상태이면 내 서버 성능에 영향 가능 (“노이지 네이버” 문제)</li>
  <li>소규모~중규모 웹 서비스에는 충분한 성능</li>
</ul>

<h3 id="전용서버-성능">전용서버 성능</h3>
<ul>
  <li>물리 CPU 코어 전체를 단독 사용 (Intel Xeon 멀티코어 기준)</li>
  <li>RAM 32GB~128GB를 단독 점유</li>
  <li>NVMe SSD I/O 성능을 최대로 활용</li>
  <li>예측 가능한 안정적인 성능</li>
</ul>

<p><strong>결론</strong>: 트래픽 급증이나 고성능 데이터베이스가 필요한 경우 전용서버가 압도적으로 유리합니다.</p>

<hr />

<h2 id="비교-2-가격">비교 2: 가격</h2>

<table>
  <thead>
    <tr>
      <th>구분</th>
      <th>VPS</th>
      <th>전용서버</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>월 비용</td>
      <td>₩100,000~</td>
      <td>₩300,000~</td>
    </tr>
    <tr>
      <td>초기 비용</td>
      <td>없음</td>
      <td>없음</td>
    </tr>
    <tr>
      <td>환경 구성</td>
      <td>즉시 가능</td>
      <td>1~2일 내 개설</td>
    </tr>
  </tbody>
</table>

<p>VPS는 소규모 서비스 운영자에게 비용 효율적입니다. 전용서버는 비용이 높지만, 성능 당 단가로 계산하면 클라우드(AWS, GCP 등) 대비 훨씬 저렴한 경우가 많습니다.</p>

<hr />

<h2 id="비교-3-보안">비교 3: 보안</h2>

<h3 id="vps-보안">VPS 보안</h3>
<ul>
  <li>하이퍼바이저 레벨에서 격리되어 다른 VPS와 데이터 격리</li>
  <li>커널 취약점이 있을 경우 호스트 서버 영향 가능성 존재</li>
  <li>운영체제 레벨 보안은 사용자가 직접 관리</li>
</ul>

<h3 id="전용서버-보안">전용서버 보안</h3>
<ul>
  <li>물리적으로 완전 격리된 환경</li>
  <li>다른 사용자와 커널·하드웨어를 공유하지 않음</li>
  <li>금융, 의료, 법률 등 보안 규정이 엄격한 서비스에 필수</li>
</ul>

<hr />

<h2 id="비교-4-확장성">비교 4: 확장성</h2>

<p><strong>VPS</strong>: 플랜 업그레이드로 CPU·RAM을 늘릴 수 있지만, 물리 서버 한계 내에서만 가능합니다.</p>

<p><strong>전용서버</strong>: 서버 자체를 교체하거나 RAM·디스크를 물리적으로 추가해야 합니다. 수직 확장에 한계가 있어 대규모 트래픽은 로드밸런서를 통한 수평 확장이 필요합니다.</p>

<hr />

<h2 id="비교-5-관리-난이도">비교 5: 관리 난이도</h2>

<p>두 서버 모두 기본적으로 OS만 설치된 상태로 제공되므로, Nginx·Apache·데이터베이스 등 필요한 소프트웨어는 직접 설치·관리해야 합니다. 관리가 부담된다면 TCP-80.NET 기술 지원을 통해 초기 설정을 도움받을 수 있습니다.</p>

<hr />

<h2 id="어떤-서버를-선택해야-할까">어떤 서버를 선택해야 할까?</h2>

<h3 id="vps가-적합한-경우">VPS가 적합한 경우</h3>
<ul>
  <li>월 방문자 10만 이하의 웹사이트, 블로그</li>
  <li>개발 환경, 스테이징 서버</li>
  <li>스타트업 초기 단계 서비스</li>
  <li>Node.js API, 소규모 데이터베이스</li>
</ul>

<h3 id="전용서버가-적합한-경우">전용서버가 적합한 경우</h3>
<ul>
  <li>게임서버 (MMO, FPS 등 50인 이상)</li>
  <li>대규모 이커머스, 고트래픽 웹 서비스</li>
  <li>영상 스트리밍, 파일 스토리지 서버</li>
  <li>금융·결제 시스템처럼 높은 보안이 필요한 환경</li>
</ul>

<hr />

<h2 id="tcp-80net-일본-서버-플랜">TCP-80.NET 일본 서버 플랜</h2>

<ul>
  <li><strong><a href="/virtual-server/">일본 VPS</a></strong>: 1 vCore~4 vCore, 월 ₩100,000부터</li>
  <li><strong><a href="/dedicated-server/">일본 전용서버</a></strong>: Intel Xeon 5개 플랜, 월 ₩300,000부터</li>
</ul>

<p>서비스 규모와 예산에 맞는 서버 선택이 어렵다면 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요. 용도에 맞는 최적의 플랜을 안내해 드립니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 전용서버와 VPS의 차이점을 성능, 가격, 보안, 확장성 측면에서 상세 비교합니다. 서비스 규모와 예산에 맞는 선택을 도와드립니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">해외서버호스팅 완벽 가이드 — 해외서버를 쓰는 이유와 운영 노하우</title><link href="https://tcp-80.net/blog/2025/05/12/overseas-server-hosting/" rel="alternate" type="text/html" title="해외서버호스팅 완벽 가이드 — 해외서버를 쓰는 이유와 운영 노하우" /><published>2025-05-12T00:00:00+09:00</published><updated>2025-05-12T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/05/12/overseas-server-hosting</id><content type="html" xml:base="https://tcp-80.net/blog/2025/05/12/overseas-server-hosting/"><![CDATA[<p>해외서버호스팅에 관심을 갖게 되는 계기는 다양합니다. 국내 서버보다 저렴한 비용, 해외 IP 주소가 필요한 업무, 특정 국가 타겟의 서비스 운영 등. 이 글에서는 해외서버를 선택하는 이유와 해외서버 운영 시 반드시 알아야 할 내용을 정리합니다.</p>

<h2 id="해외서버를-쓰는-주요-이유">해외서버를 쓰는 주요 이유</h2>

<h3 id="1-해외-ip-주소-필요">1. 해외 IP 주소 필요</h3>

<p>가장 흔한 이유입니다. 일본, 미국, 홍콩, 싱가포르 등 특정 국가의 IP가 필요한 경우:</p>

<ul>
  <li>해당 국가 전용 스트리밍/미디어 서비스 이용</li>
  <li>현지 인터넷 뱅킹·핀테크 서비스 연동</li>
  <li>해당 국가 광고 타겟팅 및 마케팅 운영</li>
  <li>현지 사용자 대상 서비스의 지연 없는 응답</li>
</ul>

<h3 id="2-해외-타겟-서비스-운영">2. 해외 타겟 서비스 운영</h3>

<p>서비스 대상 사용자가 해외에 있다면 그 국가 가까운 곳에 서버를 두는 것이 기본입니다. 물리적으로 가까울수록 레이턴시가 낮아지고 사용자 경험이 향상됩니다.</p>

<h3 id="3-국내-규제-우회-또는-회피">3. 국내 규제 우회 또는 회피</h3>

<p>일부 서비스는 국내 규제 환경보다 해외 데이터센터 운영이 법적·기술적으로 유리한 경우가 있습니다.</p>

<h3 id="4-비용-효율">4. 비용 효율</h3>

<p>일본, 홍콩, 싱가포르 등 아시아 주요 거점의 해외서버호스팅은 국내 대비 동급 스펙을 더 합리적인 가격에 이용할 수 있는 경우가 많습니다.</p>

<hr />

<h2 id="아시아-해외서버-지역별-비교">아시아 해외서버 지역별 비교</h2>

<p>한국인이 가장 많이 사용하는 아시아 해외서버 거점을 비교합니다.</p>

<table>
  <thead>
    <tr>
      <th>지역</th>
      <th>서울~레이턴시</th>
      <th>특징</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>일본 도쿄</strong></td>
      <td>20~35ms</td>
      <td>가장 가깝고 안정적, 한국어 지원 업체 존재</td>
    </tr>
    <tr>
      <td>홍콩</td>
      <td>40~60ms</td>
      <td>아시아 허브, 중국 접근성 좋음</td>
    </tr>
    <tr>
      <td>싱가포르</td>
      <td>70~100ms</td>
      <td>동남아 거점, 글로벌 CDN 허브</td>
    </tr>
    <tr>
      <td>미국 서부</td>
      <td>140~180ms</td>
      <td>규모 큰 글로벌 서비스</td>
    </tr>
    <tr>
      <td>유럽</td>
      <td>230~280ms</td>
      <td>유럽 타겟 서비스</td>
    </tr>
  </tbody>
</table>

<p><strong>한국 사용자 또는 한국 기반 서비스를 운영한다면 일본 도쿄 서버가 가장 유리합니다.</strong> 거리가 가장 가깝고, 한국어 지원 호스팅 업체가 있어 커뮤니케이션도 편리합니다.</p>

<hr />

<h2 id="해외서버호스팅-종류">해외서버호스팅 종류</h2>

<h3 id="해외-vps-가상-서버">해외 VPS (가상 서버)</h3>

<p>가장 많이 사용되는 해외서버 유형입니다. 물리 서버를 가상화로 분할해 사용하며, 독립된 OS 환경을 제공합니다.</p>

<ul>
  <li><strong>장점</strong>: 합리적인 가격, 즉시 개설, 다양한 OS</li>
  <li><strong>단점</strong>: 물리 서버 리소스를 타 VPS와 공유</li>
  <li><strong>적합한 용도</strong>: 웹 서비스, API 서버, 소규모 DB</li>
</ul>

<h3 id="해외-전용서버-dedicated-server">해외 전용서버 (Dedicated Server)</h3>

<p>물리 서버 전체를 단독으로 사용하는 방식입니다.</p>

<ul>
  <li><strong>장점</strong>: 최고 성능, 리소스 경합 없음, IPMI 접근</li>
  <li><strong>단점</strong>: VPS 대비 높은 비용</li>
  <li><strong>적합한 용도</strong>: 게임서버, 대규모 트래픽 서비스, 고성능 DB</li>
</ul>

<p>TCP-80.NET은 일본 도쿄 데이터센터에서 <a href="/virtual-server/">VPS</a>와 <a href="/dedicated-server/">전용서버</a>를 직영으로 운영합니다.</p>

<hr />

<h2 id="해외서버-운영-시-주의사항">해외서버 운영 시 주의사항</h2>

<h3 id="1-시간대-차이">1. 시간대 차이</h3>

<p>일본은 한국과 동일한 시간대(UTC+9)이므로 큰 문제가 없습니다. 단, 미국이나 유럽 서버는 시간대 차이로 인해 장애 대응 시간이 늦어질 수 있습니다.</p>

<h3 id="2-ddos-공격-대응">2. DDoS 공격 대응</h3>

<p>해외서버는 국내 서버보다 DDoS 공격에 더 많이 노출되는 경향이 있습니다. 특히 게임서버, 트레이딩 관련 서비스가 주요 타겟이 됩니다. 호스팅 업체의 DDoS 방어 수준을 반드시 확인하세요.</p>

<p>TCP-80.NET은 모든 서버에 L3/L4 DDoS 방어를 무료로 기본 제공하며, 고급 보호는 <a href="/ddos-security/">DDoS 방어 서비스</a>로 추가 가능합니다.</p>

<h3 id="3-한국어-지원-여부">3. 한국어 지원 여부</h3>

<p>해외서버 운영 중 장애가 발생하면 빠른 소통이 중요합니다. 영어로만 지원하는 해외 업체는 장애 발생 시 대응이 느릴 수 있습니다. 한국어 지원 가능한 호스팅 업체를 선택하는 것이 좋습니다.</p>

<h3 id="4-데이터-백업">4. 데이터 백업</h3>

<p>해외서버라도 정기 백업은 필수입니다. rsync 또는 업체 제공 스냅샷 기능을 활용하세요. TCP-80.NET은 내부 네트워크를 이용한 무료 백업 서비스를 제공합니다.</p>

<h3 id="5-보안-초기-설정">5. 보안 초기 설정</h3>

<p>해외서버를 개설하자마자 SSH 포트 변경, 방화벽(UFW) 설정, fail2ban 설치를 완료하세요. 초기 설정을 미루면 그 사이 자동화 공격에 노출될 수 있습니다.</p>

<hr />

<h2 id="해외서버호스팅-선택-체크리스트">해외서버호스팅 선택 체크리스트</h2>

<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />서버 위치가 타겟 사용자와 가까운가?</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />DDoS 방어가 기본 포함되는가?</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />한국어 지원이 가능한가?</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />OS 선택이 자유로운가?</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />환불 정책이 있는가?</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />업타임 SLA가 명시되어 있는가?</li>
</ul>

<hr />

<h2 id="마치며">마치며</h2>

<p>해외서버호스팅은 목적에 따라 지역과 서버 유형을 신중하게 선택해야 합니다. 한국 사용자를 대상으로 하거나 일본 IP가 필요한 서비스라면 일본 도쿄 서버가 가장 합리적인 선택입니다.</p>

<p>TCP-80.NET은 일본 도쿄 데이터센터를 직영하며 24시간 한국어 지원을 제공합니다. 해외서버 선택에 대한 상담은 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="해외서버" /><summary type="html"><![CDATA[해외서버호스팅이 왜 필요할까요? 해외서버를 선택하는 이유, 지역별 비교, 해외서버 운영 시 주의사항까지 한번에 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버호스팅 업체 선택 기준 5가지 — 후회 없는 선택을 위한 체크리스트</title><link href="https://tcp-80.net/blog/2025/04/07/japan-server-hosting-selection-guide/" rel="alternate" type="text/html" title="일본 서버호스팅 업체 선택 기준 5가지 — 후회 없는 선택을 위한 체크리스트" /><published>2025-04-07T00:00:00+09:00</published><updated>2025-04-07T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/04/07/japan-server-hosting-selection-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2025/04/07/japan-server-hosting-selection-guide/"><![CDATA[<p>일본 서버호스팅 시장에는 다양한 업체가 존재합니다. 가격만 보고 선택했다가 낮은 품질의 서비스를 경험하거나, 장애 발생 시 한국어 지원이 안 돼 곤란을 겪는 경우가 많습니다. 이 글에서는 일본 서버호스팅 업체를 선택할 때 반드시 확인해야 할 5가지 기준을 구체적으로 설명합니다.</p>

<h2 id="기준-1-데이터센터-위치와-네트워크-품질">기준 1: 데이터센터 위치와 네트워크 품질</h2>

<p>일본 서버호스팅이라고 해도 실제 서버 위치는 다양합니다. 도쿄, 오사카, 후쿠오카 등 여러 도시에 데이터센터가 있으며, <strong>한국에서의 레이턴시는 도쿄가 가장 낮습니다.</strong></p>

<p>확인해야 할 사항:</p>
<ul>
  <li><strong>데이터센터 위치</strong>: 도쿄 도심 또는 인근 IDC가 유리</li>
  <li><strong>네트워크 이중화</strong>: 단일 회선인지, 이중화된 100G 이상 회선인지</li>
  <li><strong>Tier 등급</strong>: Tier III 이상 데이터센터는 99.982% 가용성 보장</li>
  <li><strong>업스트림 사업자</strong>: KDDI, NTT 등 주요 통신사 직접 연결 여부</li>
</ul>

<p>실제 핑 테스트를 직접 해보는 것이 가장 정확합니다. 업체에 테스트 IP를 요청하거나 무료 트라이얼 서버로 레이턴시를 측정해보세요.</p>

<hr />

<h2 id="기준-2-ddos-방어-서비스-포함-여부">기준 2: DDoS 방어 서비스 포함 여부</h2>

<p>일본 서버에서 웹 서비스나 게임서버를 운영하면 DDoS 공격을 받을 가능성이 있습니다. DDoS 방어가 포함되어 있지 않은 서버는 공격 한 번에 서비스 전체가 다운될 수 있습니다.</p>

<p>확인해야 할 사항:</p>
<ul>
  <li><strong>기본 DDoS 방어 포함 여부</strong>: 추가 비용 없이 기본 제공되는지</li>
  <li><strong>방어 용량</strong>: 최소 수십 Gbps 이상의 완화 용량</li>
  <li><strong>방어 레이어</strong>: L3/L4 네트워크 레이어 방어가 기본, WAF(L7)는 추가 옵션</li>
  <li><strong>대응 시간</strong>: 공격 감지 후 차단까지 걸리는 시간 (자동 vs 수동)</li>
</ul>

<p>TCP-80.NET은 모든 서버에 네트워크 레이어 DDoS 방어를 무료로 기본 제공합니다. 더 강력한 보호가 필요하다면 <a href="/ddos-security/">전용 DDoS 방어 서비스</a>를 이용할 수 있습니다.</p>

<hr />

<h2 id="기준-3-한국어-지원과-응답-속도">기준 3: 한국어 지원과 응답 속도</h2>

<p>일본 서버호스팅 업체 중 상당수는 일본어나 영어로만 지원합니다. 기술적인 문제가 생겼을 때 언어 장벽으로 인해 해결이 늦어지면 서비스 장애가 길어질 수 있습니다.</p>

<p>확인해야 할 사항:</p>
<ul>
  <li><strong>지원 언어</strong>: 한국어 지원 여부</li>
  <li><strong>지원 채널</strong>: 이메일만 있는지, 실시간 채팅·텔레그램이 있는지</li>
  <li><strong>응답 시간</strong>: 평균 응답 시간이 수 시간 이내인지</li>
  <li><strong>지원 시간</strong>: 24시간 365일 대응인지, 업무 시간만 대응인지</li>
</ul>

<p>TCP-80.NET은 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>을 통해 24시간 365일 한국어 기술 지원을 제공합니다.</p>

<hr />

<h2 id="기준-4-서버-하드웨어-품질">기준 4: 서버 하드웨어 품질</h2>

<p>가격이 저렴한 일부 업체는 노후화된 서버나 저가 화이트박스 서버를 사용합니다. 하드웨어 품질은 서비스 안정성과 직결됩니다.</p>

<p>확인해야 할 사항:</p>
<ul>
  <li><strong>서버 브랜드</strong>: Dell, HP(HPE), Supermicro 등 검증된 벤더 제품인지</li>
  <li><strong>CPU 세대</strong>: 최신 인텔 Xeon 또는 AMD EPYC 계열인지</li>
  <li><strong>스토리지 유형</strong>: HDD 대신 NVMe SSD 또는 SATA SSD 사용 여부</li>
  <li><strong>IPMI 제공</strong>: 하드웨어 원격 관리 인터페이스 기본 포함 여부</li>
</ul>

<p>TCP-80.NET은 Dell, HP 등 정품 벤더 서버만을 사용하며, 전용서버에는 IPMI가 기본 포함됩니다.</p>

<hr />

<h2 id="기준-5-환불-정책과-계약-조건">기준 5: 환불 정책과 계약 조건</h2>

<p>서비스가 기대에 미치지 못할 때 환불을 받을 수 있는지 확인하세요. 계약 기간이 너무 길거나 환불 정책이 불명확한 업체는 피하는 것이 좋습니다.</p>

<p>확인해야 할 사항:</p>
<ul>
  <li><strong>환불 기간</strong>: 최소 7일 이상의 환불 보장 기간 제공 여부</li>
  <li><strong>위약금</strong>: 중도 해지 시 위약금 여부</li>
  <li><strong>계약 기간</strong>: 월 단위 계약인지, 장기 선불 할인만 있는지</li>
  <li><strong>서비스 수준 협약(SLA)</strong>: 가동률 보장 조건과 보상 기준</li>
</ul>

<p>TCP-80.NET은 서비스 시작일로부터 <a href="/return-policy/">7일 이내 전액 환불</a>을 보장하며, 위약금이 없습니다.</p>

<hr />

<h2 id="체크리스트-요약">체크리스트 요약</h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>확인 포인트</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>데이터센터 위치</td>
      <td>도쿄 + 네트워크 이중화</td>
    </tr>
    <tr>
      <td>DDoS 방어</td>
      <td>기본 무료 포함 여부</td>
    </tr>
    <tr>
      <td>한국어 지원</td>
      <td>24시간 실시간 대응</td>
    </tr>
    <tr>
      <td>서버 하드웨어</td>
      <td>정품 벤더, NVMe SSD</td>
    </tr>
    <tr>
      <td>환불 정책</td>
      <td>7일+ 전액 환불 보장</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버호스팅 업체를 선택할 때는 단순히 가격만 비교하지 말고, 위 5가지 기준을 종합적으로 검토하세요. 특히 DDoS 방어와 한국어 지원은 나중에 후회하지 않기 위해 반드시 미리 확인해야 합니다.</p>

<p>서버 선택에 대해 궁금하신 점은 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅 업체를 선택할 때 반드시 확인해야 할 5가지 기준을 정리했습니다. 데이터센터 위치, DDoS 방어, 한국어 지원 여부 등을 꼼꼼히 비교하세요.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버운영 실전 가이드 — 초기 설정부터 보안까지</title><link href="https://tcp-80.net/blog/2025/03/10/japan-server-operation/" rel="alternate" type="text/html" title="일본 서버운영 실전 가이드 — 초기 설정부터 보안까지" /><published>2025-03-10T00:00:00+09:00</published><updated>2025-03-10T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/03/10/japan-server-operation</id><content type="html" xml:base="https://tcp-80.net/blog/2025/03/10/japan-server-operation/"><![CDATA[<p>일본 서버를 처음 개설하고 나면, 막막함부터 느끼는 경우가 많습니다. OS 설치 후 아무것도 없는 터미널 화면. 이 글은 일본 서버운영을 처음 시작하는 분들을 위한 단계별 실전 가이드입니다.</p>

<h2 id="1단계--ssh-접속-및-초기-보안-설정">1단계 — SSH 접속 및 초기 보안 설정</h2>

<p>서버를 개설하면 루트(root) 계정과 초기 비밀번호로 SSH 접속이 가능합니다. 가장 먼저 해야 할 일은 보안 강화입니다.</p>

<h3 id="루트-비밀번호-변경">루트 비밀번호 변경</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>passwd root
</code></pre></div></div>

<h3 id="일반-사용자-계정-생성">일반 사용자 계정 생성</h3>

<p>root 계정으로 직접 서버를 운영하는 것은 보안상 좋지 않습니다. 별도 계정을 만들고 sudo 권한을 부여하세요.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adduser myuser
usermod <span class="nt">-aG</span> <span class="nb">sudo </span>myuser
</code></pre></div></div>

<h3 id="ssh-포트-변경">SSH 포트 변경</h3>

<p>기본 22번 포트는 자동화된 공격 대상이 됩니다. 다른 포트로 변경하세요.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/ssh/sshd_config 편집</span>
Port 2222   <span class="c"># 원하는 포트 번호로 변경</span>

systemctl restart sshd
</code></pre></div></div>

<h3 id="ssh-키-인증-설정">SSH 키 인증 설정</h3>

<p>비밀번호 대신 SSH 키 인증을 사용하면 훨씬 안전합니다. 로컬 PC에서 키를 생성하고 서버에 등록하세요.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 로컬 PC에서 실행</span>
ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-C</span> <span class="s2">"myserver"</span>
ssh-copy-id <span class="nt">-p</span> 2222 myuser@서버IP
</code></pre></div></div>

<hr />

<h2 id="2단계--방화벽ufw-설정">2단계 — 방화벽(UFW) 설정</h2>

<p>일본 서버운영에서 방화벽은 필수입니다. Ubuntu 기준 UFW를 사용합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>ufw <span class="nt">-y</span>

<span class="c"># 기본 정책: 모든 인바운드 차단, 아웃바운드 허용</span>
ufw default deny incoming
ufw default allow outgoing

<span class="c"># 필요한 포트만 열기</span>
ufw allow 2222/tcp   <span class="c"># SSH (변경한 포트)</span>
ufw allow 80/tcp     <span class="c"># HTTP</span>
ufw allow 443/tcp    <span class="c"># HTTPS</span>

ufw <span class="nb">enable
</span>ufw status verbose
</code></pre></div></div>

<hr />

<h2 id="3단계--패키지-업데이트-및-자동-보안-업데이트">3단계 — 패키지 업데이트 및 자동 보안 업데이트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update <span class="o">&amp;&amp;</span> apt upgrade <span class="nt">-y</span>

<span class="c"># 보안 업데이트 자동 적용</span>
apt <span class="nb">install </span>unattended-upgrades <span class="nt">-y</span>
dpkg-reconfigure <span class="nt">--priority</span><span class="o">=</span>low unattended-upgrades
</code></pre></div></div>

<hr />

<h2 id="4단계--서비스-설치">4단계 — 서비스 설치</h2>

<p>일본 서버에서 많이 사용하는 스택별 설치 예시입니다.</p>

<h3 id="nginx-웹서버">Nginx (웹서버)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>nginx <span class="nt">-y</span>
systemctl <span class="nb">enable </span>nginx
systemctl start nginx
</code></pre></div></div>

<h3 id="nodejs-최신-lts">Node.js (최신 LTS)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-fsSL</span> https://deb.nodesource.com/setup_lts.x | bash -
apt <span class="nb">install </span>nodejs <span class="nt">-y</span>
</code></pre></div></div>

<h3 id="docker">Docker</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-fsSL</span> https://get.docker.com | sh
systemctl <span class="nb">enable </span>docker
</code></pre></div></div>

<hr />

<h2 id="5단계--ddos-대응">5단계 — DDoS 대응</h2>

<p>일본 서버운영에서 가장 자주 겪는 문제 중 하나가 DDoS 공격입니다. TCP-80.NET은 모든 서버에 네트워크 레이어(L3/L4) DDoS 방어를 기본 제공하지만, 응용 계층(L7) 공격에는 추가 대응이 필요합니다.</p>

<h3 id="nginx-레이트-리밋-설정">Nginx 레이트 리밋 설정</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/nginx.conf</span>
<span class="k">http</span> <span class="p">{</span>
    <span class="kn">limit_req_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=req_limit:10m</span> <span class="s">rate=10r/s</span><span class="p">;</span>

    <span class="kn">server</span> <span class="p">{</span>
        <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
            <span class="kn">limit_req</span> <span class="s">zone=req_limit</span> <span class="s">burst=20</span> <span class="s">nodelay</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="fail2ban-설치">fail2ban 설치</h3>

<p>반복 로그인 실패를 자동으로 차단합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>fail2ban <span class="nt">-y</span>
systemctl <span class="nb">enable </span>fail2ban
</code></pre></div></div>

<p>더 강력한 DDoS 보호가 필요하다면 <a href="/ddos-security/">전용 DDoS 방어 서비스</a>를 이용하세요.</p>

<hr />

<h2 id="6단계--모니터링-설정">6단계 — 모니터링 설정</h2>

<p>서버 상태를 주기적으로 확인하는 것이 안정적인 일본 서버운영의 핵심입니다.</p>

<h3 id="htop-설치-실시간-리소스-모니터링">htop 설치 (실시간 리소스 모니터링)</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>htop <span class="nt">-y</span>
htop
</code></pre></div></div>

<h3 id="디스크-사용량-확인">디스크 사용량 확인</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">df</span> <span class="nt">-h</span>
<span class="nb">du</span> <span class="nt">-sh</span> /var/log/<span class="k">*</span>
</code></pre></div></div>

<h3 id="로그-모니터링">로그 모니터링</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Nginx 접속 로그 실시간 확인</span>
<span class="nb">tail</span> <span class="nt">-f</span> /var/log/nginx/access.log

<span class="c"># 시스템 로그</span>
journalctl <span class="nt">-f</span>
</code></pre></div></div>

<hr />

<h2 id="일본-서버운영-체크리스트">일본 서버운영 체크리스트</h2>

<p>서버를 처음 개설하면 아래 항목을 순서대로 완료하세요.</p>

<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />root 비밀번호 변경</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />일반 사용자 계정 생성 및 sudo 권한 부여</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />SSH 포트 변경 및 키 인증 설정</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />UFW 방화벽 설정 (필요한 포트만 개방)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />패키지 전체 업데이트</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />자동 보안 업데이트 활성화</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />fail2ban 설치</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />서비스(Nginx/Apache/Node.js 등) 설치 및 설정</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />로그 모니터링 설정</li>
</ul>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버운영은 처음에 설정할 게 많아 보이지만, 기본 보안과 방화벽만 제대로 갖추면 이후 운영은 크게 어렵지 않습니다. TCP-80.NET은 서버 개설 후 OS 설치, 초기 설정까지 텔레그램으로 24시간 한국어 지원을 제공합니다.</p>

<p>서버 설정에 대한 문의는 <a href="https://t.me/tcp80net">@tcp80net</a>으로 연락해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버운영" /><summary type="html"><![CDATA[일본 서버를 처음 개설했다면? SSH 초기 설정, 방화벽 구성, DDoS 대응까지 일본 서버운영의 기본을 단계별로 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 서버 워드프레스 설치 및 최적화 완전 가이드</title><link href="https://tcp-80.net/blog/2025/02/10/japan-server-wordpress-guide/" rel="alternate" type="text/html" title="일본 서버 워드프레스 설치 및 최적화 완전 가이드" /><published>2025-02-10T00:00:00+09:00</published><updated>2025-02-10T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/02/10/japan-server-wordpress-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2025/02/10/japan-server-wordpress-guide/"><![CDATA[<p>일본 서버에 워드프레스를 운영하면 한국 및 아시아 방문자 기준으로 빠른 응답 속도를 기대할 수 있습니다. 이 글에서는 일본 서버호스팅 환경(Ubuntu 22.04 LTS, Nginx, PHP-FPM, MariaDB)에서 워드프레스를 설치하고 성능을 최적화하는 방법을 단계별로 설명합니다.</p>

<h2 id="왜-일본-서버에-워드프레스를-운영하나요">왜 일본 서버에 워드프레스를 운영하나요?</h2>

<p>한국에서 일본 서버까지의 왕복 지연은 평균 20~30ms입니다. 국내 일부 데이터센터보다 오히려 빠른 경우도 있으며, 일본 및 동남아시아 방문자까지 커버할 수 있다는 장점이 있습니다.</p>

<p>주요 이점:</p>
<ul>
  <li><strong>낮은 레이턴시</strong>: 한·일 간 20~30ms RTT</li>
  <li><strong>일본 IP 주소</strong>: 일본 대상 마케팅·SEO에 유리</li>
  <li><strong>안정적인 인프라</strong>: 이중화 전력·네트워크 환경</li>
  <li><strong>DDoS 방어 기본 포함</strong>: 봇 트래픽·공격으로부터 워드프레스 보호</li>
</ul>

<hr />

<h2 id="1단계-서버-기본-환경-준비">1단계: 서버 기본 환경 준비</h2>

<h3 id="패키지-업데이트">패키지 업데이트</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update <span class="o">&amp;&amp;</span> apt upgrade <span class="nt">-y</span>
</code></pre></div></div>

<h3 id="nginx-설치">Nginx 설치</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>nginx <span class="nt">-y</span>
systemctl <span class="nb">enable </span>nginx
systemctl start nginx
</code></pre></div></div>

<hr />

<h2 id="2단계-php-fpm-설치">2단계: PHP-FPM 설치</h2>

<p>워드프레스는 PHP 8.1 이상을 권장합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>php8.1-fpm php8.1-mysql php8.1-curl php8.1-gd <span class="se">\</span>
  php8.1-mbstring php8.1-xml php8.1-zip php8.1-bcmath <span class="nt">-y</span>
</code></pre></div></div>

<p>PHP-FPM 설정에서 워드프레스 성능에 영향을 주는 값을 조정합니다:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">; /etc/php/8.1/fpm/php.ini
</span><span class="py">upload_max_filesize</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">64M</span>
<span class="py">post_max_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">64M</span>
<span class="py">memory_limit</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">256M</span>
<span class="py">max_execution_time</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">120</span>
</code></pre></div></div>

<hr />

<h2 id="3단계-mariadb-설치-및-데이터베이스-생성">3단계: MariaDB 설치 및 데이터베이스 생성</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>mariadb-server <span class="nt">-y</span>
mysql_secure_installation
</code></pre></div></div>

<p>워드프레스용 데이터베이스 생성:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">wordpress_db</span> <span class="nb">CHARACTER</span> <span class="k">SET</span> <span class="n">utf8mb4</span> <span class="k">COLLATE</span> <span class="n">utf8mb4_unicode_ci</span><span class="p">;</span>
<span class="k">CREATE</span> <span class="k">USER</span> <span class="s1">'wp_user'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="s1">'강력한패스워드'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">PRIVILEGES</span> <span class="k">ON</span> <span class="n">wordpress_db</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">'wp_user'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
<span class="n">FLUSH</span> <span class="k">PRIVILEGES</span><span class="p">;</span>
</code></pre></div></div>

<hr />

<h2 id="4단계-nginx-가상-호스트-설정">4단계: Nginx 가상 호스트 설정</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">yourdomain.com</span> <span class="s">www.yourdomain.com</span><span class="p">;</span>
    <span class="kn">root</span> <span class="n">/var/www/wordpress</span><span class="p">;</span>
    <span class="kn">index</span> <span class="s">index.php</span> <span class="s">index.html</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">try_files</span> <span class="nv">$uri</span> <span class="nv">$uri</span><span class="n">/</span> <span class="n">/index.php?</span><span class="nv">$args</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kn">location</span> <span class="p">~</span> <span class="sr">\.php$</span> <span class="p">{</span>
        <span class="kn">fastcgi_pass</span> <span class="s">unix:/var/run/php/php8.1-fpm.sock</span><span class="p">;</span>
        <span class="kn">fastcgi_index</span> <span class="s">index.php</span><span class="p">;</span>
        <span class="kn">include</span> <span class="s">fastcgi_params</span><span class="p">;</span>
        <span class="kn">fastcgi_param</span> <span class="s">SCRIPT_FILENAME</span> <span class="nv">$document_root$fastcgi_script_name</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kn">location</span> <span class="p">~</span><span class="sr">*</span> <span class="err">\</span><span class="s">.(jpg|jpeg|png|gif|ico|css|js|woff2)</span>$ <span class="p">{</span>
        <span class="kn">expires</span> <span class="s">30d</span><span class="p">;</span>
        <span class="kn">add_header</span> <span class="s">Cache-Control</span> <span class="s">"public,</span> <span class="s">no-transform"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="5단계-워드프레스-설치">5단계: 워드프레스 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> /var/www
wget https://wordpress.org/latest.tar.gz
<span class="nb">tar</span> <span class="nt">-xzf</span> latest.tar.gz
<span class="nb">chown</span> <span class="nt">-R</span> www-data:www-data wordpress
</code></pre></div></div>

<hr />

<h2 id="6단계-워드프레스-성능-최적화">6단계: 워드프레스 성능 최적화</h2>

<h3 id="오브젝트-캐시-redis-연동">오브젝트 캐시: Redis 연동</h3>

<p>일본 서버에 Redis를 설치하면 데이터베이스 쿼리를 캐싱해 응답 속도를 크게 개선할 수 있습니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>redis-server php8.1-redis <span class="nt">-y</span>
</code></pre></div></div>

<p>워드프레스에서는 <strong>Redis Object Cache</strong> 플러그인을 설치해 연동하세요.</p>

<h3 id="nginx-fastcgi-캐시">Nginx FastCGI 캐시</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fastcgi_cache_path</span> <span class="n">/tmp/nginx_cache</span> <span class="s">levels=1:2</span> <span class="s">keys_zone=WORDPRESS:100m</span> <span class="s">inactive=60m</span><span class="p">;</span>
<span class="k">fastcgi_cache_key</span> <span class="s">"</span><span class="nv">$scheme$request_method$host$request_uri</span><span class="s">"</span><span class="p">;</span>
</code></pre></div></div>

<hr />

<h2 id="일본-서버-워드프레스-보안-기본-설정">일본 서버 워드프레스 보안 기본 설정</h2>

<p>워드프레스는 봇·브루트포스 공격의 주요 표적입니다. 일본 서버에서 운영 시 아래 보안 설정을 반드시 적용하세요:</p>

<ol>
  <li><strong>wp-login.php 접근 제한</strong>: IP 화이트리스트 또는 2FA 플러그인 적용</li>
  <li><strong>xmlrpc.php 비활성화</strong>: 불필요시 Nginx에서 차단</li>
  <li><strong>자동 업데이트 활성화</strong>: 코어·플러그인·테마 보안 패치 자동 적용</li>
  <li><strong>파일 권한 설정</strong>: <code class="language-plaintext highlighter-rouge">wp-config.php</code> 권한을 400으로 제한</li>
</ol>

<p>TCP-80.NET 일본 서버에는 네트워크 레이어 DDoS 방어가 기본 포함되어 워드프레스 운영 시 봇 트래픽 부담을 줄여줍니다.</p>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 서버호스팅 환경에서 Nginx + PHP-FPM + MariaDB + Redis 조합은 워드프레스를 가장 효율적으로 운영할 수 있는 스택입니다. 서버 설정에 어려움이 있으시면 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요. 24시간 한국어 기술 지원을 제공합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="서버" /><summary type="html"><![CDATA[일본 서버호스팅에 워드프레스를 설치하고 최적화하는 방법을 단계별로 정리했습니다. Nginx + PHP-FPM + MariaDB 환경에서 빠른 워드프레스 운영을 시작하세요.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">일본 웹호스팅 vs 일본 서버호스팅 — 어떤 걸 선택해야 할까?</title><link href="https://tcp-80.net/blog/2025/01/20/japan-web-hosting/" rel="alternate" type="text/html" title="일본 웹호스팅 vs 일본 서버호스팅 — 어떤 걸 선택해야 할까?" /><published>2025-01-20T00:00:00+09:00</published><updated>2025-01-20T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2025/01/20/japan-web-hosting</id><content type="html" xml:base="https://tcp-80.net/blog/2025/01/20/japan-web-hosting/"><![CDATA[<p>일본 호스팅을 알아보다 보면 “웹호스팅”과 “서버호스팅(VPS·전용서버)” 두 가지 선택지가 나옵니다. 이름은 비슷하지만 구조와 용도가 완전히 다릅니다. 이 글에서 두 서비스의 차이를 명확히 정리합니다.</p>

<h2 id="일본-웹호스팅이란">일본 웹호스팅이란?</h2>

<p>일본 웹호스팅은 하나의 물리 서버를 여러 고객이 함께 사용하는 공유 호스팅(Shared Hosting)입니다. 일반적으로 웹사이트 파일 업로드, 이메일, DB 등을 제공하지만 서버 운영체제(OS)에는 접근할 수 없습니다.</p>

<p><strong>일본 웹호스팅이 적합한 경우:</strong></p>
<ul>
  <li>간단한 소개 페이지, 블로그, 포트폴리오 사이트</li>
  <li>트래픽이 적고 설정이 단순한 서비스</li>
  <li>서버 관리 경험이 없는 초보자</li>
</ul>

<p><strong>일본 웹호스팅의 한계:</strong></p>
<ul>
  <li>서버 환경 커스터마이징 불가</li>
  <li>공유 리소스로 인한 성능 불안정</li>
  <li>Node.js, Python, Docker 등 최신 스택 사용 어려움</li>
  <li>대규모 트래픽 처리 불가</li>
</ul>

<hr />

<h2 id="일본-서버호스팅vps전용서버이란">일본 서버호스팅(VPS·전용서버)이란?</h2>

<p>일본 서버호스팅은 가상 서버(VPS) 또는 물리 전용서버 전체를 임대하는 서비스입니다. root 권한으로 OS를 직접 관리하며, 어떤 소프트웨어든 자유롭게 설치할 수 있습니다.</p>

<p><strong>일본 서버호스팅이 적합한 경우:</strong></p>
<ul>
  <li>웹 서비스, API 서버, 데이터베이스 서버 운영</li>
  <li>게임서버, 스트리밍 서버 등 고성능이 필요한 서비스</li>
  <li>Docker, Kubernetes 등 컨테이너 환경 구축</li>
  <li>일본 IP가 필요한 업무 및 마케팅 시스템</li>
</ul>

<hr />

<h2 id="웹호스팅-vs-서버호스팅-비교">웹호스팅 vs 서버호스팅 비교</h2>

<table>
  <thead>
    <tr>
      <th>구분</th>
      <th>일본 웹호스팅</th>
      <th>일본 서버호스팅 (VPS)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>서버 접근</td>
      <td>FTP/cPanel만</td>
      <td>root SSH 전체 접근</td>
    </tr>
    <tr>
      <td>OS 설정</td>
      <td>불가</td>
      <td>자유롭게 설정</td>
    </tr>
    <tr>
      <td>성능</td>
      <td>공유, 불안정</td>
      <td>전용 리소스</td>
    </tr>
    <tr>
      <td>확장성</td>
      <td>제한적</td>
      <td>자유로운 스케일업</td>
    </tr>
    <tr>
      <td>가격</td>
      <td>저렴 (월 수천 원)</td>
      <td>월 10만 원~</td>
    </tr>
    <tr>
      <td>적합한 규모</td>
      <td>소규모 개인 사이트</td>
      <td>상업용 서비스 전반</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="한국에서-일본-호스팅을-쓰는-이유">한국에서 일본 호스팅을 쓰는 이유</h2>

<h3 id="1-낮은-레이턴시">1. 낮은 레이턴시</h3>

<p>서울~도쿄 간 인터넷 왕복 지연은 평균 <strong>20~35ms</strong>입니다. 미국 서버(150~200ms)에 비해 압도적으로 빠르기 때문에 실시간 응답이 중요한 서비스에 유리합니다.</p>

<h3 id="2-일본-ip-주소">2. 일본 IP 주소</h3>

<p>일본 현지 IP가 필요한 서비스(인터넷 뱅킹, 특정 스트리밍, 마케팅 툴 등) 이용 시 일본 호스팅이 필수입니다.</p>

<h3 id="3-안정적인-일본-인프라">3. 안정적인 일본 인프라</h3>

<p>일본 도쿄 데이터센터는 고가용성 전원 공급 시스템과 네트워크 이중화를 기본으로 갖추고 있어 장애 발생률이 낮습니다.</p>

<hr />

<h2 id="일본-서버호스팅-선택-시-확인-사항">일본 서버호스팅 선택 시 확인 사항</h2>

<p>일본 웹호스팅보다 서버호스팅이 필요하다고 판단됐다면, 아래 항목을 반드시 확인하세요.</p>

<ol>
  <li><strong>DDoS 방어 포함 여부</strong> — 기본 제공인지 유료 추가인지 확인</li>
  <li><strong>한국어 지원</strong> — 장애 발생 시 한국어로 신속하게 소통 가능한지</li>
  <li><strong>서버 위치</strong> — 일본 도쿄 IDC인지, 실제 일본 내 위치 확인</li>
  <li><strong>OS 선택 범위</strong> — Ubuntu, Debian, CentOS, Windows Server 등 지원 여부</li>
  <li><strong>환불 정책</strong> — 서비스 품질이 맞지 않을 경우 환불 가능 여부</li>
</ol>

<p>TCP-80.NET은 일본 도쿄 데이터센터 직영으로 DDoS 기본 방어, 24시간 한국어 지원, 7일 전액 환불을 보장합니다. <a href="/virtual-server/">VPS</a>와 <a href="/dedicated-server/">전용서버</a> 모두 제공하며, 일본 IP 기반 <a href="/virtual-desktop/">가상 데스크톱</a>도 이용하실 수 있습니다.</p>

<hr />

<h2 id="마치며">마치며</h2>

<p>일본 호스팅이 필요하다면, 목적에 따라 웹호스팅과 서버호스팅을 구분해서 선택하는 것이 중요합니다. 단순 블로그나 개인 사이트가 아니라 실제 서비스를 운영할 계획이라면 VPS 또는 전용서버 기반의 일본 서버호스팅이 훨씬 유연하고 안정적인 선택입니다.</p>

<p>서비스 선택에 대한 상담은 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 언제든지 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가이드" /><category term="호스팅" /><summary type="html"><![CDATA[일본 호스팅을 알아보고 있다면 웹호스팅과 서버호스팅의 차이부터 이해해야 합니다. 용도별 선택 기준과 일본 웹호스팅의 장단점을 정리했습니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-server.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-server.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">리눅스 서버 네트워크 트러블슈팅 가이드</title><link href="https://tcp-80.net/blog/2024/10/07/network-troubleshooting/" rel="alternate" type="text/html" title="리눅스 서버 네트워크 트러블슈팅 가이드" /><published>2024-10-07T00:00:00+09:00</published><updated>2024-10-07T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/10/07/network-troubleshooting</id><content type="html" xml:base="https://tcp-80.net/blog/2024/10/07/network-troubleshooting/"><![CDATA[<p>서버 네트워크 문제는 다양한 원인으로 발생합니다. 당황하지 않고 단계별로 접근하면 대부분의 문제를 빠르게 찾을 수 있습니다.</p>

<h2 id="1단계-기본-연결-확인">1단계: 기본 연결 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 인터넷 연결 확인</span>
ping <span class="nt">-c</span> 4 8.8.8.8

<span class="c"># DNS 해석 확인</span>
nslookup google.com
dig google.com

<span class="c"># 특정 도메인 확인</span>
ping <span class="nt">-c</span> 4 example.com

<span class="c"># 내 서버 IP 확인</span>
curl ifconfig.me
ip addr show
</code></pre></div></div>

<h2 id="2단계-네트워크-인터페이스-상태-확인">2단계: 네트워크 인터페이스 상태 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 인터페이스 목록 및 IP 확인</span>
ip addr show
ip <span class="nb">link </span>show

<span class="c"># 인터페이스 통계 (에러, 드롭 확인)</span>
ip <span class="nt">-s</span> <span class="nb">link </span>show eth0

<span class="c"># 라우팅 테이블 확인</span>
ip route show
route <span class="nt">-n</span>

<span class="c"># 기본 게이트웨이 확인</span>
ip route | <span class="nb">grep </span>default
</code></pre></div></div>

<h2 id="3단계-포트-및-서비스-확인">3단계: 포트 및 서비스 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 특정 포트가 열려 있는지 확인</span>
<span class="c"># 서버에서 실행</span>
<span class="nb">sudo </span>ss <span class="nt">-tlnp</span> | <span class="nb">grep</span> :80
<span class="nb">sudo </span>ss <span class="nt">-tlnp</span> | <span class="nb">grep</span> :443

<span class="c"># 외부에서 포트 확인 (다른 서버에서)</span>
nc <span class="nt">-zv</span> server-ip 80
telnet server-ip 80

<span class="c"># nmap으로 포트 스캔</span>
nmap <span class="nt">-p</span> 22,80,443 server-ip

<span class="c"># curl로 HTTP 응답 확인</span>
curl <span class="nt">-I</span> http://server-ip
curl <span class="nt">-I</span> https://example.com
curl <span class="nt">-v</span> https://example.com 2&gt;&amp;1 | <span class="nb">head</span> <span class="nt">-30</span>
</code></pre></div></div>

<h2 id="4단계-dns-문제-진단">4단계: DNS 문제 진단</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># DNS 응답 확인</span>
dig example.com
dig example.com @8.8.8.8  <span class="c"># Google DNS 사용</span>
dig +short example.com

<span class="c"># 역방향 DNS (PTR 레코드)</span>
dig <span class="nt">-x</span> 203.0.113.10

<span class="c"># DNS 전파 확인 (여러 네임서버에서)</span>
dig example.com @8.8.8.8     <span class="c"># Google</span>
dig example.com @1.1.1.1     <span class="c"># Cloudflare</span>
dig example.com @168.126.63.1 <span class="c"># KT DNS</span>

<span class="c"># /etc/resolv.conf 확인</span>
<span class="nb">cat</span> /etc/resolv.conf

<span class="c"># hosts 파일 확인</span>
<span class="nb">cat</span> /etc/hosts
</code></pre></div></div>

<h2 id="5단계-응답-속도-문제-진단">5단계: 응답 속도 문제 진단</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 경로별 지연시간 추적</span>
traceroute example.com
traceroute <span class="nt">-n</span> example.com   <span class="c"># DNS 역방향 없이 (빠름)</span>
mtr example.com              <span class="c"># 실시간 traceroute</span>

<span class="c"># HTTP 응답 시간 측정</span>
curl <span class="nt">-o</span> /dev/null <span class="nt">-s</span> <span class="nt">-w</span> <span class="s2">"응답코드: %{http_code}</span><span class="se">\n</span><span class="s2">연결시간: %{time_connect}s</span><span class="se">\n</span><span class="s2">TTFB: %{time_starttransfer}s</span><span class="se">\n</span><span class="s2">전체: %{time_total}s</span><span class="se">\n</span><span class="s2">"</span> https://example.com

<span class="c"># 네트워크 대역폭 테스트 (iperf3)</span>
<span class="c"># 서버에서</span>
iperf3 <span class="nt">-s</span>
<span class="c"># 클라이언트에서</span>
iperf3 <span class="nt">-c</span> server-ip
</code></pre></div></div>

<h2 id="6단계-방화벽-확인">6단계: 방화벽 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># UFW 규칙 확인</span>
<span class="nb">sudo </span>ufw status numbered

<span class="c"># iptables 규칙 확인</span>
<span class="nb">sudo </span>iptables <span class="nt">-L</span> <span class="nt">-n</span> <span class="nt">-v</span>

<span class="c"># 차단된 패킷 로그 확인</span>
<span class="nb">sudo grep</span> <span class="s2">"UFW BLOCK</span><span class="se">\|</span><span class="s2">IPT DROP"</span> /var/log/kern.log | <span class="nb">tail</span> <span class="nt">-20</span>

<span class="c"># 임시로 방화벽 비활성화 (테스트 후 반드시 재활성화!)</span>
<span class="nb">sudo </span>ufw disable
<span class="c"># 테스트...</span>
<span class="nb">sudo </span>ufw <span class="nb">enable</span>
</code></pre></div></div>

<h2 id="7단계-서비스-상태-확인">7단계: 서비스 상태 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Nginx 상태 확인</span>
<span class="nb">sudo </span>systemctl status nginx
<span class="nb">sudo </span>nginx <span class="nt">-t</span>              <span class="c"># 설정 파일 검사</span>

<span class="c"># 서비스 재시작</span>
<span class="nb">sudo </span>systemctl restart nginx
<span class="nb">sudo </span>systemctl restart php8.2-fpm

<span class="c"># 실시간 에러 로그 확인</span>
<span class="nb">sudo tail</span> <span class="nt">-f</span> /var/log/nginx/error.log
<span class="nb">sudo </span>journalctl <span class="nt">-u</span> nginx <span class="nt">-f</span>
</code></pre></div></div>

<h2 id="8단계-연결-수-및-리소스-확인">8단계: 연결 수 및 리소스 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 현재 TCP 연결 수</span>
ss <span class="nt">-s</span>
ss <span class="nt">-tn</span> | <span class="nb">grep </span>ESTABLISHED | <span class="nb">wc</span> <span class="nt">-l</span>

<span class="c"># TIME_WAIT 상태 연결 (많으면 문제)</span>
ss <span class="nt">-tn</span> | <span class="nb">grep </span>TIME_WAIT | <span class="nb">wc</span> <span class="nt">-l</span>

<span class="c"># 연결 상태별 집계</span>
ss <span class="nt">-tan</span> | <span class="nb">awk</span> <span class="s1">'NR&gt;1{print $1}'</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span>

<span class="c"># CPU/메모리 사용률</span>
top <span class="nt">-bn1</span> | <span class="nb">head</span> <span class="nt">-15</span>
free <span class="nt">-h</span>

<span class="c"># 디스크 용량 (가득 차면 서비스 장애)</span>
<span class="nb">df</span> <span class="nt">-h</span>
</code></pre></div></div>

<h2 id="자주-발생하는-문제와-해결법">자주 발생하는 문제와 해결법</h2>

<h3 id="connection-refused-포트가-닫혀-있음">“Connection refused” (포트가 닫혀 있음)</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 서비스가 실행 중인지 확인</span>
systemctl status nginx

<span class="c"># 해당 포트를 누가 사용하는지</span>
<span class="nb">sudo </span>ss <span class="nt">-tlnp</span> | <span class="nb">grep</span> :80

<span class="c"># 방화벽이 차단하는지</span>
<span class="nb">sudo </span>ufw status
</code></pre></div></div>

<h3 id="connection-timed-out-패킷이-도달하지-않음">“Connection timed out” (패킷이 도달하지 않음)</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 방화벽에서 차단 중인지 확인</span>
<span class="nb">sudo </span>iptables <span class="nt">-L</span> <span class="nt">-n</span> | <span class="nb">grep</span> <span class="nt">-i</span> drop
<span class="nb">sudo </span>ufw status

<span class="c"># 네트워크 경로 문제</span>
traceroute server-ip
mtr server-ip
</code></pre></div></div>

<h3 id="502-bad-gateway-nginx--백엔드-연결-실패">“502 Bad Gateway” (Nginx → 백엔드 연결 실패)</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Nginx 에러 로그 확인</span>
<span class="nb">sudo tail</span> <span class="nt">-20</span> /var/log/nginx/error.log

<span class="c"># PHP-FPM 소켓 확인</span>
<span class="nb">sudo ls</span> <span class="nt">-la</span> /run/php/php8.2-fpm.sock
<span class="nb">sudo </span>systemctl status php8.2-fpm
</code></pre></div></div>

<h3 id="too-many-open-files-파일-디스크립터-한도-초과">“Too many open files” (파일 디스크립터 한도 초과)</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 현재 한도 확인</span>
<span class="nb">ulimit</span> <span class="nt">-n</span>
<span class="nb">cat</span> /proc/sys/fs/file-max

<span class="c"># 한도 늘리기</span>
<span class="nb">sudo </span>sh <span class="nt">-c</span> <span class="s1">'echo "fs.file-max = 1000000" &gt;&gt; /etc/sysctl.conf'</span>
<span class="nb">sudo </span>sysctl <span class="nt">-p</span>

<span class="c"># Nginx 한도 설정</span>
<span class="c"># /etc/nginx/nginx.conf</span>
<span class="c"># worker_rlimit_nofile 65535;</span>
</code></pre></div></div>

<h2 id="패킷-캡처-고급-진단">패킷 캡처 (고급 진단)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 특정 포트의 패킷 캡처</span>
<span class="nb">sudo </span>tcpdump <span class="nt">-i</span> eth0 port 80 <span class="nt">-n</span>

<span class="c"># 특정 IP와의 통신 캡처</span>
<span class="nb">sudo </span>tcpdump <span class="nt">-i</span> eth0 host 203.0.113.10 <span class="nt">-n</span>

<span class="c"># 파일로 저장 (Wireshark로 분석)</span>
<span class="nb">sudo </span>tcpdump <span class="nt">-i</span> eth0 port 80 <span class="nt">-w</span> /tmp/capture.pcap
</code></pre></div></div>

<p>네트워크 문제는 단계적으로 접근하는 것이 핵심입니다. 인터넷 연결 → DNS → 라우팅 → 방화벽 → 서비스 순서로 확인하면 대부분의 문제를 빠르게 찾을 수 있습니다. TCP-80.NET 서버 관련 네트워크 문제는 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 언제든지 문의하세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><summary type="html"><![CDATA[서버 접속이 안 될 때, 응답이 느릴 때, 특정 서비스가 다운됐을 때 단계별로 원인을 찾고 해결하는 네트워크 트러블슈팅 방법을 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">logrotate로 서버 로그 파일 자동 관리하기</title><link href="https://tcp-80.net/blog/2024/09/23/logrotate-setup/" rel="alternate" type="text/html" title="logrotate로 서버 로그 파일 자동 관리하기" /><published>2024-09-23T00:00:00+09:00</published><updated>2024-09-23T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/09/23/logrotate-setup</id><content type="html" xml:base="https://tcp-80.net/blog/2024/09/23/logrotate-setup/"><![CDATA[<p>서버에서 로그 파일을 관리하지 않으면 디스크가 꽉 차 서버가 다운될 수 있습니다. <code class="language-plaintext highlighter-rouge">logrotate</code>는 로그 파일을 자동으로 회전(rotate)시키고 오래된 것은 삭제해주는 필수 도구입니다.</p>

<h2 id="logrotate-동작-원리">logrotate 동작 원리</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>오늘: app.log (현재 로그)
      ↓ 자동 처리
app.log.1    (어제 로그)
app.log.2.gz (그제 로그, 압축)
app.log.3.gz
...
app.log.7.gz (7일 전 로그)
[삭제]       (8일 이상 된 것)
</code></pre></div></div>

<h2 id="설정-파일-위치">설정 파일 위치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/logrotate.conf         <span class="c"># 전역 기본 설정</span>
/etc/logrotate.d/           <span class="c"># 서비스별 설정 디렉터리</span>
/etc/logrotate.d/nginx      <span class="c"># Nginx 로그 설정 (패키지가 자동 생성)</span>
/etc/logrotate.d/mysql      <span class="c"># MySQL 로그 설정</span>
</code></pre></div></div>

<h2 id="기본-설정-파일-구조">기본 설정 파일 구조</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/var/log/myapp/*.log {
    daily           # 회전 주기 (daily/weekly/monthly/yearly)
    rotate 7        # 7개 파일 보존 (7일치)
    compress        # 회전된 파일 gzip 압축
    delaycompress   # 최신 회전 파일은 압축 보류 (다음 번에 압축)
    missingok       # 파일 없어도 오류 없이 넘어감
    notifempty      # 빈 파일은 회전하지 않음
    create 644 www-data www-data  # 새 로그 파일 생성 (권한 소유자 그룹)
    sharedscripts   # postrotate 스크립트를 한 번만 실행
    postrotate
        # 로그 회전 후 실행할 명령 (서비스에 새 파일 사용 신호)
        [ -f /var/run/nginx.pid ] &amp;&amp; kill -USR1 `cat /var/run/nginx.pid`
    endscript
}
</code></pre></div></div>

<h2 id="nginx-로그-설정-기본-제공">Nginx 로그 설정 (기본 제공)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 기존 설정 확인</span>
<span class="nb">cat</span> /etc/logrotate.d/nginx
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/var/log/nginx/*.log {
    daily
    missingok
    rotate 52       # 52일(약 7주)치 보존
    compress
    delaycompress
    notifempty
    create 640 nginx adm
    sharedscripts
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 `cat /var/run/nginx.pid`
        fi
    endscript
}
</code></pre></div></div>

<h2 id="mysql-로그-설정">MySQL 로그 설정</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># /etc/logrotate.d/mysql
/var/log/mysql/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 640 mysql adm
    sharedscripts
    postrotate
        test -x /usr/bin/mysqladmin || exit 0
        if [ -f /var/run/mysqld/mysqld.pid ]; then
            mysqladmin --defaults-file=/etc/mysql/debian.cnf flush-logs
        fi
    endscript
}
</code></pre></div></div>

<h2 id="사용자-정의-애플리케이션-로그">사용자 정의 애플리케이션 로그</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># /etc/logrotate.d/myapp
/var/log/myapp/app.log
/var/log/myapp/error.log {
    daily
    rotate 30           # 30일치 보존
    size 100M           # 100MB 초과 시 즉시 회전 (daily와 OR 조건)
    compress
    delaycompress
    missingok
    notifempty
    copytruncate        # 파일을 복사 후 원본을 비움 (재시작 없이 로테이션)
                        # 주의: 데이터 손실 가능성 있음, postrotate 선호
    create 644 appuser appgroup
}
</code></pre></div></div>

<h2 id="copytruncate-vs-postrotate">copytruncate vs postrotate</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>copytruncate:
  - 파일을 복사하고 원본을 0바이트로 만듦
  - 애플리케이션 재시작/신호 없이 작동
  - 복사~트런케이트 사이 짧은 시간 동안 로그 손실 가능

postrotate + kill -USR1:
  - 파일 이름을 변경하고 새 파일 생성
  - 애플리케이션에 새 파일 열도록 신호 전송
  - 더 안전하고 권장됨 (Nginx, Apache 등 지원)
</code></pre></div></div>

<h2 id="수동-실행-및-디버깅">수동 실행 및 디버깅</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 특정 설정 파일 테스트 (실제 실행 없이)</span>
<span class="nb">sudo </span>logrotate <span class="nt">-d</span> /etc/logrotate.d/myapp

<span class="c"># 강제 실행 (이미 오늘 실행했더라도)</span>
<span class="nb">sudo </span>logrotate <span class="nt">-f</span> /etc/logrotate.d/myapp

<span class="c"># 전체 logrotate 강제 실행</span>
<span class="nb">sudo </span>logrotate <span class="nt">-f</span> /etc/logrotate.conf

<span class="c"># 상세 출력으로 실행</span>
<span class="nb">sudo </span>logrotate <span class="nt">-v</span> /etc/logrotate.d/myapp
</code></pre></div></div>

<h2 id="logrotate-실행-확인">logrotate 실행 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># logrotate 상태 파일 (마지막 실행 날짜 기록)</span>
<span class="nb">cat</span> /var/lib/logrotate/status | <span class="nb">grep </span>myapp

<span class="c"># 시스템 logrotate 타이머 확인</span>
<span class="nb">sudo </span>systemctl status logrotate.timer
<span class="nb">sudo </span>systemctl list-timers | <span class="nb">grep </span>logrotate

<span class="c"># 실행 로그 확인</span>
<span class="nb">sudo grep </span>logrotate /var/log/syslog | <span class="nb">tail</span> <span class="nt">-10</span>
</code></pre></div></div>

<h2 id="로그-보존-용량-계산">로그 보존 용량 계산</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 예상 디스크 사용량 계산</span>
<span class="c"># 일일 로그 크기 * 보존 일수</span>

<span class="c"># 현재 로그 파일 크기</span>
<span class="nb">du</span> <span class="nt">-sh</span> /var/log/nginx/
<span class="nb">du</span> <span class="nt">-sh</span> /var/log/mysql/

<span class="c"># 압축 효율 확인 (텍스트 로그는 보통 5~10배 압축)</span>
<span class="nb">ls</span> <span class="nt">-lh</span> /var/log/nginx/<span class="k">*</span>.gz
</code></pre></div></div>

<h2 id="로그-없는-정적-파일-요청-제외">로그 없는 정적 파일 요청 제외</h2>

<p>Nginx 설정에서 정적 파일 접근 로그를 꺼두면 로그 크기를 크게 줄일 수 있습니다:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">location</span> <span class="p">~</span><span class="sr">*</span> <span class="err">\</span><span class="s">.(jpg|jpeg|png|gif|ico|css|js|woff2)</span>$ <span class="p">{</span>
    <span class="kn">expires</span> <span class="s">1y</span><span class="p">;</span>
    <span class="kn">access_log</span> <span class="no">off</span><span class="p">;</span>  <span class="c1"># 정적 파일 접근 로그 비활성화</span>
<span class="p">}</span>
</code></pre></div></div>

<p>logrotate를 올바르게 설정하면 디스크 부족으로 인한 갑작스러운 서버 장애를 예방할 수 있습니다. 새 서비스를 설치할 때마다 해당 서비스의 로그 파일에 대한 logrotate 설정을 추가하는 습관을 들이세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><summary type="html"><![CDATA[logrotate 설정 파일 작성법, 회전 주기·보존 기간·압축 설정, Nginx·MySQL·사용자 정의 로그 관리, 수동 실행 및 디버깅 방법을 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">리눅스 서버 보안 최종 점검 체크리스트</title><link href="https://tcp-80.net/blog/2024/09/09/server-security-final-checklist/" rel="alternate" type="text/html" title="리눅스 서버 보안 최종 점검 체크리스트" /><published>2024-09-09T00:00:00+09:00</published><updated>2024-09-09T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/09/09/server-security-final-checklist</id><content type="html" xml:base="https://tcp-80.net/blog/2024/09/09/server-security-final-checklist/"><![CDATA[<p>서버를 운영하다 보면 초기 보안 설정이 느슨해지거나 새로운 취약점이 발생합니다. 이 체크리스트로 정기적으로 서버 보안 상태를 점검하세요.</p>

<h2 id="1-시스템-업데이트">1. 시스템 업데이트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 보안 업데이트 가능 패키지 확인</span>
apt list <span class="nt">--upgradeable</span> 2&gt;/dev/null | <span class="nb">grep</span> <span class="nt">-i</span> security
apt list <span class="nt">--upgradeable</span> 2&gt;/dev/null | <span class="nb">wc</span> <span class="nt">-l</span>

<span class="c"># 마지막 업데이트 날짜 확인</span>
<span class="nb">ls</span> <span class="nt">-la</span> /var/log/apt/history.log
<span class="nb">tail</span> <span class="nt">-5</span> /var/log/apt/history.log
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✅ 모든 보안 패키지 최신 상태
✅ 자동 보안 업데이트 활성화 (unattended-upgrades)
✅ 재부팅 필요 여부 확인 (/var/run/reboot-required)
</code></pre></div></div>

<h2 id="2-ssh-보안">2. SSH 보안</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SSH 설정 확인</span>
sshd <span class="nt">-T</span> | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"permitrootlogin|passwordauthentication|port|maxauthtries|logingracetime"</span>

<span class="c"># 허용된 키 목록 확인</span>
<span class="nb">cat</span> /root/.ssh/authorized_keys
<span class="k">for </span>home <span class="k">in</span> /home/<span class="k">*</span>/<span class="p">;</span> <span class="k">do
    </span><span class="nb">echo</span> <span class="s2">"=== </span><span class="nv">$home</span><span class="s2"> ==="</span> <span class="o">&amp;&amp;</span> <span class="nb">cat</span> <span class="k">${</span><span class="nv">home</span><span class="k">}</span>.ssh/authorized_keys 2&gt;/dev/null
<span class="k">done</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✅ PermitRootLogin no
✅ PasswordAuthentication no
✅ 기본 포트(22) 변경 또는 fail2ban 적용
✅ MaxAuthTries 3 이하
✅ authorized_keys에 불필요한 키 없음
</code></pre></div></div>

<h2 id="3-방화벽">3. 방화벽</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># UFW 상태</span>
<span class="nb">sudo </span>ufw status numbered

<span class="c"># 열려 있는 포트 확인 (모든 인터페이스)</span>
<span class="nb">sudo </span>ss <span class="nt">-tlnp</span>
<span class="nb">sudo </span>nmap <span class="nt">-sV</span> localhost
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✅ 방화벽 활성화
✅ 필요한 포트만 허용 (최소 권한 원칙)
✅ 관리 포트(SSH, MySQL 등)는 특정 IP에서만 허용
✅ 0.0.0.0 바인딩 서비스가 의도한 것만 존재
</code></pre></div></div>

<h2 id="4-사용자-계정">4. 사용자 계정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 전체 계정 목록 (로그인 가능한 계정)</span>
<span class="nb">cat</span> /etc/passwd | <span class="nb">grep</span> <span class="nt">-vE</span> <span class="s2">"nologin|false|sync|halt|shutdown"</span>

<span class="c"># 최근 로그인 기록</span>
last | <span class="nb">head</span> <span class="nt">-20</span>
lastb | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># sudo 권한 보유 계정</span>
<span class="nb">grep</span> <span class="nt">-E</span> <span class="s1">'sudo|wheel'</span> /etc/group

<span class="c"># 비밀번호 정책</span>
chage <span class="nt">-l</span> username
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✅ 불필요한 계정 없음
✅ 비밀번호 만료 정책 설정
✅ sudo 권한 계정 최소화
✅ 시스템 계정에 로그인 불가 설정
</code></pre></div></div>

<h2 id="5-파일-시스템">5. 파일 시스템</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SUID/SGID 파일 목록</span>
find / <span class="nt">-perm</span> <span class="nt">-4000</span> <span class="nt">-o</span> <span class="nt">-perm</span> <span class="nt">-2000</span> <span class="nt">-type</span> f 2&gt;/dev/null

<span class="c"># 기타 사용자 쓰기 가능한 파일 (보안 위험)</span>
find /etc /var/www <span class="nt">-perm</span> <span class="nt">-o</span>+w <span class="nt">-type</span> f 2&gt;/dev/null

<span class="c"># 소유자 없는 파일</span>
find / <span class="nt">-nouser</span> <span class="nt">-o</span> <span class="nt">-nogroup</span> 2&gt;/dev/null | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># 웹 디렉터리 권한 확인</span>
<span class="nb">ls</span> <span class="nt">-la</span> /var/www/html/
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✅ 비정상 SUID 파일 없음
✅ 웹 디렉터리 권한 755(디렉터리)/644(파일)
✅ 업로드 디렉터리 PHP 실행 불가
✅ 설정 파일 (DB 비밀번호 등) 권한 600 이하
</code></pre></div></div>

<h2 id="6-네트워크-서비스">6. 네트워크 서비스</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 모든 리슨 서비스</span>
<span class="nb">sudo </span>ss <span class="nt">-tlnp</span>
<span class="nb">sudo </span>ss <span class="nt">-ulnp</span>   <span class="c"># UDP</span>

<span class="c"># 외부로 나가는 연결 확인</span>
<span class="nb">sudo </span>ss <span class="nt">-tnp</span> state established

<span class="c"># 포트 매핑 (어떤 프로세스가 어떤 포트)</span>
<span class="nb">sudo </span>lsof <span class="nt">-i</span> <span class="nt">-n</span> <span class="nt">-P</span> | <span class="nb">grep </span>LISTEN
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✅ 불필요한 서비스 비활성화
✅ Redis/Memcached 로컬 바인딩 확인 (0.0.0.0 노출 금지)
✅ MySQL/PostgreSQL 로컬 바인딩 확인
✅ 의심스러운 아웃바운드 연결 없음
</code></pre></div></div>

<h2 id="7-프로세스-및-크론">7. 프로세스 및 크론</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 실행 중인 프로세스</span>
ps auxf

<span class="c"># 시스템 크론탭 확인</span>
<span class="nb">cat</span> /etc/crontab
<span class="nb">ls</span> /etc/cron.d/
<span class="nb">ls</span> /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/

<span class="c"># 모든 사용자 크론탭</span>
<span class="k">for </span>user <span class="k">in</span> <span class="si">$(</span><span class="nb">cut</span> <span class="nt">-d</span>: <span class="nt">-f1</span> /etc/passwd<span class="si">)</span><span class="p">;</span> <span class="k">do
    </span><span class="nv">cron</span><span class="o">=</span><span class="si">$(</span>crontab <span class="nt">-u</span> <span class="nv">$user</span> <span class="nt">-l</span> 2&gt;/dev/null<span class="si">)</span>
    <span class="o">[</span> <span class="nt">-n</span> <span class="s2">"</span><span class="nv">$cron</span><span class="s2">"</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"=== </span><span class="nv">$user</span><span class="s2"> ==="</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$cron</span><span class="s2">"</span>
<span class="k">done</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✅ 알 수 없는 프로세스 없음
✅ 크론탭에 악성 명령 없음
✅ /tmp, /var/tmp에 수상한 실행 파일 없음
</code></pre></div></div>

<h2 id="8-로그-모니터링">8. 로그 모니터링</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 최근 인증 실패</span>
<span class="nb">grep</span> <span class="s2">"Failed password"</span> /var/log/auth.log | <span class="nb">tail</span> <span class="nt">-20</span>

<span class="c"># 성공한 로그인</span>
<span class="nb">grep</span> <span class="s2">"Accepted"</span> /var/log/auth.log | <span class="nb">tail</span> <span class="nt">-20</span>

<span class="c"># sudo 사용 기록</span>
<span class="nb">grep</span> <span class="s2">"sudo"</span> /var/log/auth.log | <span class="nb">tail</span> <span class="nt">-20</span>

<span class="c"># 웹 서버 에러</span>
<span class="nb">sudo tail</span> <span class="nt">-50</span> /var/log/nginx/error.log
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✅ 비정상적인 로그인 시도 없음 (또는 fail2ban 차단 중)
✅ 알 수 없는 sudo 사용 기록 없음
✅ 웹 서버 에러 로그 주기적 확인
✅ 로그 파일 정상 rotation 중
</code></pre></div></div>

<h2 id="9-ssl-인증서">9. SSL 인증서</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Let's Encrypt 인증서 만료일 확인</span>
<span class="nb">sudo </span>certbot certificates

<span class="c"># 수동 SSL 만료일 확인</span>
<span class="nb">echo</span> | openssl s_client <span class="nt">-connect</span> example.com:443 2&gt;/dev/null | <span class="se">\</span>
    openssl x509 <span class="nt">-noout</span> <span class="nt">-dates</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✅ 인증서 만료 30일 이상 남음
✅ 자동 갱신 타이머 활성화
✅ HSTS 헤더 적용
✅ TLS 1.2 이상만 허용
</code></pre></div></div>

<h2 id="10-보안-스캐너-실행">10. 보안 스캐너 실행</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Lynis (종합 보안 감사)</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> lynis
<span class="nb">sudo </span>lynis audit system

<span class="c"># chkrootkit (루트킷 탐지)</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> chkrootkit
<span class="nb">sudo </span>chkrootkit

<span class="c"># rkhunter (루트킷 탐지)</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> rkhunter
<span class="nb">sudo </span>rkhunter <span class="nt">--update</span>
<span class="nb">sudo </span>rkhunter <span class="nt">--checkall</span>
</code></pre></div></div>

<h2 id="점검-주기-권장">점검 주기 권장</h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>권장 주기</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>시스템 업데이트</td>
      <td>자동 (또는 매주)</td>
    </tr>
    <tr>
      <td>로그인 기록 확인</td>
      <td>매일</td>
    </tr>
    <tr>
      <td>방화벽 규칙 검토</td>
      <td>월 1회</td>
    </tr>
    <tr>
      <td>사용자 계정 감사</td>
      <td>월 1회</td>
    </tr>
    <tr>
      <td>전체 보안 스캔</td>
      <td>분기 1회</td>
    </tr>
    <tr>
      <td>SSL 인증서 확인</td>
      <td>월 1회</td>
    </tr>
  </tbody>
</table>

<p>서버 보안은 한 번 설정하고 끝나는 것이 아닙니다. 이 체크리스트를 기반으로 정기적인 보안 감사를 실시하면 취약점을 조기에 발견할 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[SSH 설정, 방화벽, 업데이트, 파일 권한, 네트워크, 서비스, 모니터링까지 서버 보안 전 영역을 점검하는 종합 체크리스트입니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">rsync로 원격 서버 간 파일 동기화 및 백업 자동화</title><link href="https://tcp-80.net/blog/2024/08/26/rsync-remote-backup/" rel="alternate" type="text/html" title="rsync로 원격 서버 간 파일 동기화 및 백업 자동화" /><published>2024-08-26T00:00:00+09:00</published><updated>2024-08-26T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/08/26/rsync-remote-backup</id><content type="html" xml:base="https://tcp-80.net/blog/2024/08/26/rsync-remote-backup/"><![CDATA[<p>rsync는 변경된 파일만 전송하는 효율적인 동기화 도구입니다. SSH와 함께 사용하면 원격 서버 간 안전한 파일 동기화와 백업이 가능합니다.</p>

<h2 id="rsync-기본-문법">rsync 기본 문법</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rsync <span class="o">[</span>옵션] 출발지 목적지

<span class="c"># 로컬 디렉터리 동기화</span>
rsync <span class="nt">-av</span> /source/dir/ /destination/dir/

<span class="c"># 원격 서버로 전송 (로컬 → 원격)</span>
rsync <span class="nt">-av</span> /local/dir/ user@remote-server:/remote/dir/

<span class="c"># 원격 서버에서 가져오기 (원격 → 로컬)</span>
rsync <span class="nt">-av</span> user@remote-server:/remote/dir/ /local/dir/
</code></pre></div></div>

<h2 id="자주-사용하는-옵션">자주 사용하는 옵션</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">-a</span>  <span class="c"># archive mode: -rlptgoD 옵션 묶음 (권한, 소유자, 타임스탬프 보존)</span>
<span class="nt">-v</span>  <span class="c"># verbose (상세 출력)</span>
<span class="nt">-z</span>  <span class="c"># 압축 전송 (느린 네트워크에 유용)</span>
<span class="nt">-h</span>  <span class="c"># 사람이 읽기 쉬운 크기 표시</span>
<span class="nt">-P</span>  <span class="c"># 진행률 표시 + 부분 전송 재개 (--progress --partial)</span>
<span class="nt">-n</span>  <span class="c"># dry-run (실제 전송 없이 시뮬레이션)</span>
<span class="nt">--delete</span>  <span class="c"># 출발지에 없는 파일을 목적지에서 삭제 (완전 동기화)</span>
<span class="nt">--exclude</span>  <span class="c"># 특정 파일/디렉터리 제외</span>
<span class="nt">--bwlimit</span><span class="o">=</span>1000  <span class="c"># 대역폭 제한 (KB/s)</span>
</code></pre></div></div>

<h2 id="실전-사용-예제">실전 사용 예제</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 웹 루트 동기화 (삭제 포함)</span>
rsync <span class="nt">-avz</span> <span class="nt">--delete</span> /var/www/html/ user@backup-server:/backup/www/

<span class="c"># 특정 파일 제외하며 동기화</span>
rsync <span class="nt">-avz</span> <span class="se">\</span>
    <span class="nt">--exclude</span><span class="o">=</span><span class="s1">'*.log'</span> <span class="se">\</span>
    <span class="nt">--exclude</span><span class="o">=</span><span class="s1">'*.tmp'</span> <span class="se">\</span>
    <span class="nt">--exclude</span><span class="o">=</span><span class="s1">'node_modules/'</span> <span class="se">\</span>
    <span class="nt">--exclude</span><span class="o">=</span><span class="s1">'.git/'</span> <span class="se">\</span>
    /var/www/html/ user@backup-server:/backup/www/

<span class="c"># 먼저 시뮬레이션으로 확인</span>
rsync <span class="nt">-avzn</span> <span class="nt">--delete</span> /var/www/html/ user@backup-server:/backup/www/

<span class="c"># 대역폭 제한 (네트워크 부하 방지)</span>
rsync <span class="nt">-avz</span> <span class="nt">--bwlimit</span><span class="o">=</span>10240 /large-file/ user@backup-server:/backup/
</code></pre></div></div>

<h2 id="ssh-포트-및-키-지정">SSH 포트 및 키 지정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 비표준 SSH 포트 사용</span>
rsync <span class="nt">-avz</span> <span class="nt">-e</span> <span class="s2">"ssh -p 2222"</span> /local/ user@remote:/remote/

<span class="c"># 특정 SSH 키 사용</span>
rsync <span class="nt">-avz</span> <span class="nt">-e</span> <span class="s2">"ssh -i /home/user/.ssh/backup-key"</span> /local/ user@remote:/remote/

<span class="c"># 포트와 키 동시 지정</span>
rsync <span class="nt">-avz</span> <span class="nt">-e</span> <span class="s2">"ssh -p 2222 -i ~/.ssh/backup-key -o StrictHostKeyChecking=no"</span> <span class="se">\</span>
    /local/ user@remote:/remote/
</code></pre></div></div>

<h2 id="스냅샷-방식-백업-하드링크-활용">스냅샷 방식 백업 (하드링크 활용)</h2>

<p>변경된 파일만 새로 저장하고 변경되지 않은 파일은 하드링크로 연결해 공간을 절약하는 방식입니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /opt/snapshot-backup.sh</span>

<span class="nv">REMOTE_USER</span><span class="o">=</span><span class="s2">"backup"</span>
<span class="nv">REMOTE_HOST</span><span class="o">=</span><span class="s2">"backup-server"</span>
<span class="nv">REMOTE_DIR</span><span class="o">=</span><span class="s2">"/backup/snapshots"</span>
<span class="nv">SOURCE</span><span class="o">=</span><span class="s2">"/var/www/html"</span>
<span class="nv">DATE</span><span class="o">=</span><span class="si">$(</span><span class="nb">date</span> +%Y%m%d_%H%M%S<span class="si">)</span>
<span class="nv">LATEST</span><span class="o">=</span><span class="s2">"</span><span class="nv">$REMOTE_DIR</span><span class="s2">/latest"</span>
<span class="nv">DEST</span><span class="o">=</span><span class="s2">"</span><span class="nv">$REMOTE_DIR</span><span class="s2">/</span><span class="nv">$DATE</span><span class="s2">"</span>

rsync <span class="nt">-avz</span> <span class="nt">--delete</span> <span class="se">\</span>
    <span class="nt">--link-dest</span><span class="o">=</span><span class="s2">"</span><span class="nv">$LATEST</span><span class="s2">"</span> <span class="se">\</span>
    <span class="nt">-e</span> <span class="s2">"ssh -i /root/.ssh/backup-key"</span> <span class="se">\</span>
    <span class="s2">"</span><span class="nv">$SOURCE</span><span class="s2">/"</span> <span class="se">\</span>
    <span class="s2">"</span><span class="nv">$REMOTE_USER</span><span class="s2">@</span><span class="nv">$REMOTE_HOST</span><span class="s2">:</span><span class="nv">$DEST</span><span class="s2">/"</span>

<span class="c"># latest 심볼릭 링크 업데이트</span>
ssh <span class="nt">-i</span> /root/.ssh/backup-key <span class="s2">"</span><span class="nv">$REMOTE_USER</span><span class="s2">@</span><span class="nv">$REMOTE_HOST</span><span class="s2">"</span> <span class="se">\</span>
    <span class="s2">"rm -f </span><span class="nv">$LATEST</span><span class="s2"> &amp;&amp; ln -s </span><span class="nv">$DEST</span><span class="s2"> </span><span class="nv">$LATEST</span><span class="s2">"</span>

<span class="nb">echo</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">date</span><span class="si">)</span><span class="s2">: Snapshot backup completed: </span><span class="nv">$DEST</span><span class="s2">"</span>
</code></pre></div></div>

<h2 id="데이터베이스-백업--rsync">데이터베이스 백업 + rsync</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /opt/full-backup.sh</span>

<span class="nv">BACKUP_DIR</span><span class="o">=</span><span class="s2">"/opt/backup"</span>
<span class="nv">DATE</span><span class="o">=</span><span class="si">$(</span><span class="nb">date</span> +%Y%m%d<span class="si">)</span>
<span class="nv">REMOTE</span><span class="o">=</span><span class="s2">"backup-server"</span>

<span class="nb">mkdir</span> <span class="nt">-p</span> <span class="s2">"</span><span class="nv">$BACKUP_DIR</span><span class="s2">"</span>

<span class="c"># MySQL 덤프</span>
<span class="nb">echo</span> <span class="s2">"MySQL 백업 중..."</span>
mysqldump <span class="nt">-u</span> root <span class="nt">-p</span>비밀번호 <span class="nt">--all-databases</span> | <span class="se">\</span>
    <span class="nb">gzip</span> <span class="o">&gt;</span> <span class="s2">"</span><span class="nv">$BACKUP_DIR</span><span class="s2">/mysql_</span><span class="nv">$DATE</span><span class="s2">.sql.gz"</span>

<span class="c"># 웹 파일 백업 (디렉터리는 trailing slash 주의)</span>
<span class="nb">echo</span> <span class="s2">"파일 백업 중..."</span>
rsync <span class="nt">-avz</span> <span class="nt">--delete</span> <span class="se">\</span>
    <span class="nt">--exclude</span><span class="o">=</span><span class="s1">'*.tmp'</span> <span class="se">\</span>
    <span class="nt">--exclude</span><span class="o">=</span><span class="s1">'cache/'</span> <span class="se">\</span>
    /var/www/html/ <span class="se">\</span>
    root@<span class="nv">$REMOTE</span>:/backup/www/

<span class="c"># DB 파일 전송</span>
rsync <span class="nt">-avz</span> <span class="s2">"</span><span class="nv">$BACKUP_DIR</span><span class="s2">/mysql_</span><span class="nv">$DATE</span><span class="s2">.sql.gz"</span> <span class="se">\</span>
    root@<span class="nv">$REMOTE</span>:/backup/db/

<span class="c"># 7일 이상된 로컬 백업 삭제</span>
find <span class="s2">"</span><span class="nv">$BACKUP_DIR</span><span class="s2">"</span> <span class="nt">-name</span> <span class="s2">"*.sql.gz"</span> <span class="nt">-mtime</span> +7 <span class="nt">-delete</span>

<span class="nb">echo</span> <span class="s2">"백업 완료: </span><span class="si">$(</span><span class="nb">date</span><span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<h2 id="ssh-키-없이-rsync-rsync-데몬">SSH 키 없이 rsync (rsync 데몬)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 백업 서버에 rsync 데몬 설정</span>
<span class="c"># /etc/rsyncd.conf</span>
<span class="o">[</span>www-backup]
path <span class="o">=</span> /backup/www
comment <span class="o">=</span> Web files backup
<span class="nb">read </span>only <span class="o">=</span> no
auth <span class="nb">users</span> <span class="o">=</span> rsyncuser
secrets file <span class="o">=</span> /etc/rsyncd.secrets

<span class="c"># /etc/rsyncd.secrets</span>
rsyncuser:비밀번호
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 클라이언트에서 접속</span>
rsync <span class="nt">-avz</span> /var/www/html/ rsyncuser@backup-server::www-backup
</code></pre></div></div>

<h2 id="자동화-cron-설정">자동화 cron 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/cron.d/rsync-backup</span>
<span class="nv">SHELL</span><span class="o">=</span>/bin/bash
<span class="nv">PATH</span><span class="o">=</span>/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

<span class="c"># 매일 새벽 2시 전체 백업</span>
0 2 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> root /opt/full-backup.sh <span class="o">&gt;&gt;</span> /var/log/backup.log 2&gt;&amp;1

<span class="c"># 매시간 스냅샷 (증분)</span>
0 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> root /opt/snapshot-backup.sh <span class="o">&gt;&gt;</span> /var/log/snapshot.log 2&gt;&amp;1
</code></pre></div></div>

<h2 id="전송-속도-및-진행-상황-모니터링">전송 속도 및 진행 상황 모니터링</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 진행률과 함께 전송</span>
rsync <span class="nt">-avzP</span> /large-dir/ user@remote:/dest/

<span class="c"># 전송 완료 후 통계</span>
rsync <span class="nt">-avz</span> <span class="nt">--stats</span> /source/ user@remote:/dest/
</code></pre></div></div>

<p>rsync는 안정적이고 효율적인 백업 도구입니다. TCP-80.NET의 서버는 내부 네트워크를 이용한 정기 백업을 무료로 제공하지만, 추가적인 외부 백업을 직접 구성하면 데이터를 더욱 안전하게 보호할 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><summary type="html"><![CDATA[rsync 주요 옵션, SSH를 통한 원격 동기화, 증분 백업, 스냅샷 방식 백업, cron으로 자동화하는 방법까지 실전 rsync 활용법을 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Let’s Encrypt 와일드카드 SSL 인증서 발급하기</title><link href="https://tcp-80.net/blog/2024/08/12/lets-encrypt-wildcard/" rel="alternate" type="text/html" title="Let’s Encrypt 와일드카드 SSL 인증서 발급하기" /><published>2024-08-12T00:00:00+09:00</published><updated>2024-08-12T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/08/12/lets-encrypt-wildcard</id><content type="html" xml:base="https://tcp-80.net/blog/2024/08/12/lets-encrypt-wildcard/"><![CDATA[<p>일반 Let’s Encrypt 인증서는 특정 도메인에만 유효합니다. <code class="language-plaintext highlighter-rouge">*.example.com</code> 형태의 와일드카드 인증서는 모든 서브도메인을 하나의 인증서로 커버할 수 있어 편리합니다.</p>

<h2 id="와일드카드-인증서-특징">와일드카드 인증서 특징</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">*.example.com</code> → <code class="language-plaintext highlighter-rouge">blog.example.com</code>, <code class="language-plaintext highlighter-rouge">api.example.com</code>, <code class="language-plaintext highlighter-rouge">shop.example.com</code> 등 모두 커버</li>
  <li><strong>DNS TXT 레코드 인증 방식 필수</strong> (HTTP 파일 방식 불가)</li>
  <li>Certbot DNS 플러그인이나 수동 DNS 방식 사용</li>
</ul>

<h2 id="방법-1-수동-dns-인증-어떤-dns-서비스든-가능">방법 1: 수동 DNS 인증 (어떤 DNS 서비스든 가능)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># certbot 설치</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> certbot

<span class="c"># 수동 DNS 인증으로 와일드카드 발급</span>
<span class="nb">sudo </span>certbot certonly <span class="se">\</span>
    <span class="nt">--manual</span> <span class="se">\</span>
    <span class="nt">--preferred-challenges</span> dns <span class="se">\</span>
    <span class="nt">-d</span> <span class="s2">"*.example.com"</span> <span class="se">\</span>
    <span class="nt">-d</span> <span class="s2">"example.com"</span>
</code></pre></div></div>

<p>Certbot이 DNS TXT 레코드를 추가하라는 안내를 표시합니다:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Please deploy a DNS TXT record under the name:
_acme-challenge.example.com

with the following value:
aAbBcCdDeEfFgGhHiIjJkKlLmMnNoO1234567890

Once this is deployed,
Press Enter to Continue
</code></pre></div></div>

<p>DNS 관리 패널에서 <code class="language-plaintext highlighter-rouge">_acme-challenge.example.com</code> TXT 레코드를 추가하고 전파될 때까지 기다린 후 Enter를 누릅니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># DNS 전파 확인 (다른 터미널에서)</span>
dig TXT _acme-challenge.example.com
nslookup <span class="nt">-type</span><span class="o">=</span>TXT _acme-challenge.example.com 8.8.8.8
</code></pre></div></div>

<h2 id="방법-2-cloudflare-dns-플러그인-자동-갱신-가능">방법 2: Cloudflare DNS 플러그인 (자동 갱신 가능)</h2>

<p>Cloudflare를 DNS 서비스로 사용 중이라면 플러그인으로 자동화할 수 있습니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Cloudflare 플러그인 설치</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> python3-certbot-dns-cloudflare
<span class="c"># 또는</span>
pip3 <span class="nb">install </span>certbot-dns-cloudflare
</code></pre></div></div>

<p>Cloudflare API 키 파일 생성:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo mkdir</span> <span class="nt">-p</span> /etc/letsencrypt/
<span class="nb">sudo </span>nano /etc/letsencrypt/cloudflare.ini
</code></pre></div></div>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/letsencrypt/cloudflare.ini
</span><span class="py">dns_cloudflare_api_token</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">Cloudflare_API_토큰</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo chmod </span>600 /etc/letsencrypt/cloudflare.ini

<span class="c"># 와일드카드 인증서 발급 (완전 자동화)</span>
<span class="nb">sudo </span>certbot certonly <span class="se">\</span>
    <span class="nt">--dns-cloudflare</span> <span class="se">\</span>
    <span class="nt">--dns-cloudflare-credentials</span> /etc/letsencrypt/cloudflare.ini <span class="se">\</span>
    <span class="nt">-d</span> <span class="s2">"*.example.com"</span> <span class="se">\</span>
    <span class="nt">-d</span> <span class="s2">"example.com"</span>
</code></pre></div></div>

<h2 id="방법-3-route53-aws">방법 3: Route53 (AWS)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> python3-certbot-dns-route53

<span class="nb">sudo </span>certbot certonly <span class="se">\</span>
    <span class="nt">--dns-route53</span> <span class="se">\</span>
    <span class="nt">-d</span> <span class="s2">"*.example.com"</span> <span class="se">\</span>
    <span class="nt">-d</span> <span class="s2">"example.com"</span>
</code></pre></div></div>

<h2 id="발급된-인증서-확인">발급된 인증서 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 인증서 목록</span>
<span class="nb">sudo </span>certbot certificates

<span class="c"># 출력 예시:</span>
<span class="c"># Found the following certs:</span>
<span class="c">#   Certificate Name: example.com</span>
<span class="c">#     Domains: *.example.com example.com</span>
<span class="c">#     Expiry Date: 2024-11-10 (VALID: 89 days)</span>
<span class="c">#     Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem</span>
<span class="c">#     Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem</span>
</code></pre></div></div>

<h2 id="nginx에-와일드카드-인증서-적용">Nginx에 와일드카드 인증서 적용</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/sites-available/wildcard</span>
<span class="c1"># 모든 서브도메인에 동일한 인증서 사용</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">*.example.com</span> <span class="s">example.com</span><span class="p">;</span>
    <span class="kn">return</span> <span class="mi">301</span> <span class="s">https://</span><span class="nv">$host$request_uri</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">blog.example.com</span><span class="p">;</span>

    <span class="c1"># 하나의 인증서로 모든 서브도메인 커버</span>
    <span class="kn">ssl_certificate</span> <span class="n">/etc/letsencrypt/live/example.com/fullchain.pem</span><span class="p">;</span>
    <span class="kn">ssl_certificate_key</span> <span class="n">/etc/letsencrypt/live/example.com/privkey.pem</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:3001</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">api.example.com</span><span class="p">;</span>

    <span class="kn">ssl_certificate</span> <span class="n">/etc/letsencrypt/live/example.com/fullchain.pem</span><span class="p">;</span>
    <span class="kn">ssl_certificate_key</span> <span class="n">/etc/letsencrypt/live/example.com/privkey.pem</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:8080</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="자동-갱신-설정">자동 갱신 설정</h2>

<p>DNS 플러그인을 사용한 경우 자동 갱신이 가능합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 갱신 테스트</span>
<span class="nb">sudo </span>certbot renew <span class="nt">--dry-run</span>

<span class="c"># 갱신 타이머 확인</span>
<span class="nb">sudo </span>systemctl status certbot.timer

<span class="c"># 수동 갱신 크론 설정 (타이머가 없는 경우)</span>
<span class="nb">echo</span> <span class="s2">"0 0,12 * * * root certbot renew --quiet --dns-cloudflare </span><span class="se">\</span><span class="s2">
    --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini"</span> | <span class="se">\</span>
    <span class="nb">sudo tee</span> /etc/cron.d/certbot-renew
</code></pre></div></div>

<h2 id="수동-dns-방식-자동-갱신-갱신-후크">수동 DNS 방식 자동 갱신 (갱신 후크)</h2>

<p>수동 방식은 자동 갱신이 어렵습니다. 갱신 후크 스크립트로 부분 자동화할 수 있습니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh</span>
<span class="c">#!/bin/bash</span>
systemctl reload nginx
<span class="nb">echo</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">date</span><span class="si">)</span><span class="s2">: Nginx reloaded after certificate renewal"</span> <span class="o">&gt;&gt;</span> /var/log/certbot-renew.log
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo chmod</span> +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
</code></pre></div></div>

<h2 id="ssl-보안-설정-강화">SSL 보안 설정 강화</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/snippets/ssl-params.conf</span>
<span class="k">ssl_protocols</span> <span class="s">TLSv1.2</span> <span class="s">TLSv1.3</span><span class="p">;</span>
<span class="k">ssl_ciphers</span> <span class="s">ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384</span><span class="p">;</span>
<span class="k">ssl_prefer_server_ciphers</span> <span class="no">off</span><span class="p">;</span>

<span class="k">ssl_session_cache</span> <span class="s">shared:SSL:10m</span><span class="p">;</span>
<span class="k">ssl_session_timeout</span> <span class="s">1d</span><span class="p">;</span>
<span class="k">ssl_session_tickets</span> <span class="no">off</span><span class="p">;</span>

<span class="k">ssl_stapling</span> <span class="no">on</span><span class="p">;</span>
<span class="k">ssl_stapling_verify</span> <span class="no">on</span><span class="p">;</span>
<span class="k">resolver</span> <span class="mf">8.8</span><span class="s">.8.8</span> <span class="mf">8.8</span><span class="s">.4.4</span> <span class="s">valid=300s</span><span class="p">;</span>

<span class="k">add_header</span> <span class="s">Strict-Transport-Security</span> <span class="s">"max-age=63072000"</span> <span class="s">always</span><span class="p">;</span>
</code></pre></div></div>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span>
    <span class="kn">include</span> <span class="n">/etc/nginx/snippets/ssl-params.conf</span><span class="p">;</span>
    <span class="kn">ssl_certificate</span> <span class="n">/etc/letsencrypt/live/example.com/fullchain.pem</span><span class="p">;</span>
    <span class="kn">ssl_certificate_key</span> <span class="n">/etc/letsencrypt/live/example.com/privkey.pem</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>와일드카드 인증서 하나로 여러 서브도메인을 관리하면 인증서 갱신 부담을 크게 줄일 수 있습니다. Cloudflare 등 지원되는 DNS 서비스를 사용한다면 완전 자동화를 권장합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[*.example.com 형태의 와일드카드 SSL 인증서를 DNS 인증 방식으로 발급하고 Nginx에 적용하는 방법, 자동 갱신 설정까지 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Crontab 완전 가이드: 리눅스 작업 자동화 스케줄링</title><link href="https://tcp-80.net/blog/2024/07/29/crontab-guide/" rel="alternate" type="text/html" title="Crontab 완전 가이드: 리눅스 작업 자동화 스케줄링" /><published>2024-07-29T00:00:00+09:00</published><updated>2024-07-29T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/07/29/crontab-guide</id><content type="html" xml:base="https://tcp-80.net/blog/2024/07/29/crontab-guide/"><![CDATA[<p>cron은 리눅스에서 정해진 시간에 반복 작업을 실행하는 스케줄러입니다. 백업, 로그 정리, 모니터링, 인증서 갱신 등 수많은 서버 자동화 작업에 활용됩니다.</p>

<h2 id="crontab-기본-사용법">crontab 기본 사용법</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 현재 사용자의 crontab 편집</span>
crontab <span class="nt">-e</span>

<span class="c"># 현재 사용자의 crontab 목록 확인</span>
crontab <span class="nt">-l</span>

<span class="c"># crontab 삭제 (주의: 모두 삭제)</span>
crontab <span class="nt">-r</span>

<span class="c"># 특정 사용자의 crontab 편집/확인 (root만 가능)</span>
<span class="nb">sudo </span>crontab <span class="nt">-u</span> username <span class="nt">-e</span>
<span class="nb">sudo </span>crontab <span class="nt">-u</span> username <span class="nt">-l</span>
</code></pre></div></div>

<h2 id="시간-표현식-문법">시간 표현식 문법</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>분  시  일  월  요일  실행할명령어
*   *   *   *   *     command
│   │   │   │   └─ 요일 (0=일요일, 1=월요일, ..., 6=토요일, 7=일요일)
│   │   │   └──── 월 (1~12)
│   │   └──────── 일 (1~31)
│   └──────────── 시 (0~23)
└──────────────── 분 (0~59)
</code></pre></div></div>

<h3 id="특수-표현">특수 표현</h3>

<table>
  <thead>
    <tr>
      <th>표현</th>
      <th>의미</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">*</code></td>
      <td>모든 값</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">*/5</code></td>
      <td>5마다 (5분마다, 5시간마다)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">1-5</code></td>
      <td>1부터 5까지 (월~금요일)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">1,15</code></td>
      <td>1일과 15일</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">@reboot</code></td>
      <td>부팅 시 1회</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">@daily</code></td>
      <td>매일 자정 (0 0 * * *)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">@weekly</code></td>
      <td>매주 일요일 자정</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">@monthly</code></td>
      <td>매월 1일 자정</td>
    </tr>
  </tbody>
</table>

<h2 id="자주-쓰는-예제">자주 쓰는 예제</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 매 5분마다 실행</span>
<span class="k">*</span>/5 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /opt/monitor.sh

<span class="c"># 매일 새벽 3시에 실행</span>
0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /opt/backup.sh

<span class="c"># 매주 월요일 오전 9시에 실행</span>
0 9 <span class="k">*</span> <span class="k">*</span> 1 /opt/weekly-report.sh

<span class="c"># 평일(월~금) 오전 8시에 실행</span>
0 8 <span class="k">*</span> <span class="k">*</span> 1-5 /opt/workday.sh

<span class="c"># 매월 1일, 15일 실행</span>
0 0 1,15 <span class="k">*</span> <span class="k">*</span> /opt/billing.sh

<span class="c"># 매 시간 정각에 실행</span>
0 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /opt/hourly.sh

<span class="c"># 부팅 시 1회 실행</span>
@reboot /opt/startup.sh

<span class="c"># 매일 자정 (축약)</span>
@daily /opt/daily-cleanup.sh
</code></pre></div></div>

<h2 id="시스템-cron-vs-사용자-crontab">시스템 cron vs 사용자 crontab</h2>

<h3 id="사용자-crontab-crontab--e">사용자 crontab (<code class="language-plaintext highlighter-rouge">crontab -e</code>)</h3>
<ul>
  <li>특정 사용자 권한으로 실행</li>
  <li><code class="language-plaintext highlighter-rouge">분 시 일 월 요일 명령어</code> 형식</li>
</ul>

<h3 id="시스템-cron-etccrond-etccrontab">시스템 cron (<code class="language-plaintext highlighter-rouge">/etc/cron.d/</code>, <code class="language-plaintext highlighter-rouge">/etc/crontab</code>)</h3>
<ul>
  <li>사용자 지정 가능 (루트 권한 필요)</li>
  <li><code class="language-plaintext highlighter-rouge">분 시 일 월 요일 사용자 명령어</code> 형식 (사용자 필드 추가)</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/cron.d/myapp</span>
0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> root /opt/backup.sh <span class="o">&gt;&gt;</span> /var/log/backup.log 2&gt;&amp;1
0 2 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> www-data /opt/cleanup.sh
</code></pre></div></div>

<h3 id="시스템-cron-디렉터리">시스템 cron 디렉터리</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> /etc/cron.daily/    <span class="c"># 매일 실행</span>
<span class="nb">ls</span> /etc/cron.weekly/   <span class="c"># 매주 실행</span>
<span class="nb">ls</span> /etc/cron.monthly/  <span class="c"># 매월 실행</span>
<span class="nb">ls</span> /etc/cron.hourly/   <span class="c"># 매시간 실행</span>

<span class="c"># 스크립트를 해당 디렉터리에 넣으면 자동 실행 (실행 권한 필요)</span>
<span class="nb">sudo cp </span>myscript.sh /etc/cron.daily/
<span class="nb">sudo chmod</span> +x /etc/cron.daily/myscript.sh
</code></pre></div></div>

<h2 id="환경-변수와-path-문제">환경 변수와 PATH 문제</h2>

<p>cron 실행 환경은 일반 쉘과 다릅니다. PATH가 제한되어 있어 명령을 찾지 못하는 경우가 많습니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># crontab에서 PATH 명시적 설정</span>
<span class="nv">SHELL</span><span class="o">=</span>/bin/bash
<span class="nv">PATH</span><span class="o">=</span>/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /opt/backup.sh

<span class="c"># 또는 스크립트에서 절대 경로 사용</span>
/usr/bin/mysqldump <span class="nt">-u</span> root mydb <span class="o">&gt;</span> /backup/db.sql
/usr/local/bin/python3 /opt/script.py
</code></pre></div></div>

<h2 id="로그-출력-제어">로그 출력 제어</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 표준 출력과 오류를 모두 로그 파일에 저장</span>
0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /opt/backup.sh <span class="o">&gt;&gt;</span> /var/log/backup.log 2&gt;&amp;1

<span class="c"># 오류만 로그 파일에 저장 (표준 출력 버림)</span>
0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /opt/backup.sh <span class="o">&gt;</span> /dev/null 2&gt;&gt; /var/log/backup-error.log

<span class="c"># 모든 출력 버리기 (메일 발송도 없음)</span>
0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /opt/backup.sh <span class="o">&gt;</span> /dev/null 2&gt;&amp;1

<span class="c"># MAILTO 설정 (이메일로 출력 전송, 빈 문자열이면 발송 안 함)</span>
<span class="nv">MAILTO</span><span class="o">=</span><span class="s2">""</span>
0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /opt/backup.sh
</code></pre></div></div>

<h2 id="cron-실행-로그-확인">cron 실행 로그 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Ubuntu/Debian</span>
<span class="nb">sudo grep </span>CRON /var/log/syslog | <span class="nb">tail</span> <span class="nt">-20</span>

<span class="c"># CentOS/RHEL</span>
<span class="nb">sudo grep </span>CRON /var/log/cron | <span class="nb">tail</span> <span class="nt">-20</span>

<span class="c"># journalctl (systemd)</span>
<span class="nb">sudo </span>journalctl <span class="nt">-u</span> cron <span class="nt">-n</span> 50 <span class="nt">--no-pager</span>
</code></pre></div></div>

<h2 id="실전-cron-예제-모음">실전 cron 예제 모음</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 매일 새벽 3시 MySQL 백업</span>
0 3 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> mysqldump <span class="nt">-u</span> root <span class="nt">-p</span>비밀번호 <span class="nt">--all-databases</span> | <span class="nb">gzip</span> <span class="o">&gt;</span> /backup/mysql_<span class="si">$(</span><span class="nb">date</span> +<span class="se">\%</span>Y<span class="se">\%</span>m<span class="se">\%</span>d<span class="si">)</span>.sql.gz

<span class="c"># 매일 새벽 4시 30일 이상된 백업 파일 삭제</span>
30 4 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> find /backup <span class="nt">-name</span> <span class="s2">"*.sql.gz"</span> <span class="nt">-mtime</span> +30 <span class="nt">-delete</span>

<span class="c"># 매시간 디스크 사용량 확인</span>
0 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="nb">df</span> <span class="nt">-h</span> <span class="o">&gt;&gt;</span> /var/log/disk-usage.log

<span class="c"># 매일 자정 Nginx 로그 로테이트</span>
0 0 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="nb">kill</span> <span class="nt">-USR1</span> <span class="si">$(</span><span class="nb">cat</span> /var/run/nginx.pid<span class="si">)</span> <span class="o">&amp;&amp;</span> <span class="nb">sleep </span>1 <span class="o">&amp;&amp;</span> <span class="nb">mv</span> /var/log/nginx/access.log /var/log/nginx/access_<span class="si">$(</span><span class="nb">date</span> +<span class="se">\%</span>Y<span class="se">\%</span>m<span class="se">\%</span>d<span class="si">)</span>.log

<span class="c"># 5분마다 서비스 상태 체크</span>
<span class="k">*</span>/5 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> systemctl is-active nginx <span class="o">&gt;</span> /dev/null <span class="o">||</span> systemctl restart nginx

<span class="c"># 매월 1일 Let's Encrypt 인증서 갱신 시도</span>
0 0 1 <span class="k">*</span> <span class="k">*</span> certbot renew <span class="nt">--quiet</span>

<span class="c"># 부팅 시 VPN 재연결</span>
@reboot <span class="nb">sleep </span>30 <span class="o">&amp;&amp;</span> /usr/local/bin/wg-quick up wg0
</code></pre></div></div>

<h2 id="cron-작업-디버깅">cron 작업 디버깅</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># cron이 실행하는 것과 같은 환경에서 수동 실행</span>
<span class="nb">env</span> <span class="nt">-i</span> <span class="nv">HOME</span><span class="o">=</span>/root <span class="nv">SHELL</span><span class="o">=</span>/bin/bash <span class="nv">PATH</span><span class="o">=</span>/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin /opt/backup.sh

<span class="c"># cron 서비스 상태 확인</span>
<span class="nb">sudo </span>systemctl status cron

<span class="c"># cron 데몬 재시작</span>
<span class="nb">sudo </span>systemctl restart cron
</code></pre></div></div>

<p>cron을 잘 활용하면 서버 관리 업무의 상당 부분을 자동화할 수 있습니다. 중요한 자동화 작업은 로그를 남겨 정상 실행 여부를 정기적으로 확인하는 습관을 들이세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><summary type="html"><![CDATA[crontab 문법, 시간 표현식, 사용자별·시스템 cron 차이, 실행 로그 확인, 자주 쓰는 예제까지 리눅스 자동화 스케줄링 전반을 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Nginx 접속 로그 분석과 악성 봇 차단하기</title><link href="https://tcp-80.net/blog/2024/07/15/nginx-log-bot-blocking/" rel="alternate" type="text/html" title="Nginx 접속 로그 분석과 악성 봇 차단하기" /><published>2024-07-15T00:00:00+09:00</published><updated>2024-07-15T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/07/15/nginx-log-bot-blocking</id><content type="html" xml:base="https://tcp-80.net/blog/2024/07/15/nginx-log-bot-blocking/"><![CDATA[<p>Nginx 접속 로그에는 서버로 들어오는 모든 요청 정보가 담겨 있습니다. 로그를 분석하면 악성 봇, 보안 스캐너, DDoS 공격 패턴을 파악하고 차단할 수 있습니다.</p>

<h2 id="로그-형식-이해">로그 형식 이해</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/nginx.conf의 기본 로그 형식</span>
<span class="k">log_format</span> <span class="s">main</span> <span class="s">'</span><span class="nv">$remote_addr</span> <span class="s">-</span> <span class="nv">$remote_user</span> <span class="s">[</span><span class="nv">$time_local</span><span class="s">]</span> <span class="s">'</span>
                <span class="s">'"</span><span class="nv">$request</span><span class="s">"</span> <span class="nv">$status</span> <span class="nv">$body_bytes_sent</span> <span class="s">'</span>
                <span class="s">'"</span><span class="nv">$http_referer</span><span class="s">"</span> <span class="s">"</span><span class="nv">$http_user_agent</span><span class="s">"'</span><span class="p">;</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># 로그 샘플
203.0.113.55 - - [15/Jul/2024:03:24:15 +0900] "GET /wp-login.php HTTP/1.1" 404 162 "-" "Mozilla/5.0 zgrab/0.x"
</code></pre></div></div>

<h2 id="기본-로그-분석-명령어">기본 로그 분석 명령어</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 접속 로그 경로</span>
<span class="nv">ACCESS_LOG</span><span class="o">=</span><span class="s2">"/var/log/nginx/access.log"</span>

<span class="c"># 상위 10개 접속 IP</span>
<span class="nb">awk</span> <span class="s1">'{print $1}'</span> <span class="nv">$ACCESS_LOG</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-10</span>

<span class="c"># HTTP 상태 코드별 집계</span>
<span class="nb">awk</span> <span class="s1">'{print $9}'</span> <span class="nv">$ACCESS_LOG</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span>

<span class="c"># 상위 10개 요청 URL</span>
<span class="nb">awk</span> <span class="s1">'{print $7}'</span> <span class="nv">$ACCESS_LOG</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-10</span>

<span class="c"># 특정 IP의 요청 내역</span>
<span class="nb">grep</span> <span class="s2">"203.0.113.55"</span> <span class="nv">$ACCESS_LOG</span>

<span class="c"># 404 오류가 많은 URL (스캐너 탐지)</span>
<span class="nb">awk</span> <span class="s1">'$9 == 404 {print $7}'</span> <span class="nv">$ACCESS_LOG</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># User-Agent별 집계</span>
<span class="nb">awk</span> <span class="nt">-F</span><span class="s1">'"'</span> <span class="s1">'{print $6}'</span> <span class="nv">$ACCESS_LOG</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-10</span>
</code></pre></div></div>

<h2 id="악성-봇-식별-패턴">악성 봇 식별 패턴</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># WordPress 공격 스캐너 탐지</span>
<span class="nb">grep</span> <span class="s2">"wp-login</span><span class="se">\|</span><span class="s2">xmlrpc</span><span class="se">\|</span><span class="s2">wp-config</span><span class="se">\|</span><span class="s2">eval("</span> <span class="nv">$ACCESS_LOG</span> | <span class="nb">awk</span> <span class="s1">'{print $1}'</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span>

<span class="c"># 알려진 취약점 스캔 패턴</span>
<span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"</span><span class="se">\.</span><span class="s2">env|</span><span class="se">\.</span><span class="s2">git/|phpmyadmin|admin|setup</span><span class="se">\.</span><span class="s2">php|shell</span><span class="se">\.</span><span class="s2">php"</span> <span class="nv">$ACCESS_LOG</span> | <span class="nb">awk</span> <span class="s1">'{print $1}'</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span>

<span class="c"># 비정상적으로 많은 요청 (초당 100건 이상)</span>
<span class="nb">awk</span> <span class="s1">'{print $4}'</span> <span class="nv">$ACCESS_LOG</span> | <span class="nb">cut</span> <span class="nt">-d</span>: <span class="nt">-f1</span>,2,3 | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span>

<span class="c"># 알려진 악성 User-Agent</span>
<span class="nb">grep</span> <span class="nt">-i</span> <span class="s2">"zgrab</span><span class="se">\|</span><span class="s2">masscan</span><span class="se">\|</span><span class="s2">nikto</span><span class="se">\|</span><span class="s2">sqlmap</span><span class="se">\|</span><span class="s2">acunetix</span><span class="se">\|</span><span class="s2">nessus</span><span class="se">\|</span><span class="s2">nmap</span><span class="se">\|</span><span class="s2">dirbuster"</span> <span class="nv">$ACCESS_LOG</span>
</code></pre></div></div>

<h2 id="nginx에서-악성-봇-차단">Nginx에서 악성 봇 차단</h2>

<h3 id="user-agent-기반-차단">User-Agent 기반 차단</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/conf.d/block-bots.conf</span>
<span class="k">map</span> <span class="nv">$http_user_agent</span> <span class="nv">$bad_bot</span> <span class="p">{</span>
    <span class="kn">default</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kn">~*zgrab</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kn">~*masscan</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kn">~*nikto</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kn">~*sqlmap</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kn">~*acunetix</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kn">~*nessus</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kn">~*dirbuster</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kn">~*python-requests</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kn">~*Go-http-client</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kn">~*curl</span> <span class="mi">0</span><span class="p">;</span>  <span class="c1"># curl은 허용 (개발자 도구로 사용)</span>
<span class="p">}</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">if</span> <span class="s">(</span><span class="nv">$bad_bot</span><span class="s">)</span> <span class="p">{</span>
        <span class="kn">return</span> <span class="mi">444</span><span class="p">;</span>  <span class="c1"># 연결 즉시 종료 (응답 없음)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="ip-기반-차단">IP 기반 차단</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/conf.d/block-ips.conf</span>
<span class="k">geo</span> <span class="nv">$blocked_ip</span> <span class="p">{</span>
    <span class="kn">default</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kn">203.0.113.55</span> <span class="mi">1</span><span class="p">;</span>
    <span class="kn">198.51.100.0/24</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">if</span> <span class="s">(</span><span class="nv">$blocked_ip</span><span class="s">)</span> <span class="p">{</span>
        <span class="kn">return</span> <span class="mi">444</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="요청-속도-제한으로-봇-차단">요청 속도 제한으로 봇 차단</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># nginx.conf (http 블록)</span>
<span class="k">limit_req_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=api:10m</span> <span class="s">rate=10r/s</span><span class="p">;</span>
<span class="k">limit_req_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=login:10m</span> <span class="s">rate=3r/m</span><span class="p">;</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="c1"># API 엔드포인트</span>
    <span class="kn">location</span> <span class="n">/api/</span> <span class="p">{</span>
        <span class="kn">limit_req</span> <span class="s">zone=api</span> <span class="s">burst=20</span> <span class="s">nodelay</span><span class="p">;</span>
        <span class="kn">limit_req_status</span> <span class="mi">429</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># 로그인 페이지 (브루트포스 방어)</span>
    <span class="kn">location</span> <span class="n">/wp-login.php</span> <span class="p">{</span>
        <span class="kn">limit_req</span> <span class="s">zone=login</span> <span class="s">burst=5</span><span class="p">;</span>
        <span class="kn">limit_req_status</span> <span class="mi">429</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="악성-요청-패턴-차단">악성 요청 패턴 차단</h3>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="c1"># 숨겨진 파일 접근 차단 (.env, .git 등)</span>
    <span class="kn">location</span> <span class="p">~</span> <span class="sr">/\.</span> <span class="p">{</span>
        <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
        <span class="kn">access_log</span> <span class="no">off</span><span class="p">;</span>
        <span class="kn">log_not_found</span> <span class="no">off</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># 민감한 파일 직접 접근 차단</span>
    <span class="kn">location</span> <span class="p">~</span><span class="sr">*</span> <span class="err">\</span><span class="s">.(env|sql|bak|backup|config|log)</span>$ <span class="p">{</span>
        <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># PHP 파일 업로드 디렉터리에서 실행 차단</span>
    <span class="kn">location</span> <span class="p">~</span><span class="sr">*</span> <span class="n">/uploads/.*\.php</span>$ <span class="p">{</span>
        <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># 비정상 요청 메서드 차단</span>
    <span class="kn">if</span> <span class="s">(</span><span class="nv">$request_method</span> <span class="s">!~</span> <span class="s">^(GET|POST|HEAD|OPTIONS)</span>$<span class="s">)</span> <span class="p">{</span>
        <span class="kn">return</span> <span class="mi">405</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="goaccess로-실시간-시각화">GoAccess로 실시간 시각화</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># GoAccess 설치</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> goaccess

<span class="c"># 터미널에서 실시간 분석</span>
<span class="nb">sudo </span>goaccess /var/log/nginx/access.log <span class="nt">--log-format</span><span class="o">=</span>COMBINED

<span class="c"># HTML 리포트 생성</span>
<span class="nb">sudo </span>goaccess /var/log/nginx/access.log <span class="se">\</span>
    <span class="nt">--log-format</span><span class="o">=</span>COMBINED <span class="se">\</span>
    <span class="nt">-o</span> /var/www/html/report.html <span class="se">\</span>
    <span class="nt">--real-time-html</span> <span class="se">\</span>
    <span class="nt">--daemonize</span>

<span class="c"># 특정 기간 분석</span>
zcat /var/log/nginx/access.log.<span class="k">*</span>.gz | goaccess <span class="nt">--log-format</span><span class="o">=</span>COMBINED
</code></pre></div></div>

<h2 id="자동-차단-스크립트">자동 차단 스크립트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /opt/auto-block.sh</span>
<span class="c"># 10분 내 500회 이상 요청한 IP 자동 차단</span>

<span class="nv">LOG</span><span class="o">=</span><span class="s2">"/var/log/nginx/access.log"</span>
<span class="nv">THRESHOLD</span><span class="o">=</span>500
<span class="nv">WINDOW</span><span class="o">=</span>600  <span class="c"># 10분 (초)</span>

<span class="c"># 최근 10분간 로그만 분석</span>
<span class="nv">START_TIME</span><span class="o">=</span><span class="si">$(</span><span class="nb">date</span> <span class="nt">-d</span> <span class="s2">"-</span><span class="k">${</span><span class="nv">WINDOW</span><span class="k">}</span><span class="s2"> seconds"</span> <span class="s1">'+%d/%b/%Y:%H:%M:%S'</span><span class="si">)</span>

<span class="nb">awk</span> <span class="nt">-v</span> <span class="nv">start</span><span class="o">=</span><span class="s2">"</span><span class="nv">$START_TIME</span><span class="s2">"</span> <span class="s1">'
{
    # 타임스탬프 파싱
    split($4, t, ":");
    if (t[2]":"t[3]":"t[4] &gt;= substr(start, 13)) {
        count[$1]++
    }
}
END {
    for (ip in count) {
        if (count[ip] &gt; '</span><span class="s2">"</span><span class="nv">$THRESHOLD</span><span class="s2">"</span><span class="s1">') {
            print ip, count[ip]
        }
    }
}'</span> <span class="nv">$LOG</span> | <span class="k">while </span><span class="nb">read </span>ip count<span class="p">;</span> <span class="k">do
    if</span> <span class="o">!</span> <span class="nb">sudo </span>ufw status | <span class="nb">grep</span> <span class="nt">-q</span> <span class="s2">"</span><span class="nv">$ip</span><span class="s2">"</span><span class="p">;</span> <span class="k">then
        </span><span class="nb">sudo </span>ufw insert 1 deny from <span class="nv">$ip</span>
        <span class="nb">echo</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">date</span><span class="si">)</span><span class="s2">: Blocked </span><span class="nv">$ip</span><span class="s2"> (</span><span class="nv">$count</span><span class="s2"> requests in </span><span class="k">${</span><span class="nv">WINDOW</span><span class="k">}</span><span class="s2">s)"</span> <span class="o">&gt;&gt;</span> /var/log/auto-block.log
    <span class="k">fi
done</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 5분마다 실행</span>
<span class="nb">echo</span> <span class="s2">"*/5 * * * * root /opt/auto-block.sh"</span> | <span class="nb">sudo tee</span> /etc/cron.d/auto-block
</code></pre></div></div>

<p>로그 분석을 통한 사전 차단이 DDoS나 봇 공격을 효율적으로 막는 방법 중 하나입니다. TCP-80.NET은 자체 DDoS 방어 시스템을 통해 대규모 공격을 네트워크 레벨에서 차단합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[Nginx 접속 로그 분석으로 악성 봇과 스캐너를 식별하고, User-Agent 및 IP 기반으로 차단하는 방법, 그리고 GoAccess로 실시간 모니터링하는 방법을 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">서버 침해 사고 대응: 해킹당했을 때 취해야 할 조치</title><link href="https://tcp-80.net/blog/2024/07/01/server-incident-response/" rel="alternate" type="text/html" title="서버 침해 사고 대응: 해킹당했을 때 취해야 할 조치" /><published>2024-07-01T00:00:00+09:00</published><updated>2024-07-01T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/07/01/server-incident-response</id><content type="html" xml:base="https://tcp-80.net/blog/2024/07/01/server-incident-response/"><![CDATA[<p>서버 침해 사고는 발생하지 않도록 예방하는 것이 최선이지만, 실제로 발생했을 때 올바른 대응 절차를 알아두는 것도 중요합니다. 패닉 상태에서 잘못된 조치를 취하면 증거가 사라지거나 상황이 악화될 수 있습니다.</p>

<h2 id="침해-징후-식별">침해 징후 식별</h2>

<p>다음 징후가 하나라도 있다면 침해를 의심해야 합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 알 수 없는 로그인 기록</span>
last | <span class="nb">head</span> <span class="nt">-20</span>
lastb | <span class="nb">head</span> <span class="nt">-20</span>   <span class="c"># 실패한 로그인</span>

<span class="c"># 비정상적인 프로세스</span>
ps aux | <span class="nb">grep</span> <span class="nt">-v</span> <span class="s2">"</span><span class="se">\[</span><span class="s2">"</span> | <span class="nb">sort</span> <span class="nt">-k3</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-20</span>
top <span class="nt">-bn1</span> | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># 외부로 나가는 이상한 연결</span>
ss <span class="nt">-tnp</span> | <span class="nb">grep </span>ESTABLISHED
netstat <span class="nt">-tnp</span> 2&gt;/dev/null

<span class="c"># 루트 권한으로 실행 중인 프로세스</span>
ps aux | <span class="nb">awk</span> <span class="s1">'$1 == "root" {print}'</span>

<span class="c"># 최근 변경된 파일</span>
find /etc /usr/bin /usr/sbin <span class="nt">-newer</span> /etc/passwd <span class="nt">-type</span> f 2&gt;/dev/null
find /var/www <span class="nt">-newer</span> /etc/cron.d <span class="nt">-name</span> <span class="s2">"*.php"</span> 2&gt;/dev/null
</code></pre></div></div>

<h2 id="1단계-네트워크-격리-즉각-조치">1단계: 네트워크 격리 (즉각 조치)</h2>

<p>서비스를 즉시 종료하기보다 증거 수집을 위해 상황을 파악하되, 추가 피해를 막기 위한 조치를 취합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 의심스러운 IP 즉시 차단</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-s</span> 의심IP <span class="nt">-j</span> DROP
<span class="nb">sudo </span>iptables <span class="nt">-A</span> OUTPUT <span class="nt">-d</span> 의심IP <span class="nt">-j</span> DROP

<span class="c"># 특정 포트 임시 차단 (해당 서비스 중단 감수)</span>
<span class="nb">sudo </span>ufw deny out 443    <span class="c"># 예: HTTPS 아웃바운드 차단</span>

<span class="c"># 방화벽 전체 차단 (극단적 조치, 서비스 완전 중단)</span>
<span class="c"># sudo ufw default deny outgoing</span>
</code></pre></div></div>

<h2 id="2단계-증거-수집-중요">2단계: 증거 수집 (중요)</h2>

<p>시스템 포맷 전에 반드시 증거를 수집하세요:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 메모리 내 프로세스 목록 저장</span>
ps auxf <span class="o">&gt;</span> /tmp/processes_<span class="si">$(</span><span class="nb">date</span> +%Y%m%d%H%M<span class="si">)</span>.txt

<span class="c"># 네트워크 연결 상태 저장</span>
ss <span class="nt">-tnp</span> <span class="o">&gt;</span> /tmp/connections_<span class="si">$(</span><span class="nb">date</span> +%Y%m%d%H%M<span class="si">)</span>.txt
netstat <span class="nt">-rn</span> <span class="o">&gt;</span> /tmp/routes_<span class="si">$(</span><span class="nb">date</span> +%Y%m%d%H%M<span class="si">)</span>.txt

<span class="c"># 최근 수정 파일 목록</span>
find / <span class="nt">-newer</span> /etc/passwd <span class="nt">-type</span> f 2&gt;/dev/null <span class="o">&gt;</span> /tmp/modified_files.txt

<span class="c"># 로그 파일 백업</span>
<span class="nb">sudo cp</span> <span class="nt">-r</span> /var/log /tmp/log_backup_<span class="si">$(</span><span class="nb">date</span> +%Y%m%d<span class="si">)</span>

<span class="c"># 크론탭 확인</span>
crontab <span class="nt">-l</span> <span class="o">&gt;</span> /tmp/crontab_root.txt
<span class="k">for </span>user <span class="k">in</span> <span class="si">$(</span><span class="nb">cut</span> <span class="nt">-d</span>: <span class="nt">-f1</span> /etc/passwd<span class="si">)</span><span class="p">;</span> <span class="k">do
    </span>crontab <span class="nt">-u</span> <span class="nv">$user</span> <span class="nt">-l</span> 2&gt;/dev/null <span class="o">&gt;&gt;</span> /tmp/crontabs_all.txt
<span class="k">done</span>

<span class="c"># 인증 로그 백업</span>
<span class="nb">sudo cp</span> /var/log/auth.log /tmp/auth_backup.log
</code></pre></div></div>

<h2 id="3단계-침해-범위-파악">3단계: 침해 범위 파악</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 최근 수정된 시스템 파일 (웹쉘, 백도어)</span>
find /var/www <span class="nt">-name</span> <span class="s2">"*.php"</span> <span class="nt">-newer</span> /var/www/html/index.php <span class="nt">-ls</span>
find /tmp /var/tmp <span class="nt">-type</span> f <span class="nt">-ls</span>

<span class="c"># SUID 파일 변경 확인</span>
find / <span class="nt">-perm</span> <span class="nt">-4000</span> <span class="nt">-type</span> f <span class="nt">-ls</span> 2&gt;/dev/null

<span class="c"># /etc/passwd 수상한 계정 확인</span>
<span class="nb">cat</span> /etc/passwd | <span class="nb">grep</span> <span class="nt">-v</span> <span class="s2">"nologin</span><span class="se">\|</span><span class="s2">false"</span> | <span class="nb">grep</span> <span class="nt">-v</span> root

<span class="c"># 숨겨진 프로세스 (rootkit 탐지)</span>
ps aux | <span class="nb">awk</span> <span class="s1">'{print $1}'</span> | <span class="nb">sort</span> <span class="o">&gt;</span> /tmp/ps.txt
<span class="nb">ls</span> /proc | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s1">'^[0-9]+$'</span> | <span class="nb">sort</span> <span class="o">&gt;</span> /tmp/proc.txt
diff /tmp/ps.txt /tmp/proc.txt

<span class="c"># 네트워크 인터페이스 확인 (promiscuous 모드: 스니핑 의심)</span>
ip <span class="nb">link </span>show | <span class="nb">grep </span>PROMISC
</code></pre></div></div>

<h2 id="4단계-악성-파일-제거">4단계: 악성 파일 제거</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 웹쉘 탐색 (PHP 웹쉘 패턴)</span>
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"eval(base64_decode"</span> /var/www/ 2&gt;/dev/null
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"system("</span> /var/www/ 2&gt;/dev/null
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"passthru</span><span class="se">\|</span><span class="s2">shell_exec</span><span class="se">\|</span><span class="s2">exec("</span> /var/www/ 2&gt;/dev/null

<span class="c"># 백도어 사용자 확인 및 삭제</span>
<span class="nb">cat</span> /etc/passwd | <span class="nb">awk</span> <span class="nt">-F</span>: <span class="s1">'$3 == 0 &amp;&amp; $1 != "root" {print $1}'</span>
<span class="c"># 루트 권한(UID 0)이 있는 불법 계정 삭제</span>
<span class="nb">sudo </span>userdel <span class="nt">-r</span> 의심계정

<span class="c"># 악성 크론탭 제거</span>
crontab <span class="nt">-r</span>

<span class="c"># 의심스러운 프로세스 종료</span>
<span class="nb">sudo kill</span> <span class="nt">-9</span> 프로세스PID
</code></pre></div></div>

<h2 id="5단계-비밀번호-및-키-초기화">5단계: 비밀번호 및 키 초기화</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 모든 계정 비밀번호 변경</span>
<span class="nb">echo</span> <span class="s2">"root:새비밀번호"</span> | <span class="nb">sudo </span>chpasswd
<span class="nb">echo</span> <span class="s2">"admin:새비밀번호"</span> | <span class="nb">sudo </span>chpasswd

<span class="c"># SSH 키 초기화</span>
<span class="nb">sudo rm</span> /root/.ssh/authorized_keys
<span class="nb">sudo rm</span> /home/<span class="k">*</span>/.ssh/authorized_keys
<span class="c"># 재발급 후 본인 키만 등록</span>

<span class="c"># API 키, 데이터베이스 비밀번호 즉시 변경</span>
<span class="c"># 애플리케이션의 .env, config.php 등 설정 파일의 비밀번호 교체</span>
</code></pre></div></div>

<h2 id="6단계-취약점-파악-및-패치">6단계: 취약점 파악 및 패치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 최신 보안 업데이트 적용</span>
<span class="nb">sudo </span>apt update <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>apt upgrade <span class="nt">-y</span>

<span class="c"># 알려진 취약점 스캐너</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> lynis
<span class="nb">sudo </span>lynis audit system

<span class="c"># 오픈 포트 확인</span>
<span class="nb">sudo </span>nmap <span class="nt">-sV</span> localhost
</code></pre></div></div>

<h2 id="7단계-서비스-복구">7단계: 서비스 복구</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 서비스 재시작 전 설정 파일 검증</span>
<span class="nb">sudo </span>nginx <span class="nt">-t</span>
<span class="nb">sudo </span>php-fpm8.2 <span class="nt">-t</span>

<span class="c"># 정상 백업에서 복원</span>
rsync <span class="nt">-av</span> /backup/최신날짜/ /var/www/html/

<span class="c"># 데이터베이스 복원</span>
mysql <span class="nt">-u</span> root <span class="nt">-p</span> myapp &lt; /backup/db_backup.sql

<span class="c"># 권한 재설정</span>
<span class="nb">sudo chown</span> <span class="nt">-R</span> www-data:www-data /var/www/html
<span class="nb">sudo </span>find /var/www/html <span class="nt">-type</span> f <span class="nt">-exec</span> <span class="nb">chmod </span>644 <span class="o">{}</span> <span class="se">\;</span>
<span class="nb">sudo </span>find /var/www/html <span class="nt">-type</span> d <span class="nt">-exec</span> <span class="nb">chmod </span>755 <span class="o">{}</span> <span class="se">\;</span>
</code></pre></div></div>

<h2 id="재발-방지-조치">재발 방지 조치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 웹 파일 무결성 모니터링 (aide)</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> aide
<span class="nb">sudo </span>aideinit
<span class="nb">sudo </span>aide <span class="nt">--check</span>

<span class="c"># 파일 변경 감지 (inotifywait)</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> inotify-tools
inotifywait <span class="nt">-m</span> <span class="nt">-r</span> /var/www/html <span class="nt">-e</span> modify,create,delete
</code></pre></div></div>

<p>침해 사고가 발생했다면 TCP-80.NET 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 즉시 연락하세요. 서버 격리 조치와 복구를 지원해 드립니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="보안" /><category term="Linux" /><summary type="html"><![CDATA[서버가 해킹당한 것 같을 때 당황하지 않고 침해 범위를 파악하고, 서비스를 복구하며, 재발을 방지하는 단계별 대응 절차를 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">apt 자동 보안 업데이트 설정으로 서버 취약점 방어하기</title><link href="https://tcp-80.net/blog/2024/06/17/unattended-upgrades/" rel="alternate" type="text/html" title="apt 자동 보안 업데이트 설정으로 서버 취약점 방어하기" /><published>2024-06-17T00:00:00+09:00</published><updated>2024-06-17T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/06/17/unattended-upgrades</id><content type="html" xml:base="https://tcp-80.net/blog/2024/06/17/unattended-upgrades/"><![CDATA[<p>패치되지 않은 취약점은 공격자에게 서버 침입의 문을 열어줍니다. 하지만 매일 직접 업데이트하기는 현실적으로 어렵습니다. <code class="language-plaintext highlighter-rouge">unattended-upgrades</code>로 보안 패치를 자동 적용하면 이 문제를 해결할 수 있습니다.</p>

<h2 id="패키지-설치">패키지 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> unattended-upgrades apt-listchanges
</code></pre></div></div>

<h2 id="자동-업데이트-설정-마법사">자동 업데이트 설정 마법사</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 대화형 설정</span>
<span class="nb">sudo </span>dpkg-reconfigure <span class="nt">-plow</span> unattended-upgrades
<span class="c"># "자동 업데이트를 활성화할까요?" → 예 선택</span>
</code></pre></div></div>

<h2 id="상세-설정">상세 설정</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/apt/apt.conf.d/50unattended-upgrades</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Unattended-Upgrade::Allowed-Origins {
    // Ubuntu 보안 업데이트
    "${distro_id}:${distro_codename}";
    "${distro_id}:${distro_codename}-security";
    // Debian 보안 업데이트
    "origin=Debian,codename=${distro_codename},label=Debian-Security";
};

// 자동 제거 (사용하지 않는 패키지)
Unattended-Upgrade::Remove-Unused-Dependencies "true";

// 자동 재부팅 (커널 업데이트 등)
Unattended-Upgrade::Automatic-Reboot "false";

// 재부팅이 필요한 경우 자동 재부팅 시간 (false이면 비활성화)
Unattended-Upgrade::Automatic-Reboot-Time "03:00";

// 이메일 알림 (설정 시)
// Unattended-Upgrade::Mail "admin@example.com";
// Unattended-Upgrade::MailReport "on-change";  // 변경사항 있을 때만

// 업데이트 로그 위치
Unattended-Upgrade::SyslogEnable "true";
</code></pre></div></div>

<h2 id="업데이트-주기-설정">업데이트 주기 설정</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/apt/apt.conf.d/20auto-upgrades</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// 패키지 목록 업데이트 주기 (일)
APT::Periodic::Update-Package-Lists "1";

// 다운로드 주기
APT::Periodic::Download-Upgradeable-Packages "1";

// 자동 업데이트 주기 (0: 비활성화, 1: 매일)
APT::Periodic::Unattended-Upgrade "1";

// 다운로드 캐시 보존 기간 (일)
APT::Periodic::AutocleanInterval "7";
</code></pre></div></div>

<h2 id="테스트-및-확인">테스트 및 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 실제 적용 없이 시뮬레이션</span>
<span class="nb">sudo </span>unattended-upgrade <span class="nt">--dry-run</span> <span class="nt">--debug</span>

<span class="c"># 즉시 실행 (테스트)</span>
<span class="nb">sudo </span>unattended-upgrade <span class="nt">-v</span>

<span class="c"># 타이머 상태 확인</span>
<span class="nb">sudo </span>systemctl status apt-daily-upgrade.timer
<span class="nb">sudo </span>systemctl status apt-daily.timer

<span class="c"># 예약 실행 시간 확인</span>
<span class="nb">sudo </span>systemctl list-timers | <span class="nb">grep </span>apt
</code></pre></div></div>

<h2 id="업데이트-로그-확인">업데이트 로그 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># unattended-upgrades 로그</span>
<span class="nb">sudo tail</span> <span class="nt">-f</span> /var/log/unattended-upgrades/unattended-upgrades.log

<span class="c"># 적용된 업데이트 기록</span>
<span class="nb">cat</span> /var/log/unattended-upgrades/unattended-upgrades.log | <span class="nb">grep</span> <span class="s2">"Packages that"</span>

<span class="c"># dpkg 로그 (모든 패키지 변경 기록)</span>
<span class="nb">sudo tail</span> <span class="nt">-100</span> /var/log/dpkg.log

<span class="c"># 재부팅이 필요한지 확인</span>
<span class="nb">cat</span> /var/run/reboot-required 2&gt;/dev/null <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"재부팅 필요"</span> <span class="o">||</span> <span class="nb">echo</span> <span class="s2">"재부팅 불필요"</span>
<span class="nb">ls</span> /var/run/reboot-required.pkgs 2&gt;/dev/null
</code></pre></div></div>

<h2 id="자동-재부팅-정책">자동 재부팅 정책</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 재부팅이 필요할 때 서비스 중단 시간을 정해 자동 재부팅</span>
<span class="c"># /etc/apt/apt.conf.d/50unattended-upgrades 에서:</span>

<span class="c"># 자동 재부팅 활성화 (주의: 서비스 중단 발생)</span>
Unattended-Upgrade::Automatic-Reboot <span class="s2">"true"</span><span class="p">;</span>
Unattended-Upgrade::Automatic-Reboot-Time <span class="s2">"04:00"</span><span class="p">;</span>  <span class="c"># 새벽 4시</span>

<span class="c"># 사용자 로그인 중에도 재부팅</span>
Unattended-Upgrade::Automatic-Reboot-WithUsers <span class="s2">"false"</span><span class="p">;</span>
</code></pre></div></div>

<blockquote>
  <p><strong>권장</strong>: 프로덕션 서버는 <code class="language-plaintext highlighter-rouge">Automatic-Reboot "false"</code>로 설정하고, 수동으로 재부팅 일정을 잡는 것이 안전합니다.</p>
</blockquote>

<h2 id="특정-패키지-제외">특정 패키지 제외</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 업데이트에서 제외할 패키지 (예: nginx, mysql)</span>
Unattended-Upgrade::Package-Blacklist <span class="o">{</span>
    <span class="s2">"nginx"</span><span class="p">;</span>
    <span class="s2">"mysql-server"</span><span class="p">;</span>
    <span class="s2">"php*"</span><span class="p">;</span>
<span class="o">}</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="업데이트-상태-모니터링-스크립트">업데이트 상태 모니터링 스크립트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /opt/check-updates.sh</span>

<span class="nb">echo</span> <span class="s2">"=== </span><span class="si">$(</span><span class="nb">date</span> <span class="s1">'+%Y-%m-%d'</span><span class="si">)</span><span class="s2"> 업데이트 현황 ==="</span>

<span class="c"># 보안 업데이트 가능 패키지 수</span>
<span class="nv">SECURITY</span><span class="o">=</span><span class="si">$(</span>apt list <span class="nt">--upgradeable</span> 2&gt;/dev/null | <span class="nb">grep</span> <span class="nt">-i</span> security | <span class="nb">wc</span> <span class="nt">-l</span><span class="si">)</span>
<span class="nv">ALL</span><span class="o">=</span><span class="si">$(</span>apt list <span class="nt">--upgradeable</span> 2&gt;/dev/null | <span class="nb">grep</span> <span class="nt">-c</span> upgradeable<span class="si">)</span>

<span class="nb">echo</span> <span class="s2">"전체 업데이트 가능: </span><span class="nv">$ALL</span><span class="s2"> 개"</span>
<span class="nb">echo</span> <span class="s2">"보안 업데이트: </span><span class="nv">$SECURITY</span><span class="s2"> 개"</span>

<span class="k">if</span> <span class="o">[</span> <span class="nt">-f</span> /var/run/reboot-required <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"⚠️  재부팅 필요"</span>
<span class="k">fi</span>
</code></pre></div></div>

<h2 id="centosrhel-자동-업데이트">CentOS/RHEL 자동 업데이트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># dnf-automatic 설치</span>
<span class="nb">sudo </span>dnf <span class="nb">install</span> <span class="nt">-y</span> dnf-automatic

<span class="c"># 설정 파일</span>
<span class="nb">sudo </span>vi /etc/dnf/automatic.conf

<span class="c"># 보안 업데이트만 자동 적용</span>
upgrade_type <span class="o">=</span> security
apply_updates <span class="o">=</span> <span class="nb">yes</span>

<span class="c"># 타이머 활성화</span>
<span class="nb">sudo </span>systemctl <span class="nb">enable</span> <span class="nt">--now</span> dnf-automatic.timer
</code></pre></div></div>

<p>자동 보안 업데이트는 알려진 취약점으로 인한 피해를 크게 줄여줍니다. 단, 일부 패키지(Nginx, PHP 등)는 업데이트 시 설정 변경이 발생할 수 있으므로, 자동 업데이트에서 제외하고 수동으로 관리하는 것도 고려하세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[unattended-upgrades로 보안 패치를 자동 적용하고, 업데이트 로그 확인, 재부팅 정책, 이메일 알림까지 리눅스 서버 자동 업데이트 완전 가이드입니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">새 리눅스 서버 초기 설정 체크리스트</title><link href="https://tcp-80.net/blog/2024/06/03/linux-server-initial-setup/" rel="alternate" type="text/html" title="새 리눅스 서버 초기 설정 체크리스트" /><published>2024-06-03T00:00:00+09:00</published><updated>2024-06-03T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/06/03/linux-server-initial-setup</id><content type="html" xml:base="https://tcp-80.net/blog/2024/06/03/linux-server-initial-setup/"><![CDATA[<p>새 서버를 개설하면 수분 내에 자동화된 공격 스캔이 시작됩니다. 서버를 받자마자 기본 보안 설정을 마쳐야 합니다. 이 체크리스트대로 따라 하면 5분 안에 기본 보안 환경을 구축할 수 있습니다.</p>

<h2 id="1단계-시스템-업데이트">1단계: 시스템 업데이트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Ubuntu/Debian</span>
<span class="nb">sudo </span>apt update <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>apt upgrade <span class="nt">-y</span>

<span class="c"># CentOS/RHEL</span>
<span class="nb">sudo </span>dnf update <span class="nt">-y</span>
</code></pre></div></div>

<h2 id="2단계-관리자-계정-생성-root-직접-사용-금지">2단계: 관리자 계정 생성 (root 직접 사용 금지)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 새 관리자 계정 생성</span>
<span class="nb">sudo </span>adduser admin

<span class="c"># sudo 권한 부여</span>
<span class="nb">sudo </span>usermod <span class="nt">-aG</span> <span class="nb">sudo </span>admin

<span class="c"># 새 계정으로 전환 후 sudo 테스트</span>
su - admin
<span class="nb">sudo whoami</span>   <span class="c"># root가 출력되어야 함</span>
</code></pre></div></div>

<h2 id="3단계-ssh-키-인증-설정">3단계: SSH 키 인증 설정</h2>

<p>로컬 PC에서:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SSH 키 생성 (이미 있으면 생략)</span>
ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-C</span> <span class="s2">"my-server"</span>

<span class="c"># 공개키를 서버에 복사</span>
ssh-copy-id admin@서버IP
</code></pre></div></div>

<p>서버에서 SSH 설정 강화 (<code class="language-plaintext highlighter-rouge">/etc/ssh/sshd_config</code>):</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 루트 로그인 비활성화
</span><span class="na">PermitRootLogin</span><span class="w"> </span><span class="na">no</span><span class="w">

</span><span class="c"># 비밀번호 로그인 비활성화 (키 인증 확인 후)
</span><span class="na">PasswordAuthentication</span><span class="w"> </span><span class="na">no</span><span class="w">

</span><span class="c"># 빈 비밀번호 금지
</span><span class="na">PermitEmptyPasswords</span><span class="w"> </span><span class="na">no</span><span class="w">

</span><span class="c"># 최대 인증 시도 횟수
</span><span class="na">MaxAuthTries</span><span class="w"> </span><span class="na">3</span><span class="w">

</span><span class="c"># 접속 타임아웃
</span><span class="na">LoginGraceTime</span><span class="w"> </span><span class="na">30</span><span class="w">
</span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 설정 적용 전 새 터미널에서 키 인증 테스트!</span>
<span class="nb">sudo </span>systemctl restart sshd
</code></pre></div></div>

<h2 id="4단계-방화벽-설정">4단계: 방화벽 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># UFW 설치 및 활성화</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> ufw

<span class="c"># 기본 정책</span>
<span class="nb">sudo </span>ufw default deny incoming
<span class="nb">sudo </span>ufw default allow outgoing

<span class="c"># SSH 허용 (변경했다면 해당 포트)</span>
<span class="nb">sudo </span>ufw allow 22/tcp

<span class="c"># 웹 서버 운영 시</span>
<span class="nb">sudo </span>ufw allow 80/tcp
<span class="nb">sudo </span>ufw allow 443/tcp

<span class="c"># 방화벽 활성화</span>
<span class="nb">sudo </span>ufw <span class="nb">enable
sudo </span>ufw status
</code></pre></div></div>

<h2 id="5단계-fail2ban-설치">5단계: fail2ban 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> fail2ban

<span class="c"># 기본 설정으로 SSH 보호 시작</span>
<span class="nb">sudo </span>systemctl <span class="nb">enable</span> <span class="nt">--now</span> fail2ban
<span class="nb">sudo </span>fail2ban-client status sshd
</code></pre></div></div>

<h2 id="6단계-자동-보안-업데이트">6단계: 자동 보안 업데이트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> unattended-upgrades
<span class="nb">sudo </span>dpkg-reconfigure <span class="nt">-plow</span> unattended-upgrades
<span class="c"># 또는</span>
<span class="nb">sudo </span>unattended-upgrade <span class="nt">--dry-run</span>   <span class="c"># 테스트</span>
</code></pre></div></div>

<h2 id="7단계-불필요한-서비스-비활성화">7단계: 불필요한 서비스 비활성화</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 실행 중인 서비스 확인</span>
<span class="nb">sudo </span>systemctl list-units <span class="nt">--type</span><span class="o">=</span>service <span class="nt">--state</span><span class="o">=</span>running

<span class="c"># 불필요한 서비스 비활성화 예시</span>
<span class="nb">sudo </span>systemctl disable <span class="nt">--now</span> avahi-daemon
<span class="nb">sudo </span>systemctl disable <span class="nt">--now</span> cups
<span class="nb">sudo </span>systemctl disable <span class="nt">--now</span> bluetooth
</code></pre></div></div>

<h2 id="8단계-시간-동기화-설정">8단계: 시간 동기화 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 시간대 설정</span>
<span class="nb">sudo </span>timedatectl set-timezone Asia/Seoul

<span class="c"># NTP 동기화 확인</span>
timedatectl status
<span class="nb">sudo </span>systemctl status systemd-timesyncd
</code></pre></div></div>

<h2 id="9단계-스왑-설정-메모리가-적은-서버">9단계: 스왑 설정 (메모리가 적은 서버)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 1GB 스왑 파일 생성</span>
<span class="nb">sudo </span>fallocate <span class="nt">-l</span> 1G /swapfile
<span class="nb">sudo chmod </span>600 /swapfile
<span class="nb">sudo </span>mkswap /swapfile
<span class="nb">sudo </span>swapon /swapfile

<span class="c"># 영구 적용</span>
<span class="nb">echo</span> <span class="s1">'/swapfile none swap sw 0 0'</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/fstab
</code></pre></div></div>

<h2 id="10단계-기본-모니터링-도구-설치">10단계: 기본 모니터링 도구 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 유용한 도구 설치</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> <span class="se">\</span>
    htop <span class="se">\ </span>      <span class="c"># 시스템 모니터</span>
    iotop <span class="se">\ </span>     <span class="c"># 디스크 I/O 모니터</span>
    net-tools <span class="se">\ </span> <span class="c"># netstat 등</span>
    curl wget <span class="se">\ </span> <span class="c"># 다운로드</span>
    vim <span class="se">\ </span>       <span class="c"># 에디터</span>
    tmux         <span class="c"># 터미널 멀티플렉서</span>
</code></pre></div></div>

<h2 id="초기-설정-완료-확인">초기 설정 완료 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 방화벽 상태</span>
<span class="nb">sudo </span>ufw status

<span class="c"># SSH 설정 확인</span>
sshd <span class="nt">-T</span> | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"permitrootlogin|passwordauthentication|maxauthtries"</span>

<span class="c"># fail2ban 상태</span>
<span class="nb">sudo </span>fail2ban-client status

<span class="c"># 자동 업데이트 상태</span>
systemctl status unattended-upgrades

<span class="c"># 시스템 업데이트 날짜</span>
<span class="nb">sudo </span>apt-get <span class="nt">-s</span> upgrade 2&gt;/dev/null | <span class="nb">grep</span> <span class="s2">"^[0-9]"</span>
</code></pre></div></div>

<h2 id="보안-점검-요약">보안 점검 요약</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✅ 시스템 패키지 최신 상태
✅ root 직접 로그인 차단
✅ SSH 키 인증 설정
✅ 비밀번호 로그인 비활성화
✅ 방화벽 활성화 (필요한 포트만 허용)
✅ fail2ban으로 브루트포스 방어
✅ 자동 보안 업데이트 설정
✅ 불필요한 서비스 비활성화
</code></pre></div></div>

<p>이 체크리스트를 완료하면 기본적인 서버 보안은 갖춰진 상태입니다. 이후에는 서비스에 맞는 추가 보안 설정(Nginx SSL, MySQL 보안, WordPress 강화 등)을 적용하세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[새 서버를 개설하면 가장 먼저 해야 할 초기 보안 설정을 단계별로 정리했습니다. 사용자 생성, SSH 강화, 방화벽, 자동 업데이트까지 5분 안에 기본 보안 구축하기.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">PHP-FPM 최적화: 성능과 보안 동시에 잡기</title><link href="https://tcp-80.net/blog/2024/05/20/php-fpm-optimization/" rel="alternate" type="text/html" title="PHP-FPM 최적화: 성능과 보안 동시에 잡기" /><published>2024-05-20T00:00:00+09:00</published><updated>2024-05-20T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/05/20/php-fpm-optimization</id><content type="html" xml:base="https://tcp-80.net/blog/2024/05/20/php-fpm-optimization/"><![CDATA[<p>PHP-FPM(FastCGI Process Manager)의 기본 설정은 보수적이어서 서버 메모리를 제대로 활용하지 못합니다. 올바른 설정으로 PHP 애플리케이션 성능을 크게 향상시킬 수 있습니다.</p>

<h2 id="php-fpm-설치">PHP-FPM 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Ubuntu</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> php8.2-fpm

<span class="c"># 상태 확인</span>
<span class="nb">sudo </span>systemctl status php8.2-fpm
</code></pre></div></div>

<h2 id="pmprocess-manager-설정-방식">pm(Process Manager) 설정 방식</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/php/8.2/fpm/pool.d/www.conf</code>:</p>

<h3 id="dynamic-권장-일반-서버">dynamic (권장: 일반 서버)</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="py">pm</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">dynamic</span>
<span class="w">
</span><span class="c"># 최소 유지할 유휴 워커 수
</span><span class="py">pm.min_spare_servers</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2</span>
<span class="w">
</span><span class="c"># 최대 유지할 유휴 워커 수
</span><span class="py">pm.max_spare_servers</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">5</span>
<span class="w">
</span><span class="c"># 시작 시 워커 수
</span><span class="py">pm.start_servers</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">3</span>
<span class="w">
</span><span class="c"># 최대 동시 처리 가능 요청 수
</span><span class="py">pm.max_children</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">20</span>
</code></pre></div></div>

<h3 id="static-고트래픽-서버">static (고트래픽 서버)</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="py">pm</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">static</span>
<span class="py">pm.max_children</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">30   # 항상 이 수만큼 워커 유지</span>
</code></pre></div></div>

<h3 id="ondemand-저사양-서버">ondemand (저사양 서버)</h3>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="py">pm</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">ondemand</span>
<span class="py">pm.max_children</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10</span>
<span class="py">pm.process_idle_timeout</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10s   # 유휴 워커 종료 대기 시간</span>
</code></pre></div></div>

<h2 id="max_children-계산법">max_children 계산법</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># PHP 프로세스 하나의 평균 메모리 사용량 확인</span>
ps aux | <span class="nb">grep </span>php-fpm | <span class="nb">awk</span> <span class="s1">'{print $6}'</span> | <span class="nb">sort</span> <span class="nt">-n</span> | <span class="nb">tail</span> <span class="nt">-5</span>

<span class="c"># 계산 공식:</span>
<span class="c"># max_children = (사용 가능한 메모리) / (PHP 프로세스 평균 메모리)</span>
<span class="c"># 예: 4GB RAM, PHP 프로세스당 50MB = 4096 / 50 ≈ 80</span>
<span class="c"># 단, 다른 서비스(Nginx, MySQL 등) 메모리 여유분을 남겨두어야 함</span>
</code></pre></div></div>

<h2 id="요청-처리-제한">요청 처리 제한</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 워커 하나가 처리할 최대 요청 수 (메모리 누수 방어)
</span><span class="py">pm.max_requests</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">500</span>
<span class="w">
</span><span class="c"># 단일 요청 최대 실행 시간 (초)
</span><span class="py">request_terminate_timeout</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">60s</span>
</code></pre></div></div>

<h2 id="느린-요청-로그-slow-log">느린 요청 로그 (Slow Log)</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 실행 시간이 긴 PHP 요청 기록
</span><span class="py">slowlog</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/php8.2-fpm-slow.log</span>
<span class="py">request_slowlog_timeout</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">5s   # 5초 이상 걸리는 요청 기록</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 느린 로그 확인</span>
<span class="nb">sudo tail</span> <span class="nt">-f</span> /var/log/php8.2-fpm-slow.log
</code></pre></div></div>

<h2 id="보안-설정">보안 설정</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 특정 디렉터리 외 PHP 실행 차단 (중요!)
</span><span class="py">security.limit_extensions</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">.php</span>
<span class="w">
</span><span class="c"># 환경 변수 노출 방지
</span><span class="py">clear_env</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">no</span>
<span class="w">
</span><span class="c"># open_basedir로 접근 가능한 디렉터리 제한
</span><span class="na">php_admin_value</span><span class="nn">[open_basedir]</span><span class="w"> </span><span class="na">=</span><span class="w"> </span><span class="na">/var/www/html:/tmp</span><span class="w">

</span><span class="c"># 위험 PHP 함수 비활성화
</span><span class="na">php_admin_value</span><span class="nn">[disable_functions]</span><span class="w"> </span><span class="na">=</span><span class="w"> </span><span class="na">exec,passthru,shell_exec,system,proc_open,popen</span><span class="w">
</span></code></pre></div></div>

<h2 id="phpini-성능-설정">php.ini 성능 설정</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/php/8.2/fpm/php.ini
</span><span class="w">
</span><span class="c">; OPcache 활성화 (PHP 코드 캐싱으로 성능 향상)
</span><span class="py">opcache.enable</span><span class="p">=</span><span class="s">1</span>
<span class="py">opcache.memory_consumption</span><span class="p">=</span><span class="s">128</span>
<span class="py">opcache.interned_strings_buffer</span><span class="p">=</span><span class="s">8</span>
<span class="py">opcache.max_accelerated_files</span><span class="p">=</span><span class="s">4000</span>
<span class="py">opcache.revalidate_freq</span><span class="p">=</span><span class="s">60</span>
<span class="py">opcache.fast_shutdown</span><span class="p">=</span><span class="s">1</span>
<span class="w">
</span><span class="c">; 메모리 제한
</span><span class="py">memory_limit</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">256M</span>
<span class="w">
</span><span class="c">; 업로드 제한
</span><span class="py">upload_max_filesize</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">20M</span>
<span class="py">post_max_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">20M</span>
<span class="w">
</span><span class="c">; 최대 실행 시간
</span><span class="py">max_execution_time</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">30</span>
<span class="w">
</span><span class="c">; 에러 로그 (프로덕션에서는 화면 출력 비활성화)
</span><span class="py">display_errors</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">Off</span>
<span class="py">log_errors</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">On</span>
<span class="py">error_log</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/php8.2-error.log</span>
</code></pre></div></div>

<h2 id="nginx와-php-fpm-연동">Nginx와 PHP-FPM 연동</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/sites-available/mysite</span>
<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">example.com</span><span class="p">;</span>
    <span class="kn">root</span> <span class="n">/var/www/html</span><span class="p">;</span>
    <span class="kn">index</span> <span class="s">index.php</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">try_files</span> <span class="nv">$uri</span> <span class="nv">$uri</span><span class="n">/</span> <span class="n">/index.php?</span><span class="nv">$query_string</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kn">location</span> <span class="p">~</span> <span class="sr">\.php$</span> <span class="p">{</span>
        <span class="c1"># PHP-FPM 소켓 (TCP 대신 Unix 소켓이 빠름)</span>
        <span class="kn">fastcgi_pass</span> <span class="s">unix:/run/php/php8.2-fpm.sock</span><span class="p">;</span>

        <span class="kn">fastcgi_index</span> <span class="s">index.php</span><span class="p">;</span>
        <span class="kn">fastcgi_param</span> <span class="s">SCRIPT_FILENAME</span> <span class="nv">$realpath_root$fastcgi_script_name</span><span class="p">;</span>
        <span class="kn">include</span> <span class="s">fastcgi_params</span><span class="p">;</span>

        <span class="c1"># 타임아웃 (php.ini의 max_execution_time과 맞춤)</span>
        <span class="kn">fastcgi_read_timeout</span> <span class="s">60s</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># 업로드 디렉터리 PHP 실행 차단</span>
    <span class="kn">location</span> <span class="p">~</span> <span class="sr">^/uploads/.*\.php$</span> <span class="p">{</span>
        <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="설정-적용-및-검증">설정 적용 및 검증</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 설정 문법 검사</span>
<span class="nb">sudo </span>php-fpm8.2 <span class="nt">-t</span>

<span class="c"># 재시작</span>
<span class="nb">sudo </span>systemctl reload php8.2-fpm

<span class="c"># 상태 및 워커 수 확인</span>
<span class="nb">sudo </span>systemctl status php8.2-fpm
ps aux | <span class="nb">grep </span>php-fpm | <span class="nb">wc</span> <span class="nt">-l</span>

<span class="c"># OPcache 상태 확인</span>
php <span class="nt">-r</span> <span class="s2">"var_dump(opcache_get_status());"</span>
</code></pre></div></div>

<h2 id="멀티-사이트-풀-설정">멀티 사이트 풀 설정</h2>

<p>여러 사이트를 운영할 때는 사이트별로 별도 풀을 만드는 것이 보안상 안전합니다:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /etc/php/8.2/fpm/pool.d/site1.conf
</span><span class="nn">[site1]</span><span class="w">
</span><span class="py">user</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">site1user</span>
<span class="py">group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">site1user</span>
<span class="py">listen</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/run/php/php8.2-fpm-site1.sock</span>
<span class="py">listen.owner</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">www-data</span>
<span class="py">listen.group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">www-data</span>
<span class="py">pm</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">dynamic</span>
<span class="py">pm.max_children</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10</span>
<span class="py">pm.start_servers</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2</span>
<span class="py">pm.min_spare_servers</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1</span>
<span class="py">pm.max_spare_servers</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">3</span>
</code></pre></div></div>

<p>PHP-FPM 최적화는 WordPress, Laravel 등 PHP 기반 애플리케이션의 응답 속도와 안정성에 직접적인 영향을 줍니다. 서버 메모리에 맞는 <code class="language-plaintext highlighter-rouge">max_children</code> 설정이 가장 중요합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="성능" /><summary type="html"><![CDATA[PHP-FPM의 pm 설정, worker 수 계산법, 느린 로그, 보안 설정까지 Nginx와 함께 사용하는 PHP-FPM 튜닝 가이드를 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">서버 디스크 용량 관리: df, du, 정리 자동화</title><link href="https://tcp-80.net/blog/2024/05/06/disk-space-management/" rel="alternate" type="text/html" title="서버 디스크 용량 관리: df, du, 정리 자동화" /><published>2024-05-06T00:00:00+09:00</published><updated>2024-05-06T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/05/06/disk-space-management</id><content type="html" xml:base="https://tcp-80.net/blog/2024/05/06/disk-space-management/"><![CDATA[<p>디스크가 꽉 차면 서버는 갑자기 다운될 수 있습니다. 로그 파일이나 임시 파일이 쌓여 발생하는 디스크 부족 문제를 예방하고 대응하는 방법을 알아봅니다.</p>

<h2 id="현재-디스크-상황-파악">현재 디스크 상황 파악</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 전체 디스크 사용량 (사람이 읽기 쉬운 형식)</span>
<span class="nb">df</span> <span class="nt">-h</span>

<span class="c"># 출력 예시:</span>
<span class="c"># Filesystem      Size  Used Avail Use% Mounted on</span>
<span class="c"># /dev/sda1        50G   38G  9.5G  80% /</span>
<span class="c"># /dev/sdb1       500G  230G  245G  49% /data</span>

<span class="c"># inode 사용량 확인 (파일 수가 많을 때 inode 부족 발생 가능)</span>
<span class="nb">df</span> <span class="nt">-i</span>
</code></pre></div></div>

<h2 id="du로-디렉터리별-사용량-분석">du로 디렉터리별 사용량 분석</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 특정 디렉터리의 사용량</span>
<span class="nb">du</span> <span class="nt">-sh</span> /var/log

<span class="c"># 현재 디렉터리의 하위 항목별 사용량 (1단계)</span>
<span class="nb">du</span> <span class="nt">-h</span> <span class="nt">--max-depth</span><span class="o">=</span>1 /var | <span class="nb">sort</span> <span class="nt">-rh</span>

<span class="c"># 상위 10개 대용량 디렉터리 찾기</span>
<span class="nb">du</span> <span class="nt">-h</span> /var | <span class="nb">sort</span> <span class="nt">-rh</span> | <span class="nb">head</span> <span class="nt">-10</span>

<span class="c"># /var/log 하위 정리</span>
<span class="nb">du</span> <span class="nt">-sh</span> /var/log/<span class="k">*</span>
</code></pre></div></div>

<h2 id="대용량-파일-찾기">대용량 파일 찾기</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 100MB 이상 파일 찾기</span>
find / <span class="nt">-type</span> f <span class="nt">-size</span> +100M <span class="nt">-exec</span> <span class="nb">ls</span> <span class="nt">-lh</span> <span class="o">{}</span> <span class="se">\;</span> 2&gt;/dev/null

<span class="c"># 1GB 이상 파일 (사람이 읽기 쉬운 정렬)</span>
find / <span class="nt">-type</span> f <span class="nt">-size</span> +1G 2&gt;/dev/null | xargs <span class="nb">ls</span> <span class="nt">-lh</span> | <span class="nb">sort</span> <span class="nt">-k5</span> <span class="nt">-rh</span>

<span class="c"># 특정 디렉터리에서 최근 수정된 대용량 파일</span>
find /var <span class="nt">-type</span> f <span class="nt">-size</span> +50M <span class="nt">-mtime</span> <span class="nt">-7</span> <span class="nt">-ls</span>
</code></pre></div></div>

<h2 id="로그-파일-정리">로그 파일 정리</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Nginx 로그 수동 압축</span>
<span class="nb">gzip</span> /var/log/nginx/access.log.1

<span class="c"># journald 로그 정리 (systemd)</span>
<span class="nb">sudo </span>journalctl <span class="nt">--disk-usage</span>
<span class="nb">sudo </span>journalctl <span class="nt">--vacuum-time</span><span class="o">=</span>7d     <span class="c"># 7일 이상된 로그 삭제</span>
<span class="nb">sudo </span>journalctl <span class="nt">--vacuum-size</span><span class="o">=</span>500M   <span class="c"># 500MB 초과분 삭제</span>

<span class="c"># 오래된 로그 삭제</span>
find /var/log <span class="nt">-name</span> <span class="s2">"*.log"</span> <span class="nt">-mtime</span> +30 <span class="nt">-delete</span>
find /var/log <span class="nt">-name</span> <span class="s2">"*.gz"</span> <span class="nt">-mtime</span> +60 <span class="nt">-delete</span>
</code></pre></div></div>

<h2 id="임시-파일-정리">임시 파일 정리</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /tmp 정리 (오래된 파일)</span>
find /tmp <span class="nt">-type</span> f <span class="nt">-atime</span> +7 <span class="nt">-delete</span>

<span class="c"># apt 캐시 정리</span>
<span class="nb">sudo </span>apt clean
<span class="nb">sudo </span>apt autoremove <span class="nt">-y</span>

<span class="c"># Docker 미사용 리소스 정리</span>
docker system prune <span class="nt">-a</span>

<span class="c"># pip 캐시 정리</span>
pip cache purge

<span class="c"># npm 캐시 정리</span>
npm cache clean <span class="nt">--force</span>
</code></pre></div></div>

<h2 id="디스크-사용량-모니터링-스크립트">디스크 사용량 모니터링 스크립트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /opt/disk-alert.sh</span>
<span class="c"># 디스크 사용량이 임계값 초과 시 알림</span>

<span class="nv">THRESHOLD</span><span class="o">=</span>80
<span class="nv">ALERT_LOG</span><span class="o">=</span><span class="s2">"/var/log/disk-alert.log"</span>

<span class="nb">df</span> <span class="nt">-h</span> | <span class="nb">grep</span> <span class="nt">-vE</span> <span class="s1">'^Filesystem|tmpfs|cdrom'</span> | <span class="k">while </span><span class="nb">read </span>line<span class="p">;</span> <span class="k">do
    </span><span class="nv">USAGE</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="nv">$line</span> | <span class="nb">awk</span> <span class="s1">'{print $5}'</span> | <span class="nb">sed</span> <span class="s1">'s/%//'</span><span class="si">)</span>
    <span class="nv">MOUNT</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="nv">$line</span> | <span class="nb">awk</span> <span class="s1">'{print $6}'</span><span class="si">)</span>

    <span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$USAGE</span><span class="s2">"</span> <span class="nt">-gt</span> <span class="s2">"</span><span class="nv">$THRESHOLD</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
        </span><span class="nv">MSG</span><span class="o">=</span><span class="s2">"[ALERT] </span><span class="si">$(</span><span class="nb">date</span> <span class="s1">'+%Y-%m-%d %H:%M'</span><span class="si">)</span><span class="s2"> - </span><span class="nv">$MOUNT</span><span class="s2">: </span><span class="k">${</span><span class="nv">USAGE</span><span class="k">}</span><span class="s2">% 사용 중"</span>
        <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$MSG</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> <span class="nv">$ALERT_LOG</span>
        <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$MSG</span><span class="s2">"</span>

        <span class="c"># 텔레그램 알림 (선택)</span>
        <span class="c"># curl -s "https://api.telegram.org/bot토큰/sendMessage" \</span>
        <span class="c">#     -d "chat_id=채팅ID&amp;text=$MSG"</span>
    <span class="k">fi
done</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 실행 권한 부여 및 cron 등록 (1시간마다 실행)</span>
<span class="nb">chmod</span> +x /opt/disk-alert.sh
<span class="nb">echo</span> <span class="s2">"0 * * * * root /opt/disk-alert.sh"</span> | <span class="nb">sudo tee</span> /etc/cron.d/disk-alert
</code></pre></div></div>

<h2 id="디스크-사용량-정기-리포트">디스크 사용량 정기 리포트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /opt/disk-report.sh</span>
<span class="c"># 매주 디스크 현황 리포트</span>

<span class="nv">REPORT</span><span class="o">=</span><span class="si">$(</span><span class="nb">df</span> <span class="nt">-h</span> | <span class="nb">grep</span> <span class="nt">-v</span> tmpfs<span class="si">)</span>

<span class="nb">echo</span> <span class="s2">"=== 서버 디스크 현황 </span><span class="si">$(</span><span class="nb">date</span> <span class="s1">'+%Y년 %m월 %d일'</span><span class="si">)</span><span class="s2"> ==="</span>
<span class="nb">echo</span> <span class="s2">"</span><span class="nv">$REPORT</span><span class="s2">"</span>
<span class="nb">echo</span> <span class="s2">""</span>
<span class="nb">echo</span> <span class="s2">"=== 대용량 파일 TOP 10 ==="</span>
find / <span class="nt">-type</span> f <span class="nt">-size</span> +100M <span class="nt">-exec</span> <span class="nb">ls</span> <span class="nt">-lh</span> <span class="o">{}</span> <span class="se">\;</span> 2&gt;/dev/null | <span class="nb">sort</span> <span class="nt">-k5</span> <span class="nt">-rh</span> | <span class="nb">head</span> <span class="nt">-10</span>
</code></pre></div></div>

<h2 id="디스크가-꽉-찬-경우-긴급-조치">디스크가 꽉 찬 경우 긴급 조치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 1. 현황 파악</span>
<span class="nb">df</span> <span class="nt">-h</span> <span class="o">&amp;&amp;</span> <span class="nb">du</span> <span class="nt">-sh</span> /<span class="k">*</span> 2&gt;/dev/null | <span class="nb">sort</span> <span class="nt">-rh</span> | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># 2. 대용량 파일 즉시 삭제</span>
find /var/log <span class="nt">-name</span> <span class="s2">"*.log"</span> <span class="nt">-size</span> +100M <span class="nt">-delete</span>

<span class="c"># 3. 오래된 백업 파일 삭제</span>
find /backup <span class="nt">-mtime</span> +30 <span class="nt">-delete</span>

<span class="c"># 4. 패키지 캐시 정리</span>
<span class="nb">sudo </span>apt clean

<span class="c"># 5. journald 로그 축소</span>
<span class="nb">sudo </span>journalctl <span class="nt">--vacuum-size</span><span class="o">=</span>100M

<span class="c"># 6. 임시 파일 정리</span>
<span class="nb">sudo rm</span> <span class="nt">-rf</span> /tmp/<span class="k">*</span> /var/tmp/<span class="k">*</span>
</code></pre></div></div>

<h2 id="파티션-별-모니터링">파티션 별 모니터링</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 디스크 I/O 통계</span>
iostat <span class="nt">-x</span> 1 5

<span class="c"># 특정 프로세스의 디스크 사용량</span>
<span class="nb">sudo </span>iotop

<span class="c"># 디스크 상태 확인 (SMART)</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> smartmontools
<span class="nb">sudo </span>smartctl <span class="nt">-a</span> /dev/sda
</code></pre></div></div>

<p>디스크 부족은 서버 장애의 흔한 원인입니다. logrotate 설정(별도 포스팅 참조)과 함께 주기적인 정리 스크립트를 운영하면 디스크 부족으로 인한 장애를 예방할 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><summary type="html"><![CDATA[df와 du 명령어로 디스크 사용량을 분석하고, 로그·임시 파일 정리, 대용량 파일 찾기, 디스크 용량 알림 설정까지 서버 디스크 관리 전반을 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">리눅스 사용자 및 파일 권한 관리</title><link href="https://tcp-80.net/blog/2024/04/22/linux-user-management/" rel="alternate" type="text/html" title="리눅스 사용자 및 파일 권한 관리" /><published>2024-04-22T00:00:00+09:00</published><updated>2024-04-22T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/04/22/linux-user-management</id><content type="html" xml:base="https://tcp-80.net/blog/2024/04/22/linux-user-management/"><![CDATA[<p>리눅스 서버에서 적절한 사용자와 권한 관리는 보안의 기본입니다. 최소 권한 원칙(Principle of Least Privilege)에 따라 각 서비스와 사용자에게 필요한 최소한의 권한만 부여해야 합니다.</p>

<h2 id="사용자-관리">사용자 관리</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 사용자 생성 (홈 디렉터리 자동 생성)</span>
<span class="nb">sudo </span>useradd <span class="nt">-m</span> <span class="nt">-s</span> /bin/bash username

<span class="c"># 비밀번호 설정</span>
<span class="nb">sudo </span>passwd username

<span class="c"># 사용자 정보 수정</span>
<span class="nb">sudo </span>usermod <span class="nt">-c</span> <span class="s2">"Full Name"</span> username       <span class="c"># 코멘트(이름) 변경</span>
<span class="nb">sudo </span>usermod <span class="nt">-s</span> /bin/zsh username          <span class="c"># 기본 셸 변경</span>
<span class="nb">sudo </span>usermod <span class="nt">-d</span> /new/home username         <span class="c"># 홈 디렉터리 변경</span>

<span class="c"># 사용자 삭제 (홈 디렉터리 및 메일함 포함)</span>
<span class="nb">sudo </span>userdel <span class="nt">-r</span> username

<span class="c"># 현재 로그인한 사용자</span>
<span class="nb">whoami
who
</span>w
</code></pre></div></div>

<h2 id="그룹-관리">그룹 관리</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 그룹 생성</span>
<span class="nb">sudo </span>groupadd developers

<span class="c"># 사용자를 그룹에 추가</span>
<span class="nb">sudo </span>usermod <span class="nt">-aG</span> developers username   <span class="c"># -a: 기존 그룹 유지</span>

<span class="c"># 사용자가 속한 그룹 확인</span>
<span class="nb">groups </span>username
<span class="nb">id </span>username

<span class="c"># 그룹에서 사용자 제거</span>
<span class="nb">sudo </span>gpasswd <span class="nt">-d</span> username developers

<span class="c"># 그룹 삭제</span>
<span class="nb">sudo </span>groupdel developers
</code></pre></div></div>

<h2 id="sudo-권한-설정">sudo 권한 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># sudo 그룹에 추가 (Ubuntu: sudo, CentOS: wheel)</span>
<span class="nb">sudo </span>usermod <span class="nt">-aG</span> <span class="nb">sudo </span>username

<span class="c"># sudoers 파일 직접 편집 (항상 visudo 사용)</span>
<span class="nb">sudo </span>visudo
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># /etc/sudoers 설정 예시

# 특정 명령어만 허용 (비밀번호 필요)
username ALL=(ALL) /usr/bin/apt, /usr/bin/systemctl

# 비밀번호 없이 특정 명령 실행
username ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx

# 개발팀 그룹 sudo 허용
%developers ALL=(ALL:ALL) ALL
</code></pre></div></div>

<h2 id="파일-권한-이해">파일 권한 이해</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-rwxr-xr--  1  owner  group  size  date  filename
 ^^^
 |||
 ||└─ other (기타 사용자): r-- = 4 (읽기만)
 |└── group (그룹):        r-x = 5 (읽기+실행)
 └─── owner (소유자):      rwx = 7 (읽기+쓰기+실행)
</code></pre></div></div>

<p>권한 값:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">r</code> (읽기) = 4</li>
  <li><code class="language-plaintext highlighter-rouge">w</code> (쓰기) = 2</li>
  <li><code class="language-plaintext highlighter-rouge">x</code> (실행) = 1</li>
</ul>

<h2 id="chmod로-권한-변경">chmod로 권한 변경</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 숫자 방식</span>
<span class="nb">chmod </span>755 file.sh    <span class="c"># rwxr-xr-x (소유자: 7, 그룹: 5, 기타: 5)</span>
<span class="nb">chmod </span>644 file.txt   <span class="c"># rw-r--r-- (소유자: 6, 그룹: 4, 기타: 4)</span>
<span class="nb">chmod </span>600 key.pem    <span class="c"># rw------- (소유자만 읽기/쓰기)</span>
<span class="nb">chmod </span>700 ~/.ssh     <span class="c"># rwx------ (소유자만 모든 권한)</span>

<span class="c"># 기호 방식</span>
<span class="nb">chmod </span>u+x file.sh    <span class="c"># 소유자에 실행 권한 추가</span>
<span class="nb">chmod </span>g-w file.txt   <span class="c"># 그룹에서 쓰기 권한 제거</span>
<span class="nb">chmod </span>o-rwx file     <span class="c"># 기타 사용자 모든 권한 제거</span>
<span class="nb">chmod </span>a+r file       <span class="c"># 모든 사용자에 읽기 권한 추가</span>

<span class="c"># 재귀 적용</span>
<span class="nb">chmod</span> <span class="nt">-R</span> 755 /var/www/html
</code></pre></div></div>

<h2 id="chown으로-소유자-변경">chown으로 소유자 변경</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 소유자 변경</span>
<span class="nb">sudo chown </span>username file.txt

<span class="c"># 소유자와 그룹 함께 변경</span>
<span class="nb">sudo chown </span>username:groupname file.txt

<span class="c"># 그룹만 변경</span>
<span class="nb">sudo chown</span> :groupname file.txt
<span class="c"># 또는</span>
<span class="nb">sudo chgrp </span>groupname file.txt

<span class="c"># 재귀 적용</span>
<span class="nb">sudo chown</span> <span class="nt">-R</span> www-data:www-data /var/www/html
</code></pre></div></div>

<h2 id="특수-권한">특수 권한</h2>

<h3 id="suid-set-user-id">SUID (Set User ID)</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 실행 시 소유자의 권한으로 실행 (예: passwd 명령)</span>
<span class="nb">chmod </span>u+s /usr/bin/myprog
<span class="c"># 또는: chmod 4755 /usr/bin/myprog</span>

<span class="c"># SUID 파일 찾기 (보안 점검)</span>
find / <span class="nt">-perm</span> <span class="nt">-4000</span> <span class="nt">-type</span> f 2&gt;/dev/null
</code></pre></div></div>

<h3 id="sgid-set-group-id">SGID (Set Group ID)</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 디렉터리에 적용 시: 해당 디렉터리에서 생성되는 파일이 디렉터리의 그룹 상속</span>
<span class="nb">chmod </span>g+s /shared/project
<span class="c"># 또는: chmod 2755 /shared/project</span>
</code></pre></div></div>

<h3 id="sticky-bit">Sticky Bit</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 디렉터리에서 본인 파일만 삭제 가능 (예: /tmp)</span>
<span class="nb">chmod</span> +t /tmp
<span class="c"># 또는: chmod 1777 /tmp</span>
</code></pre></div></div>

<h2 id="웹-서버-디렉터리-권한-설정">웹 서버 디렉터리 권한 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 웹 루트 디렉터리 권한 (Nginx/Apache: www-data 사용자)</span>
<span class="nb">sudo chown</span> <span class="nt">-R</span> www-data:www-data /var/www/html
<span class="nb">sudo </span>find /var/www/html <span class="nt">-type</span> d <span class="nt">-exec</span> <span class="nb">chmod </span>755 <span class="o">{}</span> <span class="se">\;</span>
<span class="nb">sudo </span>find /var/www/html <span class="nt">-type</span> f <span class="nt">-exec</span> <span class="nb">chmod </span>644 <span class="o">{}</span> <span class="se">\;</span>

<span class="c"># 업로드 디렉터리는 쓰기 허용</span>
<span class="nb">sudo chmod </span>775 /var/www/html/uploads
<span class="nb">sudo chown</span> <span class="nt">-R</span> www-data:www-data /var/www/html/uploads
</code></pre></div></div>

<h2 id="파일-권한-점검">파일 권한 점검</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 기타 사용자가 쓰기 가능한 파일 찾기 (보안 위험)</span>
find /var/www <span class="nt">-perm</span> <span class="nt">-o</span>+w <span class="nt">-type</span> f

<span class="c"># 소유자 없는 파일 찾기</span>
find / <span class="nt">-nouser</span> <span class="nt">-nogroup</span> 2&gt;/dev/null

<span class="c"># 권한이 없는 파일로 인한 Nginx 403 오류 진단</span>
<span class="nb">sudo</span> <span class="nt">-u</span> www-data <span class="nb">ls</span> /var/www/html/
</code></pre></div></div>

<p>적절한 권한 관리는 서버 보안의 기반입니다. 특히 웹 서버 디렉터리와 민감한 설정 파일의 권한 설정에 주의를 기울이세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><summary type="html"><![CDATA[리눅스 사용자 생성·삭제, 그룹 관리, sudo 권한 설정, 파일 권한(chmod/chown), 특수 권한(SUID/SGID/Sticky Bit)까지 서버 운영에 필요한 권한 관리 전체를 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Nginx 리버스 프록시로 여러 서비스 한 서버에서 관리하기</title><link href="https://tcp-80.net/blog/2024/04/08/nginx-reverse-proxy/" rel="alternate" type="text/html" title="Nginx 리버스 프록시로 여러 서비스 한 서버에서 관리하기" /><published>2024-04-08T00:00:00+09:00</published><updated>2024-04-08T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/04/08/nginx-reverse-proxy</id><content type="html" xml:base="https://tcp-80.net/blog/2024/04/08/nginx-reverse-proxy/"><![CDATA[<p>하나의 서버에서 Node.js, Python, Java 등 여러 애플리케이션을 운영할 때 Nginx를 리버스 프록시로 사용하면 도메인별 또는 경로별로 트래픽을 분산할 수 있습니다.</p>

<h2 id="리버스-프록시-개념">리버스 프록시 개념</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>클라이언트 → Nginx (80/443) → app1.example.com → Node.js (3000)
                             → app2.example.com → Python (8000)
                             → example.com/api  → Java (8080)
</code></pre></div></div>

<h2 id="도메인별-프록시-설정">도메인별 프록시 설정</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/sites-available/app1</span>
<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">app1.example.com</span><span class="p">;</span>
    <span class="kn">return</span> <span class="mi">301</span> <span class="s">https://</span><span class="nv">$host$request_uri</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">app1.example.com</span><span class="p">;</span>

    <span class="kn">ssl_certificate</span> <span class="n">/etc/letsencrypt/live/app1.example.com/fullchain.pem</span><span class="p">;</span>
    <span class="kn">ssl_certificate_key</span> <span class="n">/etc/letsencrypt/live/app1.example.com/privkey.pem</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:3000</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-Proto</span> <span class="nv">$scheme</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="핵심-프록시-헤더">핵심 프록시 헤더</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">location</span> <span class="n">/</span> <span class="p">{</span>
    <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:3000</span><span class="p">;</span>

    <span class="c1"># 원본 호스트명 전달</span>
    <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>

    <span class="c1"># 클라이언트 실제 IP 전달</span>
    <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>

    <span class="c1"># 프록시 체인 전달</span>
    <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>

    <span class="c1"># HTTP/HTTPS 여부 전달</span>
    <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-Proto</span> <span class="nv">$scheme</span><span class="p">;</span>

    <span class="c1"># 업스트림 타임아웃 설정</span>
    <span class="kn">proxy_connect_timeout</span> <span class="s">30s</span><span class="p">;</span>
    <span class="kn">proxy_send_timeout</span> <span class="s">60s</span><span class="p">;</span>
    <span class="kn">proxy_read_timeout</span> <span class="s">60s</span><span class="p">;</span>

    <span class="c1"># HTTP 버전</span>
    <span class="kn">proxy_http_version</span> <span class="mf">1.1</span><span class="p">;</span>

    <span class="c1"># WebSocket 지원 (필요 시)</span>
    <span class="kn">proxy_set_header</span> <span class="s">Upgrade</span> <span class="nv">$http_upgrade</span><span class="p">;</span>
    <span class="kn">proxy_set_header</span> <span class="s">Connection</span> <span class="s">"upgrade"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="경로별-프록시-설정">경로별 프록시 설정</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">example.com</span><span class="p">;</span>

    <span class="c1"># 프론트엔드 (React, Vue 등 정적 파일)</span>
    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">root</span> <span class="n">/var/www/html</span><span class="p">;</span>
        <span class="kn">try_files</span> <span class="nv">$uri</span> <span class="nv">$uri</span><span class="n">/</span> <span class="n">/index.html</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># API 서버</span>
    <span class="kn">location</span> <span class="n">/api/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:8080/</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-Proto</span> <span class="nv">$scheme</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1"># WebSocket</span>
    <span class="kn">location</span> <span class="n">/ws/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:3001/</span><span class="p">;</span>
        <span class="kn">proxy_http_version</span> <span class="mf">1.1</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Upgrade</span> <span class="nv">$http_upgrade</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Connection</span> <span class="s">"upgrade"</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="upstream으로-로드-밸런싱">upstream으로 로드 밸런싱</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/nginx.conf 또는 별도 파일</span>
<span class="k">upstream</span> <span class="s">app_servers</span> <span class="p">{</span>
    <span class="c1"># 기본: 라운드 로빈</span>
    <span class="kn">server</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">3000</span><span class="p">;</span>
    <span class="kn">server</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">3001</span><span class="p">;</span>
    <span class="kn">server</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">3002</span><span class="p">;</span>

    <span class="c1"># 가중치 설정</span>
    <span class="c1"># server 127.0.0.1:3000 weight=3;</span>
    <span class="c1"># server 127.0.0.1:3001 weight=1;</span>

    <span class="c1"># 최소 연결 수 방식</span>
    <span class="c1"># least_conn;</span>

    <span class="c1"># 연결 유지 (성능 향상)</span>
    <span class="kn">keepalive</span> <span class="mi">32</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://app_servers</span><span class="p">;</span>
        <span class="kn">proxy_http_version</span> <span class="mf">1.1</span><span class="p">;</span>
        <span class="kn">proxy_set_header</span> <span class="s">Connection</span> <span class="s">""</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="버퍼링-설정">버퍼링 설정</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">location</span> <span class="n">/api/</span> <span class="p">{</span>
    <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:8080</span><span class="p">;</span>

    <span class="c1"># 업스트림 응답 버퍼링</span>
    <span class="kn">proxy_buffering</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">proxy_buffer_size</span> <span class="mi">4k</span><span class="p">;</span>
    <span class="kn">proxy_buffers</span> <span class="mi">8</span> <span class="mi">4k</span><span class="p">;</span>
    <span class="kn">proxy_busy_buffers_size</span> <span class="mi">8k</span><span class="p">;</span>

    <span class="c1"># 대용량 파일 다운로드 시 임시 파일 사용</span>
    <span class="kn">proxy_max_temp_file_size</span> <span class="mi">1024m</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="캐싱-설정">캐싱 설정</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># nginx.conf의 http 블록에 추가</span>
<span class="k">proxy_cache_path</span> <span class="n">/var/cache/nginx</span> <span class="s">levels=1:2</span> <span class="s">keys_zone=my_cache:10m</span>
    <span class="s">max_size=1g</span> <span class="s">inactive=60m</span> <span class="s">use_temp_path=off</span><span class="p">;</span>

<span class="k">server</span> <span class="p">{</span>
    <span class="kn">location</span> <span class="n">/api/</span> <span class="p">{</span>
        <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:8080</span><span class="p">;</span>
        <span class="kn">proxy_cache</span> <span class="s">my_cache</span><span class="p">;</span>
        <span class="kn">proxy_cache_valid</span> <span class="mi">200</span> <span class="mi">10m</span><span class="p">;</span>
        <span class="kn">proxy_cache_valid</span> <span class="mi">404</span> <span class="mi">1m</span><span class="p">;</span>

        <span class="c1"># 캐시 상태 헤더 추가 (디버깅)</span>
        <span class="kn">add_header</span> <span class="s">X-Cache-Status</span> <span class="nv">$upstream_cache_status</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="보안-헤더-추가">보안 헤더 추가</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="c1"># 보안 헤더</span>
    <span class="kn">add_header</span> <span class="s">X-Frame-Options</span> <span class="s">"SAMEORIGIN"</span> <span class="s">always</span><span class="p">;</span>
    <span class="kn">add_header</span> <span class="s">X-Content-Type-Options</span> <span class="s">"nosniff"</span> <span class="s">always</span><span class="p">;</span>
    <span class="kn">add_header</span> <span class="s">X-XSS-Protection</span> <span class="s">"1</span><span class="p">;</span> <span class="kn">mode=block"</span> <span class="s">always</span><span class="p">;</span>
    <span class="kn">add_header</span> <span class="s">Referrer-Policy</span> <span class="s">"strict-origin-when-cross-origin"</span> <span class="s">always</span><span class="p">;</span>
    <span class="kn">add_header</span> <span class="s">Content-Security-Policy</span> <span class="s">"default-src</span> <span class="s">'self'"</span> <span class="s">always</span><span class="p">;</span>

    <span class="c1"># 서버 버전 숨기기</span>
    <span class="kn">server_tokens</span> <span class="no">off</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="설정-활성화">설정 활성화</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 심볼릭 링크로 활성화</span>
<span class="nb">sudo ln</span> <span class="nt">-s</span> /etc/nginx/sites-available/app1 /etc/nginx/sites-enabled/

<span class="c"># 설정 검사</span>
<span class="nb">sudo </span>nginx <span class="nt">-t</span>

<span class="c"># 재로드</span>
<span class="nb">sudo </span>systemctl reload nginx
</code></pre></div></div>

<h2 id="트러블슈팅">트러블슈팅</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 업스트림 연결 오류 로그 확인</span>
<span class="nb">sudo tail</span> <span class="nt">-f</span> /var/log/nginx/error.log | <span class="nb">grep </span>upstream

<span class="c"># 프록시된 헤더 확인 (앱에서 요청 헤더 출력)</span>
curl <span class="nt">-H</span> <span class="s2">"Host: app1.example.com"</span> http://127.0.0.1:3000/headers
</code></pre></div></div>

<p>Nginx 리버스 프록시를 활용하면 하나의 서버에서 여러 애플리케이션을 효율적으로 운영할 수 있습니다. SSL 인증서도 Nginx에서 한 번만 설정하면 되어 관리가 편리합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><summary type="html"><![CDATA[하나의 서버에서 포트 80/443으로 여러 애플리케이션을 운영하는 Nginx 리버스 프록시 설정 방법을 실전 예제로 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">WireGuard VPN 서버 구축하기</title><link href="https://tcp-80.net/blog/2024/03/25/wireguard-vpn/" rel="alternate" type="text/html" title="WireGuard VPN 서버 구축하기" /><published>2024-03-25T00:00:00+09:00</published><updated>2024-03-25T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/03/25/wireguard-vpn</id><content type="html" xml:base="https://tcp-80.net/blog/2024/03/25/wireguard-vpn/"><![CDATA[<p>WireGuard는 OpenVPN, IPsec보다 훨씬 빠르고 설정이 간단한 현대적 VPN 프로토콜입니다. 코드베이스가 작아(약 4,000줄) 보안 감사가 용이하고 성능이 뛰어납니다.</p>

<h2 id="wireguard-설치">WireGuard 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Ubuntu 20.04+</span>
<span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> wireguard

<span class="c"># CentOS/RHEL</span>
<span class="nb">sudo </span>dnf <span class="nb">install</span> <span class="nt">-y</span> epel-release
<span class="nb">sudo </span>dnf <span class="nb">install</span> <span class="nt">-y</span> wireguard-tools
</code></pre></div></div>

<h2 id="서버-키-생성">서버 키 생성</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># WireGuard 디렉터리 생성</span>
<span class="nb">sudo mkdir</span> <span class="nt">-p</span> /etc/wireguard
<span class="nb">sudo chmod </span>700 /etc/wireguard
<span class="nb">cd</span> /etc/wireguard

<span class="c"># 서버 개인키 및 공개키 생성</span>
wg genkey | <span class="nb">sudo tee </span>privatekey | wg pubkey | <span class="nb">sudo tee </span>publickey

<span class="c"># 생성된 키 확인</span>
<span class="nb">sudo cat </span>privatekey
<span class="nb">sudo cat </span>publickey
</code></pre></div></div>

<h2 id="서버-설정-파일-생성">서버 설정 파일 생성</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/wireguard/wg0.conf</code>:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Interface]</span><span class="w">
</span><span class="c"># 서버 가상 IP (VPN 네트워크 대역)
</span><span class="py">Address</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10.0.0.1/24</span>
<span class="w">
</span><span class="c"># WireGuard 리슨 포트 (UDP)
</span><span class="py">ListenPort</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">51820</span>
<span class="w">
</span><span class="c"># 서버 개인키 (위에서 생성한 privatekey 내용)
</span><span class="py">PrivateKey</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">서버개인키내용</span>
<span class="w">
</span><span class="c"># 패킷 포워딩 활성화 (클라이언트가 인터넷 사용 시)
</span><span class="py">PostUp</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE</span>
<span class="py">PostDown</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE</span>
<span class="w">
</span><span class="c"># 클라이언트 1
</span><span class="nn">[Peer]</span><span class="w">
</span><span class="py">PublicKey</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">클라이언트1공개키</span>
<span class="py">AllowedIPs</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10.0.0.2/32</span>
<span class="w">
</span><span class="c"># 클라이언트 2
</span><span class="nn">[Peer]</span><span class="w">
</span><span class="py">PublicKey</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">클라이언트2공개키</span>
<span class="py">AllowedIPs</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10.0.0.3/32</span>
</code></pre></div></div>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">eth0</code>은 서버의 실제 네트워크 인터페이스 이름으로 변경하세요 (<code class="language-plaintext highlighter-rouge">ip link show</code> 명령으로 확인).</p>
</blockquote>

<h2 id="ip-포워딩-활성화">IP 포워딩 활성화</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 즉시 활성화</span>
<span class="nb">sudo </span>sysctl <span class="nt">-w</span> net.ipv4.ip_forward<span class="o">=</span>1

<span class="c"># 영구 설정</span>
<span class="nb">echo</span> <span class="s1">'net.ipv4.ip_forward = 1'</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/sysctl.d/99-wireguard.conf
<span class="nb">sudo </span>sysctl <span class="nt">-p</span> /etc/sysctl.d/99-wireguard.conf
</code></pre></div></div>

<h2 id="방화벽-설정">방화벽 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># WireGuard 포트 허용 (UDP)</span>
<span class="nb">sudo </span>ufw allow 51820/udp

<span class="c"># 또는 iptables</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> udp <span class="nt">--dport</span> 51820 <span class="nt">-j</span> ACCEPT
</code></pre></div></div>

<h2 id="wireguard-시작">WireGuard 시작</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 인터페이스 시작</span>
<span class="nb">sudo </span>wg-quick up wg0

<span class="c"># 부팅 시 자동 시작</span>
<span class="nb">sudo </span>systemctl <span class="nb">enable </span>wg-quick@wg0
<span class="nb">sudo </span>systemctl start wg-quick@wg0

<span class="c"># 상태 확인</span>
<span class="nb">sudo </span>wg show
</code></pre></div></div>

<h2 id="클라이언트-설정">클라이언트 설정</h2>

<p>클라이언트에서도 키를 생성합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 클라이언트에서 실행</span>
wg genkey | <span class="nb">tee </span>client-privatekey | wg pubkey <span class="o">&gt;</span> client-publickey
</code></pre></div></div>

<p>클라이언트 설정 파일 (<code class="language-plaintext highlighter-rouge">/etc/wireguard/wg0.conf</code> 또는 앱에서 가져오기):</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Interface]</span><span class="w">
</span><span class="c"># 클라이언트 가상 IP
</span><span class="py">Address</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10.0.0.2/24</span>
<span class="w">
</span><span class="c"># 클라이언트 개인키
</span><span class="py">PrivateKey</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">클라이언트개인키내용</span>
<span class="w">
</span><span class="c"># DNS 서버 (선택)
</span><span class="py">DNS</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1.1.1.1, 8.8.8.8</span>
<span class="w">
</span><span class="nn">[Peer]</span><span class="w">
</span><span class="c"># 서버 공개키
</span><span class="py">PublicKey</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">서버공개키내용</span>
<span class="w">
</span><span class="c"># 서버 주소 및 포트
</span><span class="py">Endpoint</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">서버IP:51820</span>
<span class="w">
</span><span class="c"># 허용할 트래픽 범위
# VPN을 통해 모든 트래픽 라우팅
</span><span class="py">AllowedIPs</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">0.0.0.0/0, ::/0</span>
<span class="w">
</span><span class="c"># VPN만 사용 (분할 터널링)
# AllowedIPs = 10.0.0.0/24
</span><span class="w">
</span><span class="c"># 연결 유지 (NAT 환경)
</span><span class="py">PersistentKeepalive</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">25</span>
</code></pre></div></div>

<h2 id="피어-추가-및-제거">피어 추가 및 제거</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 서버에서 새 피어 실시간 추가 (재시작 불필요)</span>
<span class="nb">sudo </span>wg <span class="nb">set </span>wg0 peer 새클라이언트공개키 allowed-ips 10.0.0.4/32

<span class="c"># 피어 제거</span>
<span class="nb">sudo </span>wg <span class="nb">set </span>wg0 peer 클라이언트공개키 remove

<span class="c"># 설정 파일에도 반영</span>
<span class="nb">sudo </span>wg-quick save wg0
</code></pre></div></div>

<h2 id="연결-상태-모니터링">연결 상태 모니터링</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 피어 연결 상태 확인</span>
<span class="nb">sudo </span>wg show

<span class="c"># 인터페이스 통계</span>
<span class="nb">sudo </span>wg show wg0

<span class="c"># 출력 예시:</span>
<span class="c"># peer: 클라이언트공개키</span>
<span class="c">#   endpoint: 클라이언트IP:포트</span>
<span class="c">#   allowed ips: 10.0.0.2/32</span>
<span class="c">#   latest handshake: 30 seconds ago</span>
<span class="c">#   transfer: 1.44 MiB received, 4.52 MiB sent</span>
</code></pre></div></div>

<h2 id="qr-코드로-모바일-클라이언트-설정">QR 코드로 모바일 클라이언트 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> qrencode

<span class="c"># 클라이언트 설정 파일을 QR 코드로 출력</span>
qrencode <span class="nt">-t</span> ansiutf8 &lt; client-wg0.conf
</code></pre></div></div>

<p>WireGuard는 특히 서버 관리자가 원격에서 내부 서비스에 안전하게 접근할 때 매우 유용합니다. 기존 OpenVPN 대비 설정이 훨씬 간단하고 성능도 뛰어납니다.</p>

<p>직접 VPN 서버를 구성하기 어렵거나 일본 IP가 필요하다면 TCP-80.NET의 <a href="/vpn-service/">일본 VPN 서비스</a>를 이용해 보세요. OpenVPN 기반으로 별도 서버 없이 바로 사용할 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[빠르고 간결한 현대적 VPN 프로토콜인 WireGuard로 서버에 VPN을 구축하고 클라이언트를 연결하는 방법을 단계별로 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Redis 보안 설정: 외부 노출 차단부터 인증까지</title><link href="https://tcp-80.net/blog/2024/03/11/redis-security/" rel="alternate" type="text/html" title="Redis 보안 설정: 외부 노출 차단부터 인증까지" /><published>2024-03-11T00:00:00+09:00</published><updated>2024-03-11T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/03/11/redis-security</id><content type="html" xml:base="https://tcp-80.net/blog/2024/03/11/redis-security/"><![CDATA[<p>Redis는 기본 설치 상태에서 인증 없이 누구나 접속할 수 있습니다. 인터넷에 노출된 Redis는 데이터 탈취는 물론 서버 전체가 침해될 수 있습니다. 2016년부터 이어지는 Redis 랜섬웨어 피해가 그 증거입니다.</p>

<h2 id="보안-취약-여부-확인">보안 취약 여부 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 외부에서 접속 테스트 (서버 IP 사용)</span>
redis-cli <span class="nt">-h</span> 서버IP ping
<span class="c"># PONG이 반환되면 외부 노출 상태</span>

<span class="c"># 현재 설정 확인</span>
redis-cli CONFIG GET <span class="nb">bind
</span>redis-cli CONFIG GET requirepass
</code></pre></div></div>

<h2 id="1-bind-설정으로-인터페이스-제한">1. bind 설정으로 인터페이스 제한</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/redis/redis.conf</code> (또는 <code class="language-plaintext highlighter-rouge">/etc/redis.conf</code>):</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 로컬호스트에서만 접속 허용
</span><span class="na">bind</span><span class="w"> </span><span class="na">127.0.0.1</span><span class="w"> </span><span class="na">-::1</span><span class="w">

</span><span class="c"># 특정 IP에서도 허용할 경우
# bind 127.0.0.1 192.168.1.100
</span></code></pre></div></div>

<h2 id="2-requirepass로-인증-설정">2. requirepass로 인증 설정</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 강력한 비밀번호 설정 (최소 32자 권장)
</span><span class="na">requirepass</span><span class="w"> </span><span class="na">랜덤하고강력한비밀번호</span><span class="w">

</span><span class="c"># 비밀번호 생성 예시
# openssl rand -base64 32
</span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 인증 후 명령 실행</span>
redis-cli <span class="nt">-a</span> 비밀번호 ping

<span class="c"># 또는 접속 후 인증</span>
redis-cli
<span class="o">&gt;</span> AUTH 비밀번호
<span class="o">&gt;</span> PING
</code></pre></div></div>

<h2 id="3-위험-명령어-비활성화">3. 위험 명령어 비활성화</h2>

<p>다음 명령어들은 공격자가 악용할 수 있어 비활성화 또는 이름 변경이 필요합니다:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># redis.conf에서 위험 명령어 비활성화
</span><span class="na">rename-command</span><span class="w"> </span><span class="na">FLUSHALL</span><span class="w"> </span><span class="na">""</span><span class="w">
</span><span class="na">rename-command</span><span class="w"> </span><span class="na">FLUSHDB</span><span class="w"> </span><span class="na">""</span><span class="w">
</span><span class="na">rename-command</span><span class="w"> </span><span class="na">CONFIG</span><span class="w"> </span><span class="na">""</span><span class="w">
</span><span class="na">rename-command</span><span class="w"> </span><span class="na">DEBUG</span><span class="w"> </span><span class="na">""</span><span class="w">
</span><span class="na">rename-command</span><span class="w"> </span><span class="na">KEYS</span><span class="w"> </span><span class="na">"*"</span><span class="w">    </span><span class="c"># 프로덕션에서 성능 문제도 있음
</span><span class="na">rename-command</span><span class="w"> </span><span class="na">SHUTDOWN</span><span class="w"> </span><span class="na">SHUTDOWN_SAFE_NAME</span><span class="w">

</span><span class="c"># 또는 다른 이름으로 변경 (관리자만 알게)
</span><span class="na">rename-command</span><span class="w"> </span><span class="na">CONFIG</span><span class="w"> </span><span class="na">"SECRET_CONFIG_CMD_abc123"</span><span class="w">
</span></code></pre></div></div>

<h2 id="4-방화벽으로-포트-차단">4. 방화벽으로 포트 차단</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Redis 포트(6379)를 로컬 및 특정 IP에서만 허용</span>
<span class="nb">sudo </span>ufw deny 6379
<span class="nb">sudo </span>ufw allow from 127.0.0.1 to any port 6379

<span class="c"># 애플리케이션 서버가 별도 서버인 경우</span>
<span class="nb">sudo </span>ufw allow from 10.0.0.5 to any port 6379
</code></pre></div></div>

<h2 id="5-protected-mode-확인">5. protected-mode 확인</h2>

<p>Redis 3.2 이상에서 외부 접속 시 보호 모드가 기본 활성화되어 있습니다:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># bind 설정이나 requirepass 없이 외부에서 접근하면 오류 반환
</span><span class="na">protected-mode</span><span class="w"> </span><span class="na">yes</span><span class="w">
</span></code></pre></div></div>

<h2 id="6-tls-암호화-연결-redis-6-이상">6. TLS 암호화 연결 (Redis 6 이상)</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># redis.conf
</span><span class="na">port</span><span class="w"> </span><span class="na">0</span><span class="w">          </span><span class="c"># 일반 포트 비활성화
</span><span class="na">tls-port</span><span class="w"> </span><span class="na">6380</span><span class="w">   </span><span class="c"># TLS 포트 활성화
</span><span class="w">
</span><span class="na">tls-cert-file</span><span class="w"> </span><span class="na">/etc/redis/tls/redis.crt</span><span class="w">
</span><span class="na">tls-key-file</span><span class="w"> </span><span class="na">/etc/redis/tls/redis.key</span><span class="w">
</span><span class="na">tls-ca-cert-file</span><span class="w"> </span><span class="na">/etc/redis/tls/ca.crt</span><span class="w">

</span><span class="na">tls-auth-clients</span><span class="w"> </span><span class="na">yes</span><span class="w">
</span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># TLS로 접속</span>
redis-cli <span class="nt">-h</span> 127.0.0.1 <span class="nt">-p</span> 6380 <span class="se">\</span>
    <span class="nt">--tls</span> <span class="se">\</span>
    <span class="nt">--cert</span> /etc/redis/tls/client.crt <span class="se">\</span>
    <span class="nt">--key</span> /etc/redis/tls/client.key <span class="se">\</span>
    <span class="nt">--cacert</span> /etc/redis/tls/ca.crt
</code></pre></div></div>

<h2 id="7-로그-설정">7. 로그 설정</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># redis.conf
</span><span class="na">loglevel</span><span class="w"> </span><span class="na">notice</span><span class="w">
</span><span class="na">logfile</span><span class="w"> </span><span class="na">/var/log/redis/redis-server.log</span><span class="w">
</span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 접속 시도 모니터링</span>
<span class="nb">sudo tail</span> <span class="nt">-f</span> /var/log/redis/redis-server.log
</code></pre></div></div>

<h2 id="8-실행-사용자-제한">8. 실행 사용자 제한</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Redis를 redis 전용 계정으로 실행 (기본값이지만 확인)</span>
<span class="nb">cat</span> /etc/systemd/system/redis.service | <span class="nb">grep </span>User
<span class="c"># User=redis</span>

<span class="c"># redis 사용자는 /data 이외의 디렉터리 접근 불가하게</span>
</code></pre></div></div>

<h2 id="9-설정-적용-및-검증">9. 설정 적용 및 검증</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 설정 파일 문법 검사</span>
redis-server /etc/redis/redis.conf <span class="nt">--test-memory</span> 1

<span class="c"># Redis 재시작</span>
<span class="nb">sudo </span>systemctl restart redis

<span class="c"># 외부에서 접속 테스트 (차단 확인)</span>
redis-cli <span class="nt">-h</span> 서버IP ping
<span class="c"># Could not connect to Redis at 서버IP:6379: Connection refused</span>
</code></pre></div></div>

<h2 id="보안-점검-체크리스트">보안 점검 체크리스트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 외부 인터페이스에 바인드되어 있는지 확인</span>
redis-cli CONFIG GET <span class="nb">bind</span>

<span class="c"># 인증 설정 확인</span>
redis-cli <span class="nt">-a</span> 비밀번호 CONFIG GET requirepass

<span class="c"># 리슨 중인 포트 확인</span>
<span class="nb">sudo </span>ss <span class="nt">-tlnp</span> | <span class="nb">grep </span>redis
<span class="c"># 127.0.0.1:6379만 표시되어야 함</span>

<span class="c"># 방화벽 규칙 확인</span>
<span class="nb">sudo </span>ufw status | <span class="nb">grep </span>6379
</code></pre></div></div>

<p>Redis는 캐시, 세션, 큐 등 핵심 역할을 하는 경우가 많습니다. 외부 노출만 차단해도 대부분의 공격을 예방할 수 있으므로, 기본 보안 설정을 반드시 적용하세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[인터넷에 노출된 Redis는 심각한 보안 위협입니다. bind 설정으로 외부 접근 차단, requirepass 인증, 위험 명령어 비활성화까지 Redis 보안 필수 설정을 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Docker로 서버 환경 분리하기: 기초부터 실전까지</title><link href="https://tcp-80.net/blog/2024/02/26/docker-server-basics/" rel="alternate" type="text/html" title="Docker로 서버 환경 분리하기: 기초부터 실전까지" /><published>2024-02-26T00:00:00+09:00</published><updated>2024-02-26T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/02/26/docker-server-basics</id><content type="html" xml:base="https://tcp-80.net/blog/2024/02/26/docker-server-basics/"><![CDATA[<p>Docker는 애플리케이션과 의존성을 컨테이너로 패키징해 어느 서버에서든 동일하게 실행할 수 있게 합니다. 서버 환경을 깔끔하게 분리하고 관리하는 데 매우 유용합니다.</p>

<h2 id="docker-설치">Docker 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 의존성 설치</span>
<span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> ca-certificates curl gnupg

<span class="c"># Docker 공식 GPG 키 추가</span>
<span class="nb">sudo install</span> <span class="nt">-m</span> 0755 <span class="nt">-d</span> /etc/apt/keyrings
curl <span class="nt">-fsSL</span> https://download.docker.com/linux/ubuntu/gpg | <span class="se">\</span>
    <span class="nb">sudo </span>gpg <span class="nt">--dearmor</span> <span class="nt">-o</span> /etc/apt/keyrings/docker.gpg

<span class="c"># 저장소 추가</span>
<span class="nb">echo</span> <span class="s2">"deb [arch=</span><span class="si">$(</span>dpkg <span class="nt">--print-architecture</span><span class="si">)</span><span class="s2"> signed-by=/etc/apt/keyrings/docker.gpg] </span><span class="se">\</span><span class="s2">
    https://download.docker.com/linux/ubuntu </span><span class="si">$(</span>lsb_release <span class="nt">-cs</span><span class="si">)</span><span class="s2"> stable"</span> | <span class="se">\</span>
    <span class="nb">sudo tee</span> /etc/apt/sources.list.d/docker.list

<span class="c"># 설치</span>
<span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> docker-ce docker-ce-cli containerd.io docker-compose-plugin

<span class="c"># 현재 사용자를 docker 그룹에 추가 (sudo 없이 사용)</span>
<span class="nb">sudo </span>usermod <span class="nt">-aG</span> docker <span class="nv">$USER</span>
newgrp docker
</code></pre></div></div>

<h2 id="기본-명령어">기본 명령어</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 이미지 검색 및 다운로드</span>
docker search nginx
docker pull nginx:latest

<span class="c"># 컨테이너 실행</span>
docker run <span class="nt">-d</span> <span class="se">\</span>
    <span class="nt">--name</span> my-nginx <span class="se">\</span>
    <span class="nt">-p</span> 8080:80 <span class="se">\</span>
    nginx:latest

<span class="c"># 실행 중인 컨테이너 목록</span>
docker ps

<span class="c"># 모든 컨테이너 목록 (중지된 것 포함)</span>
docker ps <span class="nt">-a</span>

<span class="c"># 컨테이너 로그 확인</span>
docker logs <span class="nt">-f</span> my-nginx

<span class="c"># 컨테이너 내부 접속</span>
docker <span class="nb">exec</span> <span class="nt">-it</span> my-nginx bash

<span class="c"># 컨테이너 중지 및 삭제</span>
docker stop my-nginx
docker <span class="nb">rm </span>my-nginx
</code></pre></div></div>

<h2 id="볼륨으로-데이터-영구-보존">볼륨으로 데이터 영구 보존</h2>

<p>컨테이너를 삭제하면 내부 데이터도 함께 사라집니다. 볼륨을 사용해 데이터를 호스트에 보존합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 호스트 디렉터리를 컨테이너에 마운트</span>
docker run <span class="nt">-d</span> <span class="se">\</span>
    <span class="nt">--name</span> mysql-db <span class="se">\</span>
    <span class="nt">-e</span> <span class="nv">MYSQL_ROOT_PASSWORD</span><span class="o">=</span>비밀번호 <span class="se">\</span>
    <span class="nt">-e</span> <span class="nv">MYSQL_DATABASE</span><span class="o">=</span>myapp <span class="se">\</span>
    <span class="nt">-v</span> /opt/mysql-data:/var/lib/mysql <span class="se">\</span>
    <span class="nt">-p</span> 3306:3306 <span class="se">\</span>
    mysql:8.0

<span class="c"># Docker 관리 볼륨 사용</span>
docker volume create mydata
docker run <span class="nt">-d</span> <span class="nt">-v</span> mydata:/data alpine

<span class="c"># 볼륨 목록 확인</span>
docker volume <span class="nb">ls</span>
</code></pre></div></div>

<h2 id="네트워크-설정">네트워크 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 사용자 정의 네트워크 생성 (컨테이너 간 통신)</span>
docker network create myapp-network

<span class="c"># 같은 네트워크에 컨테이너 연결</span>
docker run <span class="nt">-d</span> <span class="nt">--name</span> app <span class="nt">--network</span> myapp-network my-app-image
docker run <span class="nt">-d</span> <span class="nt">--name</span> db <span class="nt">--network</span> myapp-network mysql:8.0

<span class="c"># app 컨테이너에서 db 컨테이너 이름으로 접속 가능</span>
<span class="c"># mysql -h db -u root -p</span>
</code></pre></div></div>

<h2 id="docker-compose로-멀티-컨테이너-관리">docker-compose로 멀티 컨테이너 관리</h2>

<p>여러 컨테이너를 한 파일로 정의하고 관리합니다:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># docker-compose.yml</span>
<span class="na">version</span><span class="pi">:</span> <span class="s1">'</span><span class="s">3.8'</span>

<span class="na">services</span><span class="pi">:</span>
  <span class="na">web</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">nginx:latest</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">80:80"</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">443:443"</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">./nginx.conf:/etc/nginx/nginx.conf:ro</span>
      <span class="pi">-</span> <span class="s">./html:/usr/share/nginx/html:ro</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">app</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">myapp</span>

  <span class="na">app</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">node:20-alpine</span>
    <span class="na">working_dir</span><span class="pi">:</span> <span class="s">/app</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">./app:/app</span>
    <span class="na">command</span><span class="pi">:</span> <span class="s">node server.js</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">DB_HOST=db</span>
      <span class="pi">-</span> <span class="s">DB_PASSWORD=${DB_PASSWORD}</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">myapp</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">db</span>

  <span class="na">db</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">mysql:8.0</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">db-data:/var/lib/mysql</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}</span>
      <span class="pi">-</span> <span class="s">MYSQL_DATABASE=myapp</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">myapp</span>

<span class="na">volumes</span><span class="pi">:</span>
  <span class="na">db-data</span><span class="pi">:</span>

<span class="na">networks</span><span class="pi">:</span>
  <span class="na">myapp</span><span class="pi">:</span>
    <span class="na">driver</span><span class="pi">:</span> <span class="s">bridge</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 실행 (.env 파일에 환경변수 정의)</span>
docker compose up <span class="nt">-d</span>

<span class="c"># 상태 확인</span>
docker compose ps
docker compose logs <span class="nt">-f</span>

<span class="c"># 중지 및 삭제 (볼륨 보존)</span>
docker compose down

<span class="c"># 볼륨까지 삭제</span>
docker compose down <span class="nt">-v</span>
</code></pre></div></div>

<h2 id="이미지-빌드-dockerfile">이미지 빌드 (Dockerfile)</h2>

<div class="language-dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Dockerfile</span>
<span class="k">FROM</span><span class="s"> ubuntu:22.04</span>

<span class="c"># 패키지 설치</span>
<span class="k">RUN </span>apt update <span class="o">&amp;&amp;</span> apt <span class="nb">install</span> <span class="nt">-y</span> <span class="se">\
</span>    nginx <span class="se">\
</span>    <span class="o">&amp;&amp;</span> <span class="nb">rm</span> <span class="nt">-rf</span> /var/lib/apt/lists/<span class="k">*</span>

<span class="c"># 설정 파일 복사</span>
<span class="k">COPY</span><span class="s"> nginx.conf /etc/nginx/nginx.conf</span>

<span class="c"># 포트 노출</span>
<span class="k">EXPOSE</span><span class="s"> 80</span>

<span class="c"># 실행 명령</span>
<span class="k">CMD</span><span class="s"> ["nginx", "-g", "daemon off;"]</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 이미지 빌드</span>
docker build <span class="nt">-t</span> my-nginx:1.0 <span class="nb">.</span>

<span class="c"># 이미지 목록</span>
docker images
</code></pre></div></div>

<h2 id="리소스-제한-및-모니터링">리소스 제한 및 모니터링</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># CPU/메모리 제한</span>
docker run <span class="nt">-d</span> <span class="se">\</span>
    <span class="nt">--name</span> limited-app <span class="se">\</span>
    <span class="nt">--memory</span><span class="o">=</span><span class="s2">"512m"</span> <span class="se">\</span>
    <span class="nt">--cpus</span><span class="o">=</span><span class="s2">"1.0"</span> <span class="se">\</span>
    my-app-image

<span class="c"># 실시간 리소스 사용량 확인</span>
docker stats

<span class="c"># 사용하지 않는 리소스 정리</span>
docker system prune <span class="nt">-a</span>
</code></pre></div></div>

<h2 id="보안-고려사항">보안 고려사항</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 루트가 아닌 사용자로 실행</span>
docker run <span class="nt">--user</span> 1000:1000 my-app-image

<span class="c"># 읽기 전용 루트 파일시스템</span>
docker run <span class="nt">--read-only</span> my-app-image

<span class="c"># 컨테이너가 새 권한 획득 방지</span>
docker run <span class="nt">--security-opt</span> no-new-privileges my-app-image
</code></pre></div></div>

<p>Docker를 활용하면 서버에 여러 서비스를 깔끔하게 분리해 운영할 수 있습니다. 특히 개발 환경과 프로덕션 환경의 일관성을 유지하는 데 매우 효과적입니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><summary type="html"><![CDATA[Docker 컨테이너 개념, 설치, 기본 명령어, 볼륨·네트워크 관리, docker-compose 사용법까지 서버 환경 분리를 위한 Docker 핵심을 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">PostgreSQL 보안 강화: 설치 후 반드시 해야 할 설정</title><link href="https://tcp-80.net/blog/2024/02/12/postgresql-security/" rel="alternate" type="text/html" title="PostgreSQL 보안 강화: 설치 후 반드시 해야 할 설정" /><published>2024-02-12T00:00:00+09:00</published><updated>2024-02-12T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/02/12/postgresql-security</id><content type="html" xml:base="https://tcp-80.net/blog/2024/02/12/postgresql-security/"><![CDATA[<p>PostgreSQL은 강력한 기능을 제공하지만, 기본 설치 상태에서는 보안 설정이 미흡합니다. 프로덕션 서버에서 반드시 적용해야 할 설정들을 정리합니다.</p>

<h2 id="1-postgres-계정-비밀번호-설정">1. postgres 계정 비밀번호 설정</h2>

<p>PostgreSQL 설치 직후 <code class="language-plaintext highlighter-rouge">postgres</code> 수퍼유저 계정에는 비밀번호가 없습니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># postgres 유닉스 계정으로 전환</span>
<span class="nb">sudo</span> <span class="nt">-u</span> postgres psql

<span class="c"># PostgreSQL 프롬프트에서 비밀번호 설정</span>
ALTER USER postgres WITH PASSWORD <span class="s1">'강력한비밀번호'</span><span class="p">;</span>
<span class="se">\q</span>
</code></pre></div></div>

<h2 id="2-전용-데이터베이스-사용자-생성">2. 전용 데이터베이스 사용자 생성</h2>

<p>애플리케이션에 postgres 수퍼유저를 사용하면 침해 시 전체 DB가 위험합니다:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 읽기/쓰기 전용 사용자 생성</span>
<span class="k">CREATE</span> <span class="k">USER</span> <span class="n">appuser</span> <span class="k">WITH</span> <span class="n">PASSWORD</span> <span class="s1">'앱비밀번호'</span><span class="p">;</span>

<span class="c1">-- 특정 데이터베이스에만 권한 부여</span>
<span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">myapp</span> <span class="k">OWNER</span> <span class="n">appuser</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">CONNECT</span> <span class="k">ON</span> <span class="k">DATABASE</span> <span class="n">myapp</span> <span class="k">TO</span> <span class="n">appuser</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">USAGE</span> <span class="k">ON</span> <span class="k">SCHEMA</span> <span class="k">public</span> <span class="k">TO</span> <span class="n">appuser</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">SELECT</span><span class="p">,</span> <span class="k">INSERT</span><span class="p">,</span> <span class="k">UPDATE</span><span class="p">,</span> <span class="k">DELETE</span> <span class="k">ON</span> <span class="k">ALL</span> <span class="n">TABLES</span> <span class="k">IN</span> <span class="k">SCHEMA</span> <span class="k">public</span> <span class="k">TO</span> <span class="n">appuser</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">USAGE</span><span class="p">,</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="k">ALL</span> <span class="n">SEQUENCES</span> <span class="k">IN</span> <span class="k">SCHEMA</span> <span class="k">public</span> <span class="k">TO</span> <span class="n">appuser</span><span class="p">;</span>

<span class="c1">-- 향후 생성될 테이블에도 자동 권한 부여</span>
<span class="k">ALTER</span> <span class="k">DEFAULT</span> <span class="k">PRIVILEGES</span> <span class="k">IN</span> <span class="k">SCHEMA</span> <span class="k">public</span>
    <span class="k">GRANT</span> <span class="k">SELECT</span><span class="p">,</span> <span class="k">INSERT</span><span class="p">,</span> <span class="k">UPDATE</span><span class="p">,</span> <span class="k">DELETE</span> <span class="k">ON</span> <span class="n">TABLES</span> <span class="k">TO</span> <span class="n">appuser</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="3-원격-접속-제어-pg_hbaconf">3. 원격 접속 제어 (pg_hba.conf)</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/postgresql/*/main/pg_hba.conf</code> 또는 <code class="language-plaintext highlighter-rouge">/var/lib/pgsql/data/pg_hba.conf</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># TYPE  DATABASE  USER      ADDRESS         METHOD

# 로컬 소켓 접속 (OS 인증)
local   all       postgres                  peer
local   all       all                       md5

# 특정 IP에서만 원격 접속 허용
host    myapp     appuser   203.0.113.10/32  scram-sha-256

# 전체 허용 (보안상 비권장)
# host  all       all       0.0.0.0/0        md5
</code></pre></div></div>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">scram-sha-256</code>은 PostgreSQL 10 이상에서 권장되는 인증 방식입니다. <code class="language-plaintext highlighter-rouge">md5</code>보다 안전합니다.</p>
</blockquote>

<h2 id="4-네트워크-바인딩-설정">4. 네트워크 바인딩 설정</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/postgresql/*/main/postgresql.conf</code>:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 로컬만 허용 (기본값, 권장)
</span><span class="py">listen_addresses</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">'localhost'</span>
<span class="w">
</span><span class="c"># 특정 IP에서도 허용할 경우
# listen_addresses = 'localhost,203.0.113.10'
</span><span class="w">
</span><span class="c"># 모든 인터페이스 (비권장, 방화벽과 함께 사용 시에만)
# listen_addresses = '*'
</span></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 설정 적용</span>
<span class="nb">sudo </span>systemctl restart postgresql
</code></pre></div></div>

<h2 id="5-방화벽에서-postgresql-포트-제한">5. 방화벽에서 PostgreSQL 포트 제한</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># PostgreSQL 기본 포트 (5432)를 특정 IP에서만 허용</span>
<span class="nb">sudo </span>ufw allow from 203.0.113.10 to any port 5432

<span class="c"># 또는 iptables</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 5432 <span class="nt">-s</span> 203.0.113.10 <span class="nt">-j</span> ACCEPT
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 5432 <span class="nt">-j</span> DROP
</code></pre></div></div>

<h2 id="6-ssltls-암호화-연결">6. SSL/TLS 암호화 연결</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># postgresql.conf
</span><span class="py">ssl</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">on</span>
<span class="py">ssl_cert_file</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">'server.crt'</span>
<span class="py">ssl_key_file</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">'server.key'</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 자체 서명 인증서 생성</span>
<span class="nb">sudo </span>openssl req <span class="nt">-new</span> <span class="nt">-x509</span> <span class="nt">-days</span> 365 <span class="nt">-nodes</span> <span class="se">\</span>
    <span class="nt">-out</span> /etc/ssl/certs/postgresql.crt <span class="se">\</span>
    <span class="nt">-keyout</span> /etc/ssl/private/postgresql.key

<span class="nb">sudo chown </span>postgres:postgres /etc/ssl/private/postgresql.key
<span class="nb">sudo chmod </span>600 /etc/ssl/private/postgresql.key
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># pg_hba.conf에서 SSL 강제
hostssl  myapp  appuser  0.0.0.0/0  scram-sha-256
</code></pre></div></div>

<h2 id="7-불필요한-언어-및-확장-비활성화">7. 불필요한 언어 및 확장 비활성화</h2>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 설치된 확장 목록 확인</span>
<span class="err">\</span><span class="n">dx</span>

<span class="c1">-- 불필요한 확장 제거 예시</span>
<span class="k">DROP</span> <span class="n">EXTENSION</span> <span class="n">IF</span> <span class="k">EXISTS</span> <span class="n">plpython3u</span><span class="p">;</span>
<span class="k">DROP</span> <span class="n">EXTENSION</span> <span class="n">IF</span> <span class="k">EXISTS</span> <span class="n">plperlu</span><span class="p">;</span>

<span class="c1">-- 신뢰할 수 없는 언어 목록 확인</span>
<span class="k">SELECT</span> <span class="n">lanname</span><span class="p">,</span> <span class="n">lanpltrusted</span> <span class="k">FROM</span> <span class="n">pg_language</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="8-접속-로그-활성화">8. 접속 로그 활성화</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># postgresql.conf
</span><span class="py">logging_collector</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">on</span>
<span class="py">log_directory</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">'pg_log'</span>
<span class="py">log_filename</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">'postgresql-%Y-%m-%d.log'</span>
<span class="py">log_rotation_age</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1d</span>
<span class="py">log_rotation_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">100MB</span>
<span class="w">
</span><span class="c"># 로그에 포함할 내용
</span><span class="py">log_connections</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">on</span>
<span class="py">log_disconnections</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">on</span>
<span class="py">log_failed_authentications</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">on</span>
<span class="py">log_duration</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">off          # 모든 쿼리 시간 기록 (느린 서버 주의)</span>
<span class="py">log_min_duration_statement</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1000  # 1초 이상 걸리는 쿼리 기록</span>
</code></pre></div></div>

<h2 id="9-보안-설정-점검-쿼리">9. 보안 설정 점검 쿼리</h2>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 비밀번호 없는 사용자 확인</span>
<span class="k">SELECT</span> <span class="n">usename</span><span class="p">,</span> <span class="n">passwd</span> <span class="k">IS</span> <span class="k">NULL</span> <span class="k">AS</span> <span class="n">no_password</span>
<span class="k">FROM</span> <span class="n">pg_shadow</span>
<span class="k">WHERE</span> <span class="n">passwd</span> <span class="k">IS</span> <span class="k">NULL</span> <span class="k">OR</span> <span class="n">passwd</span> <span class="o">=</span> <span class="s1">'md5'</span> <span class="o">||</span> <span class="n">md5</span><span class="p">(</span><span class="s1">''</span><span class="p">);</span>

<span class="c1">-- 수퍼유저 목록</span>
<span class="k">SELECT</span> <span class="n">usename</span> <span class="k">FROM</span> <span class="n">pg_user</span> <span class="k">WHERE</span> <span class="n">usesuper</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>

<span class="c1">-- 데이터베이스별 권한 확인</span>
<span class="err">\</span><span class="n">l</span>

<span class="c1">-- 현재 접속 목록</span>
<span class="k">SELECT</span> <span class="n">pid</span><span class="p">,</span> <span class="n">usename</span><span class="p">,</span> <span class="n">application_name</span><span class="p">,</span> <span class="n">client_addr</span><span class="p">,</span> <span class="k">state</span>
<span class="k">FROM</span> <span class="n">pg_stat_activity</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="10-정기-백업-설정">10. 정기 백업 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 데이터베이스 백업 스크립트</span>
<span class="nb">cat</span> <span class="o">&gt;</span> /opt/pg_backup.sh <span class="o">&lt;&lt;</span> <span class="sh">'</span><span class="no">EOF</span><span class="sh">'
#!/bin/bash
BACKUP_DIR="/backup/postgresql"
DATE=</span><span class="si">$(</span><span class="nb">date</span> +%Y%m%d<span class="si">)</span><span class="sh">

mkdir -p </span><span class="nv">$BACKUP_DIR</span><span class="sh">
sudo -u postgres pg_dumpall | gzip &gt; </span><span class="nv">$BACKUP_DIR</span><span class="sh">/pg_all_</span><span class="nv">$DATE</span><span class="sh">.sql.gz

# 7일 이상 된 백업 삭제
find </span><span class="nv">$BACKUP_DIR</span><span class="sh"> -name "*.sql.gz" -mtime +7 -delete
</span><span class="no">EOF

</span><span class="nb">chmod</span> +x /opt/pg_backup.sh

<span class="c"># cron에 등록 (매일 새벽 3시)</span>
<span class="nb">echo</span> <span class="s2">"0 3 * * * root /opt/pg_backup.sh"</span> | <span class="nb">sudo tee</span> /etc/cron.d/pg-backup
</code></pre></div></div>

<p>MySQL/MariaDB와 마찬가지로 PostgreSQL도 초기 보안 설정이 중요합니다. 특히 <code class="language-plaintext highlighter-rouge">pg_hba.conf</code>의 접근 제어와 전용 사용자 계정 생성은 기본 중의 기본입니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[PostgreSQL 설치 후 기본 사용자 비밀번호 설정, 원격 접속 제어, 역할 권한 관리, 접속 로그 활성화까지 보안 강화 방법을 단계별로 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">iptables로 리눅스 서버 방화벽 직접 설정하기</title><link href="https://tcp-80.net/blog/2024/01/29/iptables-basics/" rel="alternate" type="text/html" title="iptables로 리눅스 서버 방화벽 직접 설정하기" /><published>2024-01-29T00:00:00+09:00</published><updated>2024-01-29T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/01/29/iptables-basics</id><content type="html" xml:base="https://tcp-80.net/blog/2024/01/29/iptables-basics/"><![CDATA[<p>UFW는 iptables를 감싸는 편의 도구입니다. 더 세밀한 제어가 필요하거나 스크립트로 방화벽을 관리할 때는 iptables를 직접 다루는 것이 효과적입니다.</p>

<h2 id="iptables-체인-구조">iptables 체인 구조</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>인터넷 → [PREROUTING] → 라우팅 결정
                          ↓              ↓
                       [INPUT]      [FORWARD]
                          ↓
                        서버 프로세스
                          ↓
                       [OUTPUT] → [POSTROUTING] → 인터넷
</code></pre></div></div>

<ul>
  <li><strong>INPUT</strong>: 서버로 들어오는 패킷</li>
  <li><strong>OUTPUT</strong>: 서버에서 나가는 패킷</li>
  <li><strong>FORWARD</strong>: 서버를 경유하는 패킷</li>
</ul>

<h2 id="현재-규칙-확인">현재 규칙 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 규칙 목록 (줄 번호 포함)</span>
<span class="nb">sudo </span>iptables <span class="nt">-L</span> <span class="nt">-n</span> <span class="nt">-v</span> <span class="nt">--line-numbers</span>

<span class="c"># NAT 테이블 확인</span>
<span class="nb">sudo </span>iptables <span class="nt">-t</span> nat <span class="nt">-L</span> <span class="nt">-n</span> <span class="nt">-v</span>
</code></pre></div></div>

<h2 id="기본-정책-설정">기본 정책 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 기본 정책: 입력은 차단, 출력은 허용</span>
<span class="nb">sudo </span>iptables <span class="nt">-P</span> INPUT DROP
<span class="nb">sudo </span>iptables <span class="nt">-P</span> FORWARD DROP
<span class="nb">sudo </span>iptables <span class="nt">-P</span> OUTPUT ACCEPT
</code></pre></div></div>

<blockquote>
  <p><strong>주의</strong>: 기본 정책을 DROP으로 바꾸기 전에 반드시 SSH 포트를 허용 규칙으로 추가하세요. 순서가 바뀌면 서버에 접속할 수 없게 됩니다.</p>
</blockquote>

<h2 id="필수-허용-규칙">필수 허용 규칙</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 루프백 인터페이스 허용</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-i</span> lo <span class="nt">-j</span> ACCEPT

<span class="c"># 기존 연결의 응답 패킷 허용 (ESTABLISHED, RELATED)</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-m</span> state <span class="nt">--state</span> ESTABLISHED,RELATED <span class="nt">-j</span> ACCEPT

<span class="c"># SSH 허용 (포트를 변경했다면 22 대신 변경한 포트 번호 입력)</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 22 <span class="nt">-j</span> ACCEPT

<span class="c"># HTTP, HTTPS 허용</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-j</span> ACCEPT
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 443 <span class="nt">-j</span> ACCEPT
</code></pre></div></div>

<h2 id="특정-ip-또는-대역-허용차단">특정 IP 또는 대역 허용/차단</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 특정 IP만 허용</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-s</span> 203.0.113.10 <span class="nt">-j</span> ACCEPT

<span class="c"># IP 대역 허용 (CIDR 표기)</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-s</span> 203.0.113.0/24 <span class="nt">-j</span> ACCEPT

<span class="c"># 특정 IP 차단</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-s</span> 192.0.2.100 <span class="nt">-j</span> DROP

<span class="c"># 특정 IP에서 오는 SSH만 허용 (더 엄격한 제어)</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-s</span> 203.0.113.10 <span class="nt">-p</span> tcp <span class="nt">--dport</span> 22 <span class="nt">-j</span> ACCEPT
</code></pre></div></div>

<h2 id="포트-범위-및-다중-포트">포트 범위 및 다중 포트</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 포트 범위 허용 (예: 8000~9000)</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 8000:9000 <span class="nt">-j</span> ACCEPT

<span class="c"># 여러 포트를 한 번에 (multiport 모듈)</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">-m</span> multiport <span class="nt">--dports</span> 80,443,8080 <span class="nt">-j</span> ACCEPT
</code></pre></div></div>

<h2 id="연결-수-제한-브루트포스-방어">연결 수 제한 (브루트포스 방어)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SSH 포트 연결 속도 제한 (1분에 4회 초과 시 차단)</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 22 <span class="nt">-m</span> state <span class="nt">--state</span> NEW <span class="se">\</span>
    <span class="nt">-m</span> recent <span class="nt">--set</span> <span class="nt">--name</span> SSH

<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 22 <span class="nt">-m</span> state <span class="nt">--state</span> NEW <span class="se">\</span>
    <span class="nt">-m</span> recent <span class="nt">--update</span> <span class="nt">--seconds</span> 60 <span class="nt">--hitcount</span> 4 <span class="nt">--name</span> SSH <span class="nt">-j</span> DROP
</code></pre></div></div>

<h2 id="icmp-ping-제어">ICMP (ping) 제어</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># ping 차단</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> icmp <span class="nt">-j</span> DROP

<span class="c"># ping 속도 제한 허용 (DDoS 방어)</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> icmp <span class="nt">--icmp-type</span> echo-request <span class="se">\</span>
    <span class="nt">-m</span> limit <span class="nt">--limit</span> 1/s <span class="nt">--limit-burst</span> 5 <span class="nt">-j</span> ACCEPT
</code></pre></div></div>

<h2 id="규칙-삭제">규칙 삭제</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 줄 번호로 삭제</span>
<span class="nb">sudo </span>iptables <span class="nt">-D</span> INPUT 3

<span class="c"># 규칙 내용으로 삭제 (-A 대신 -D)</span>
<span class="nb">sudo </span>iptables <span class="nt">-D</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 8080 <span class="nt">-j</span> ACCEPT

<span class="c"># 모든 규칙 초기화</span>
<span class="nb">sudo </span>iptables <span class="nt">-F</span> INPUT
</code></pre></div></div>

<h2 id="규칙-영구-저장">규칙 영구 저장</h2>

<p>재부팅하면 iptables 규칙이 초기화됩니다. 영구 적용하려면:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Debian/Ubuntu</span>
<span class="nb">sudo </span>apt <span class="nb">install </span>iptables-persistent
<span class="nb">sudo </span>netfilter-persistent save

<span class="c"># 또는 수동 저장</span>
<span class="nb">sudo </span>iptables-save <span class="o">&gt;</span> /etc/iptables/rules.v4
<span class="nb">sudo </span>ip6tables-save <span class="o">&gt;</span> /etc/iptables/rules.v6

<span class="c"># 부팅 시 자동 로드 확인</span>
<span class="nb">sudo </span>systemctl <span class="nb">enable </span>netfilter-persistent
</code></pre></div></div>

<h2 id="로깅-설정">로깅 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 차단된 패킷 로그 기록</span>
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-j</span> LOG <span class="nt">--log-prefix</span> <span class="s2">"IPT DROP: "</span> <span class="nt">--log-level</span> 4
<span class="nb">sudo </span>iptables <span class="nt">-A</span> INPUT <span class="nt">-j</span> DROP

<span class="c"># 로그 확인</span>
<span class="nb">sudo tail</span> <span class="nt">-f</span> /var/log/kern.log | <span class="nb">grep</span> <span class="s2">"IPT DROP"</span>
</code></pre></div></div>

<h2 id="완성된-방화벽-스크립트-예시">완성된 방화벽 스크립트 예시</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c"># /etc/iptables/setup.sh</span>

<span class="c"># 기존 규칙 초기화</span>
iptables <span class="nt">-F</span>
iptables <span class="nt">-X</span>

<span class="c"># 기본 정책</span>
iptables <span class="nt">-P</span> INPUT DROP
iptables <span class="nt">-P</span> FORWARD DROP
iptables <span class="nt">-P</span> OUTPUT ACCEPT

<span class="c"># 루프백</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-i</span> lo <span class="nt">-j</span> ACCEPT

<span class="c"># 기존 연결 허용</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-m</span> state <span class="nt">--state</span> ESTABLISHED,RELATED <span class="nt">-j</span> ACCEPT

<span class="c"># SSH (포트 22, 필요시 변경)</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 22 <span class="nt">-j</span> ACCEPT

<span class="c"># 웹 서버</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">-m</span> multiport <span class="nt">--dports</span> 80,443 <span class="nt">-j</span> ACCEPT

<span class="c"># 저장</span>
iptables-save <span class="o">&gt;</span> /etc/iptables/rules.v4
</code></pre></div></div>

<p>iptables를 이해하면 방화벽 동작을 정확히 제어할 수 있습니다. 복잡한 환경에서는 fail2ban과 함께 사용하면 더욱 효과적입니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[UFW보다 세밀한 제어가 필요할 때 사용하는 iptables 기초부터 체인 구조, 포트 허용·차단, 규칙 영구 저장까지 실전 위주로 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Nginx 성능 최적화: worker_processes부터 gzip까지</title><link href="https://tcp-80.net/blog/2024/01/15/nginx-performance-tuning/" rel="alternate" type="text/html" title="Nginx 성능 최적화: worker_processes부터 gzip까지" /><published>2024-01-15T00:00:00+09:00</published><updated>2024-01-15T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2024/01/15/nginx-performance-tuning</id><content type="html" xml:base="https://tcp-80.net/blog/2024/01/15/nginx-performance-tuning/"><![CDATA[<p>기본 설치 상태의 Nginx는 보수적인 설정값을 가지고 있어 서버 자원을 충분히 활용하지 못합니다. 올바른 튜닝으로 처리량을 수 배 끌어올릴 수 있습니다.</p>

<h2 id="현재-상태-확인">현재 상태 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Nginx 버전 및 컴파일 옵션 확인</span>
nginx <span class="nt">-V</span>

<span class="c"># 현재 연결 수 확인</span>
ss <span class="nt">-s</span>

<span class="c"># CPU 코어 수 확인</span>
<span class="nb">nproc</span>
</code></pre></div></div>

<h2 id="worker_processes-설정">worker_processes 설정</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/nginx/nginx.conf</code>에서 핵심 설정을 조정합니다:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># CPU 코어 수에 맞게 자동 설정 (권장)</span>
<span class="k">worker_processes</span> <span class="s">auto</span><span class="p">;</span>

<span class="k">events</span> <span class="p">{</span>
    <span class="c1"># 워커 당 최대 동시 연결 수</span>
    <span class="c1"># 울트라한 서버: 1024~4096, 일반: 512~1024</span>
    <span class="kn">worker_connections</span> <span class="mi">1024</span><span class="p">;</span>

    <span class="c1"># Linux epoll 이벤트 모델 사용 (성능 향상)</span>
    <span class="kn">use</span> <span class="s">epoll</span><span class="p">;</span>

    <span class="c1"># 연결 요청을 한 번에 수락</span>
    <span class="kn">multi_accept</span> <span class="no">on</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="http-블록-최적화">HTTP 블록 최적화</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">http</span> <span class="p">{</span>
    <span class="c1"># sendfile 시스템 콜로 파일 전송 (커널 공간에서 직접 처리)</span>
    <span class="kn">sendfile</span> <span class="no">on</span><span class="p">;</span>

    <span class="c1"># sendfile과 함께 사용, 패킷 전송 최적화</span>
    <span class="kn">tcp_nopush</span> <span class="no">on</span><span class="p">;</span>

    <span class="c1"># 작은 패킷 즉시 전송 (API 서버에 유용)</span>
    <span class="kn">tcp_nodelay</span> <span class="no">on</span><span class="p">;</span>

    <span class="c1"># Keep-Alive 타임아웃 (초)</span>
    <span class="kn">keepalive_timeout</span> <span class="mi">65</span><span class="p">;</span>

    <span class="c1"># Keep-Alive 최대 요청 수</span>
    <span class="kn">keepalive_requests</span> <span class="mi">100</span><span class="p">;</span>

    <span class="c1"># 해시 테이블 최적화</span>
    <span class="kn">types_hash_max_size</span> <span class="mi">2048</span><span class="p">;</span>
    <span class="kn">server_names_hash_bucket_size</span> <span class="mi">64</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="버퍼-크기-설정">버퍼 크기 설정</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">http</span> <span class="p">{</span>
    <span class="c1"># 클라이언트 요청 헤더 버퍼</span>
    <span class="kn">client_header_buffer_size</span> <span class="mi">1k</span><span class="p">;</span>
    <span class="kn">large_client_header_buffers</span> <span class="mi">4</span> <span class="mi">8k</span><span class="p">;</span>

    <span class="c1"># 클라이언트 요청 바디 버퍼 (POST 데이터)</span>
    <span class="kn">client_body_buffer_size</span> <span class="mi">128k</span><span class="p">;</span>
    <span class="kn">client_max_body_size</span> <span class="mi">10m</span><span class="p">;</span>   <span class="c1"># 업로드 최대 크기</span>

    <span class="c1"># 프록시 버퍼 (리버스 프록시 사용 시)</span>
    <span class="kn">proxy_buffering</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">proxy_buffer_size</span> <span class="mi">4k</span><span class="p">;</span>
    <span class="kn">proxy_buffers</span> <span class="mi">8</span> <span class="mi">4k</span><span class="p">;</span>
    <span class="kn">proxy_busy_buffers_size</span> <span class="mi">8k</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="gzip-압축-설정">gzip 압축 설정</h2>

<p>텍스트 기반 응답(HTML, CSS, JS, JSON)을 압축하면 전송량을 60~80% 줄일 수 있습니다:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">http</span> <span class="p">{</span>
    <span class="kn">gzip</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">gzip_vary</span> <span class="no">on</span><span class="p">;</span>
    <span class="kn">gzip_proxied</span> <span class="s">any</span><span class="p">;</span>

    <span class="c1"># 압축 레벨 (1~9, 높을수록 CPU 소모 증가)</span>
    <span class="c1"># 6이 속도와 압축률의 균형점</span>
    <span class="kn">gzip_comp_level</span> <span class="mi">6</span><span class="p">;</span>

    <span class="c1"># 이 크기 이상의 응답만 압축 (작은 파일은 압축 효율이 낮음)</span>
    <span class="kn">gzip_min_length</span> <span class="mi">1000</span><span class="p">;</span>

    <span class="c1"># 압축할 MIME 타입</span>
    <span class="kn">gzip_types</span>
        <span class="nc">text/plain</span>
        <span class="nc">text/css</span>
        <span class="nc">text/xml</span>
        <span class="nc">text/javascript</span>
        <span class="nc">application/javascript</span>
        <span class="nc">application/x-javascript</span>
        <span class="nc">application/json</span>
        <span class="nc">application/xml</span>
        <span class="nc">application/rss</span><span class="s">+xml</span>
        <span class="nc">image/svg</span><span class="s">+xml</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="정적-파일-캐싱-헤더">정적 파일 캐싱 헤더</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="c1"># 정적 파일에 캐시 헤더 추가</span>
    <span class="kn">location</span> <span class="p">~</span><span class="sr">*</span> <span class="err">\</span><span class="s">.(jpg|jpeg|png|gif|ico|css|js|woff2)</span>$ <span class="p">{</span>
        <span class="kn">expires</span> <span class="s">1y</span><span class="p">;</span>
        <span class="kn">add_header</span> <span class="s">Cache-Control</span> <span class="s">"public,</span> <span class="s">immutable"</span><span class="p">;</span>
        <span class="kn">access_log</span> <span class="no">off</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="타임아웃-설정">타임아웃 설정</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">http</span> <span class="p">{</span>
    <span class="c1"># 클라이언트 요청 타임아웃</span>
    <span class="kn">client_header_timeout</span> <span class="s">10s</span><span class="p">;</span>
    <span class="kn">client_body_timeout</span> <span class="s">10s</span><span class="p">;</span>
    <span class="kn">send_timeout</span> <span class="s">10s</span><span class="p">;</span>

    <span class="c1"># 느린 연결 차단 (Slowloris 방어 효과)</span>
    <span class="kn">reset_timedout_connection</span> <span class="no">on</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="설정-적용-및-검증">설정 적용 및 검증</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 설정 파일 문법 검사</span>
nginx <span class="nt">-t</span>

<span class="c"># 무중단 재로드</span>
<span class="nb">sudo </span>systemctl reload nginx

<span class="c"># 응답 속도 측정 (ab 벤치마크)</span>
ab <span class="nt">-n</span> 1000 <span class="nt">-c</span> 100 https://your-domain.com/

<span class="c"># gzip 압축 확인</span>
curl <span class="nt">-H</span> <span class="s2">"Accept-Encoding: gzip"</span> <span class="nt">-I</span> https://your-domain.com/
</code></pre></div></div>

<h2 id="성능-모니터링">성능 모니터링</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/conf.d/status.conf</span>
<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">80</span><span class="p">;</span>
    <span class="kn">location</span> <span class="n">/nginx_status</span> <span class="p">{</span>
        <span class="kn">stub_status</span> <span class="no">on</span><span class="p">;</span>
        <span class="kn">access_log</span> <span class="no">off</span><span class="p">;</span>
        <span class="kn">allow</span> <span class="mf">127.0</span><span class="s">.0.1</span><span class="p">;</span>
        <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl http://127.0.0.1/nginx_status
<span class="c"># Active connections: 145</span>
<span class="c"># server accepts handled requests</span>
<span class="c">#  1234567 1234567 2345678</span>
<span class="c"># Reading: 0 Writing: 12 Waiting: 133</span>
</code></pre></div></div>

<p>올바른 튜닝만으로도 동일 하드웨어에서 처리할 수 있는 요청 수가 크게 증가합니다. TCP-80.NET의 서버는 기본적으로 최적화된 Nginx 설정을 제공하며, 추가 튜닝이 필요하시면 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의하세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="성능" /><summary type="html"><![CDATA[Nginx의 worker_processes, 연결 수, 버퍼 크기, gzip 압축 등 핵심 설정을 조정해 웹 서버 응답 속도를 극대화하는 방법을 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">DDoS 공격 유형별 특징과 대응 방법</title><link href="https://tcp-80.net/blog/2023/11/20/ddos-attack-types/" rel="alternate" type="text/html" title="DDoS 공격 유형별 특징과 대응 방법" /><published>2023-11-20T00:00:00+09:00</published><updated>2023-11-20T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2023/11/20/ddos-attack-types</id><content type="html" xml:base="https://tcp-80.net/blog/2023/11/20/ddos-attack-types/"><![CDATA[<p>DDoS(Distributed Denial of Service) 공격은 다수의 좀비 PC나 서버에서 동시에 대량의 트래픽을 발생시켜 서비스를 마비시키는 공격입니다. 공격 유형에 따라 대응 방법이 다르므로, 유형을 정확히 파악하는 것이 중요합니다.</p>

<h2 id="레이어별-분류">레이어별 분류</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>L7 (애플리케이션): HTTP Flood, Slowloris, CC 공격
L4 (전송):         SYN Flood, UDP Flood, ACK Flood
L3 (네트워크):     ICMP Flood, IP Fragmentation
</code></pre></div></div>

<h2 id="l3l4-볼류메트릭-공격">L3/L4 볼류메트릭 공격</h2>

<h3 id="udp-flood">UDP Flood</h3>
<p>대량의 UDP 패킷을 임의의 포트로 전송합니다. 서버는 각 패킷을 처리하고 ICMP Destination Unreachable 메시지를 반환하느라 자원이 고갈됩니다.</p>

<p><strong>특징</strong>: 대역폭 소모, 수백 Gbps까지 발생 가능
<strong>대응</strong>: 업스트림 필터링, 불필요한 UDP 포트 차단</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># iptables로 UDP 트래픽 제한</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> udp <span class="nt">-m</span> limit <span class="nt">--limit</span> 100/s <span class="nt">--limit-burst</span> 200 <span class="nt">-j</span> ACCEPT
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> udp <span class="nt">-j</span> DROP
</code></pre></div></div>

<h3 id="syn-flood">SYN Flood</h3>
<p>TCP 3-way 핸드셰이크의 첫 단계(SYN)만 보내고 ACK를 보내지 않아 서버의 연결 대기 큐를 가득 채웁니다.</p>

<p><strong>특징</strong>: 서버 연결 자원 소모, 정상 사용자 접속 불가
<strong>대응</strong>: SYN Cookie 활성화</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SYN Cookie 활성화 (Linux)</span>
<span class="nb">echo </span>1 <span class="o">&gt;</span> /proc/sys/net/ipv4/tcp_syncookies

<span class="c"># 영구 설정</span>
<span class="nb">echo</span> <span class="s1">'net.ipv4.tcp_syncookies = 1'</span> <span class="o">&gt;&gt;</span> /etc/sysctl.conf
sysctl <span class="nt">-p</span>
</code></pre></div></div>

<h3 id="icmp-flood-ping-flood">ICMP Flood (Ping Flood)</h3>
<p>대량의 ICMP Echo Request(ping)를 전송합니다.</p>

<p><strong>대응</strong>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># ICMP 응답 비활성화</span>
<span class="nb">echo </span>1 <span class="o">&gt;</span> /proc/sys/net/ipv4/icmp_echo_ignore_all
</code></pre></div></div>

<h2 id="l7-애플리케이션-공격">L7 애플리케이션 공격</h2>

<h3 id="http-flood">HTTP Flood</h3>
<p>정상적인 HTTP GET/POST 요청을 대량으로 발생시킵니다. 각 요청이 서버 자원(DB 쿼리, 파일 읽기 등)을 소모하게 만듭니다.</p>

<p><strong>특징</strong>: 적은 대역폭으로도 서버 마비 가능, 탐지 어려움
<strong>대응</strong>: Rate Limiting, CAPTCHA</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Nginx Rate Limiting</span>
<span class="k">limit_req_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=api_limit:10m</span> <span class="s">rate=30r/m</span><span class="p">;</span>

<span class="k">location</span> <span class="n">/api/</span> <span class="p">{</span>
    <span class="kn">limit_req</span> <span class="s">zone=api_limit</span> <span class="s">burst=10</span> <span class="s">nodelay</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="slowloris">Slowloris</h3>
<p>HTTP 연결을 열어둔 채 헤더를 아주 천천히 전송하여 서버의 동시 연결 수를 고갈시킵니다.</p>

<p><strong>특징</strong>: 매우 적은 대역폭으로 서버 마비 가능
<strong>대응</strong>: 연결 타임아웃 설정</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Nginx 타임아웃 설정</span>
<span class="k">client_header_timeout</span> <span class="s">10s</span><span class="p">;</span>
<span class="k">client_body_timeout</span> <span class="s">10s</span><span class="p">;</span>
<span class="k">send_timeout</span> <span class="s">10s</span><span class="p">;</span>
<span class="k">keepalive_timeout</span> <span class="s">15s</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="공격-탐지-방법">공격 탐지 방법</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 초당 SYN 패킷 수 확인</span>
watch <span class="nt">-n</span> 1 <span class="s1">'netstat -s | grep "SYN"'</span>

<span class="c"># 연결 상태별 수 확인</span>
ss <span class="nt">-tan</span> | <span class="nb">awk</span> <span class="s1">'{print $1}'</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span>

<span class="c"># 특정 IP 연결 수 상위 20개</span>
ss <span class="nt">-tn</span> | <span class="nb">awk</span> <span class="s1">'NR&gt;1{print $5}'</span> | <span class="nb">cut</span> <span class="nt">-d</span>: <span class="nt">-f1</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># Nginx 초당 요청 수</span>
<span class="nb">tail</span> <span class="nt">-f</span> /var/log/nginx/access.log | <span class="nb">awk</span> <span class="s1">'{print $4}'</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
</code></pre></div></div>

<h2 id="tcp-커널-파라미터-최적화">TCP 커널 파라미터 최적화</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> <span class="o">&gt;&gt;</span> /etc/sysctl.conf <span class="o">&lt;&lt;</span> <span class="sh">'</span><span class="no">EOF</span><span class="sh">'
# SYN 대기 큐 크기 증가
net.ipv4.tcp_max_syn_backlog = 65536

# TIME_WAIT 소켓 재사용
net.ipv4.tcp_tw_reuse = 1

# 연결 추적 테이블 크기
net.netfilter.nf_conntrack_max = 1048576

# 백로그 큐 크기
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65536
</span><span class="no">EOF

</span>sysctl <span class="nt">-p</span>
</code></pre></div></div>

<h2 id="tcp-80net의-ddos-대응">TCP-80.NET의 DDoS 대응</h2>

<p>저희는 모든 서버에 네트워크 레이어 DDoS 방어를 기본 제공합니다. L7 레이어 공격이나 대규모 공격이 발생하면 웹 프록시 서비스나 DDoS 방어존 추가를 검토해 보세요.</p>

<p>텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 현재 공격 상황을 공유해 주시면 빠르게 대응 방안을 안내해 드립니다.</p>

<p>→ <a href="/ddos-security/">DDoS 보안 서비스 상세 보기</a></p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="보안" /><summary type="html"><![CDATA[L3/L4/L7 레이어별 DDoS 공격 유형과 특징, 그리고 각 공격에 대한 효과적인 대응 방법을 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">리눅스 스왑(Swap) 설정으로 메모리 부족 대비하기</title><link href="https://tcp-80.net/blog/2023/09/05/swap-memory-linux/" rel="alternate" type="text/html" title="리눅스 스왑(Swap) 설정으로 메모리 부족 대비하기" /><published>2023-09-05T00:00:00+09:00</published><updated>2023-09-05T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2023/09/05/swap-memory-linux</id><content type="html" xml:base="https://tcp-80.net/blog/2023/09/05/swap-memory-linux/"><![CDATA[<p>VPS처럼 RAM이 제한된 서버에서는 메모리가 부족하면 OOM Killer가 발동하여 중요한 프로세스를 강제 종료합니다. 스왑(Swap)을 설정하면 디스크 공간을 임시 메모리처럼 사용하여 이를 완화할 수 있습니다.</p>

<h2 id="현재-스왑-상태-확인">현재 스왑 상태 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 스왑 현황 확인</span>
<span class="nb">sudo </span>swapon <span class="nt">--show</span>

<span class="c"># 메모리 전체 현황</span>
free <span class="nt">-h</span>
</code></pre></div></div>

<h2 id="스왑-파일-생성">스왑 파일 생성</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 2GB 스왑 파일 생성 (RAM의 1~2배 권장)</span>
<span class="nb">sudo </span>fallocate <span class="nt">-l</span> 2G /swapfile

<span class="c"># 권한 설정 (root만 읽기/쓰기)</span>
<span class="nb">sudo chmod </span>600 /swapfile

<span class="c"># 스왑 영역으로 초기화</span>
<span class="nb">sudo </span>mkswap /swapfile

<span class="c"># 스왑 활성화</span>
<span class="nb">sudo </span>swapon /swapfile

<span class="c"># 확인</span>
<span class="nb">sudo </span>swapon <span class="nt">--show</span>
free <span class="nt">-h</span>
</code></pre></div></div>

<h2 id="부팅-시-자동-활성화">부팅 시 자동 활성화</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/fstab</code> 파일에 추가합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'/swapfile none swap sw 0 0'</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/fstab
</code></pre></div></div>

<h2 id="스왑-사용-적극도swappiness-조정">스왑 사용 적극도(Swappiness) 조정</h2>

<p><code class="language-plaintext highlighter-rouge">swappiness</code>는 시스템이 메모리 대신 스왑을 얼마나 적극적으로 사용할지 결정하는 값입니다 (0~100).</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">0</code>: 메모리가 완전히 차기 전까지 스왑 사용 안 함</li>
  <li><code class="language-plaintext highlighter-rouge">60</code>: 기본값</li>
  <li><code class="language-plaintext highlighter-rouge">100</code>: 가능한 한 스왑을 적극 사용</li>
</ul>

<p>서버 환경에서는 <code class="language-plaintext highlighter-rouge">10</code>으로 낮추는 것을 권장합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 현재 swappiness 확인</span>
<span class="nb">cat</span> /proc/sys/vm/swappiness

<span class="c"># 즉시 변경 (재부팅 후 초기화)</span>
<span class="nb">sudo </span>sysctl vm.swappiness<span class="o">=</span>10

<span class="c"># 영구 적용</span>
<span class="nb">echo</span> <span class="s1">'vm.swappiness=10'</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/sysctl.conf
<span class="nb">sudo </span>sysctl <span class="nt">-p</span>
</code></pre></div></div>

<h2 id="캐시-압력cache-pressure-조정">캐시 압력(Cache Pressure) 조정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 파일시스템 캐시를 더 오래 유지</span>
<span class="nb">echo</span> <span class="s1">'vm.vfs_cache_pressure=50'</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/sysctl.conf
<span class="nb">sudo </span>sysctl <span class="nt">-p</span>
</code></pre></div></div>

<h2 id="스왑-사용량-모니터링">스왑 사용량 모니터링</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 실시간 스왑 사용량 모니터링</span>
watch <span class="nt">-n</span> 1 <span class="s1">'free -h'</span>

<span class="c"># 스왑을 많이 사용하는 프로세스 확인</span>
<span class="k">for </span>file <span class="k">in</span> /proc/<span class="k">*</span>/status<span class="p">;</span> <span class="k">do
  </span><span class="nb">awk</span> <span class="s1">'/VmSwap|Name/{printf $2 " " $3 "\n"}'</span> <span class="nv">$file</span>
<span class="k">done</span> | <span class="nb">sort</span> <span class="nt">-k</span> 2 <span class="nt">-n</span> <span class="nt">-r</span> | <span class="nb">head</span> <span class="nt">-20</span>
</code></pre></div></div>

<h2 id="스왑-비활성화-및-삭제">스왑 비활성화 및 삭제</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 스왑 비활성화</span>
<span class="nb">sudo </span>swapoff /swapfile

<span class="c"># /etc/fstab에서 해당 줄 삭제</span>
<span class="nb">sudo sed</span> <span class="nt">-i</span> <span class="s1">'/swapfile/d'</span> /etc/fstab

<span class="c"># 파일 삭제</span>
<span class="nb">sudo rm</span> /swapfile
</code></pre></div></div>

<h2 id="스왑이-만능이-아닌-이유">스왑이 만능이 아닌 이유</h2>

<p>스왑은 RAM의 완전한 대체제가 아닙니다. 디스크는 RAM보다 수십~수백 배 느리기 때문에, 스왑 사용량이 지속적으로 높다면 서비스 성능이 크게 저하됩니다. 스왑은 긴급 완충재로만 활용하고, 근본적으로는 메모리 용량을 업그레이드하거나 메모리 최적화를 통해 해결해야 합니다.</p>

<p>TCP-80.NET에서 메모리 업그레이드가 필요하다면 텔레그램으로 문의해 주세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><summary type="html"><![CDATA[메모리가 부족한 서버에서 스왑 공간을 설정하여 Out-of-Memory(OOM) 오류를 방지하는 방법을 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Windows Server IIS 설치 및 기본 보안 설정</title><link href="https://tcp-80.net/blog/2023/06/14/windows-server-iis-setup/" rel="alternate" type="text/html" title="Windows Server IIS 설치 및 기본 보안 설정" /><published>2023-06-14T00:00:00+09:00</published><updated>2023-06-14T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2023/06/14/windows-server-iis-setup</id><content type="html" xml:base="https://tcp-80.net/blog/2023/06/14/windows-server-iis-setup/"><![CDATA[<p>IIS(Internet Information Services)는 Windows Server의 내장 웹서버입니다. ASP.NET 기반 웹 애플리케이션이나 Windows 환경에서 웹 서비스를 운영할 때 많이 사용합니다. 이 글에서는 IIS 설치부터 기본 보안 설정까지 설명합니다.</p>

<h2 id="iis-설치">IIS 설치</h2>

<h3 id="서버-관리자를-통한-설치">서버 관리자를 통한 설치</h3>

<ol>
  <li><strong>서버 관리자</strong> 실행</li>
  <li><strong>역할 및 기능 추가</strong> 클릭</li>
  <li><strong>서버 역할</strong> 단계에서 <strong>웹 서버(IIS)</strong> 선택</li>
  <li>기능 선택에서 필요한 항목 추가 후 설치</li>
</ol>

<h3 id="powershell로-설치">PowerShell로 설치</h3>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># IIS 기본 설치</span><span class="w">
</span><span class="n">Install-WindowsFeature</span><span class="w"> </span><span class="nt">-name</span><span class="w"> </span><span class="nx">Web-Server</span><span class="w"> </span><span class="nt">-IncludeManagementTools</span><span class="w">

</span><span class="c"># ASP.NET 포함 설치</span><span class="w">
</span><span class="n">Install-WindowsFeature</span><span class="w"> </span><span class="nt">-name</span><span class="w"> </span><span class="nx">Web-Server</span><span class="p">,</span><span class="w"> </span><span class="nx">Web-Asp-Net45</span><span class="p">,</span><span class="w"> </span><span class="nx">Web-Net-Ext45</span><span class="w"> </span><span class="nt">-IncludeManagementTools</span><span class="w">

</span><span class="c"># 설치 확인</span><span class="w">
</span><span class="n">Get-WindowsFeature</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">-like</span><span class="w"> </span><span class="s2">"Web-*"</span><span class="w"> </span><span class="o">-and</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">InstallState</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="s2">"Installed"</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h2 id="기본-사이트-구성">기본 사이트 구성</h2>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 기본 사이트 포트 변경</span><span class="w">
</span><span class="n">Import-Module</span><span class="w"> </span><span class="nx">WebAdministration</span><span class="w">
</span><span class="n">Set-WebBinding</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"Default Web Site"</span><span class="w"> </span><span class="nt">-BindingInformation</span><span class="w"> </span><span class="s2">"*:80:"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-PropertyName</span><span class="w"> </span><span class="nx">Port</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="nx">8080</span><span class="w">

</span><span class="c"># 새 사이트 추가</span><span class="w">
</span><span class="n">New-WebSite</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"MySite"</span><span class="w"> </span><span class="nt">-Port</span><span class="w"> </span><span class="nx">80</span><span class="w"> </span><span class="nt">-PhysicalPath</span><span class="w"> </span><span class="s2">"C:\inetpub\mysite"</span><span class="w"> </span><span class="nt">-Force</span><span class="w">

</span><span class="c"># 사이트 시작/중지</span><span class="w">
</span><span class="n">Start-WebSite</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"MySite"</span><span class="w">
</span><span class="n">Stop-WebSite</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"Default Web Site"</span><span class="w">
</span></code></pre></div></div>

<h2 id="보안-설정">보안 설정</h2>

<h3 id="디렉토리-검색-비활성화">디렉토리 검색 비활성화</h3>

<p>디렉토리 내용이 외부에 노출되지 않도록 합니다:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Set-WebConfigurationProperty</span><span class="w"> </span><span class="nt">-Filter</span><span class="w"> </span><span class="s2">"system.webServer/directoryBrowse"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">Enabled</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="nx">False</span><span class="w"> </span><span class="nt">-PSPath</span><span class="w"> </span><span class="s2">"IIS:\"</span><span class="w">
</span></code></pre></div></div>

<p>또는 IIS 관리자 → 사이트 선택 → <strong>디렉터리 검색</strong> → 오른쪽 패널에서 <strong>사용 안 함</strong></p>

<h3 id="서버-버전-정보-숨기기">서버 버전 정보 숨기기</h3>

<p><code class="language-plaintext highlighter-rouge">C:\Windows\System32\inetsrv\config\applicationHost.config</code>:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;httpProtocol&gt;</span>
    <span class="nt">&lt;customHeaders&gt;</span>
        <span class="nt">&lt;remove</span> <span class="na">name=</span><span class="s">"X-Powered-By"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/customHeaders&gt;</span>
<span class="nt">&lt;/httpProtocol&gt;</span>
</code></pre></div></div>

<p>PowerShell:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># X-Powered-By 헤더 제거</span><span class="w">
</span><span class="n">Remove-WebConfigurationProperty</span><span class="w"> </span><span class="nt">-PSPath</span><span class="w"> </span><span class="s2">"IIS:\"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Filter</span><span class="w"> </span><span class="s2">"system.webServer/httpProtocol/customHeaders"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"."</span><span class="w"> </span><span class="nt">-AtElement</span><span class="w"> </span><span class="p">@{</span><span class="nx">name</span><span class="o">=</span><span class="s1">'X-Powered-By'</span><span class="p">}</span><span class="w">

</span><span class="c"># Server 헤더 숨기기 (URL Rewrite 모듈 필요)</span><span class="w">
</span><span class="n">Add-WebConfigurationProperty</span><span class="w"> </span><span class="nt">-PSPath</span><span class="w"> </span><span class="s2">"IIS:\"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Filter</span><span class="w"> </span><span class="s2">"system.webServer/rewrite/outboundRules"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"."</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="p">@{</span><span class="nx">name</span><span class="o">=</span><span class="s2">"Remove Server Header"</span><span class="p">;</span><span class="w"> </span><span class="nx">enabled</span><span class="o">=</span><span class="s2">"True"</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="보안-http-헤더-추가">보안 HTTP 헤더 추가</h3>

<p><code class="language-plaintext highlighter-rouge">web.config</code>에 추가합니다:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;system.webServer&gt;</span>
    <span class="nt">&lt;httpProtocol&gt;</span>
        <span class="nt">&lt;customHeaders&gt;</span>
            <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"X-Content-Type-Options"</span> <span class="na">value=</span><span class="s">"nosniff"</span> <span class="nt">/&gt;</span>
            <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"X-Frame-Options"</span> <span class="na">value=</span><span class="s">"SAMEORIGIN"</span> <span class="nt">/&gt;</span>
            <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"X-XSS-Protection"</span> <span class="na">value=</span><span class="s">"1; mode=block"</span> <span class="nt">/&gt;</span>
            <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"Strict-Transport-Security"</span> <span class="na">value=</span><span class="s">"max-age=31536000; includeSubDomains"</span> <span class="nt">/&gt;</span>
        <span class="nt">&lt;/customHeaders&gt;</span>
    <span class="nt">&lt;/httpProtocol&gt;</span>
<span class="nt">&lt;/system.webServer&gt;</span>
</code></pre></div></div>

<h3 id="요청-필터링">요청 필터링</h3>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 최대 요청 크기 제한 (10MB)</span><span class="w">
</span><span class="n">Set-WebConfigurationProperty</span><span class="w"> </span><span class="nt">-PSPath</span><span class="w"> </span><span class="s2">"IIS:\"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Filter</span><span class="w"> </span><span class="s2">"system.webServer/security/requestFiltering/requestLimits"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">maxAllowedContentLength</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="nx">10485760</span><span class="w">

</span><span class="c"># 위험한 확장자 차단</span><span class="w">
</span><span class="n">Add-WebConfigurationProperty</span><span class="w"> </span><span class="nt">-PSPath</span><span class="w"> </span><span class="s2">"IIS:\"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Filter</span><span class="w"> </span><span class="s2">"system.webServer/security/requestFiltering/fileExtensions"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"."</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="p">@{</span><span class="nx">fileExtension</span><span class="o">=</span><span class="s2">".php"</span><span class="p">;</span><span class="w"> </span><span class="nx">allowed</span><span class="o">=</span><span class="s2">"False"</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h2 id="ssl-인증서-적용">SSL 인증서 적용</h2>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 자체 서명 인증서 생성 (테스트용)</span><span class="w">
</span><span class="n">New-SelfSignedCertificate</span><span class="w"> </span><span class="nt">-DnsName</span><span class="w"> </span><span class="s2">"example.com"</span><span class="w"> </span><span class="nt">-CertStoreLocation</span><span class="w"> </span><span class="s2">"cert:\LocalMachine\My"</span><span class="w">

</span><span class="c"># HTTPS 바인딩 추가</span><span class="w">
</span><span class="n">New-WebBinding</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"MySite"</span><span class="w"> </span><span class="nt">-Protocol</span><span class="w"> </span><span class="s2">"https"</span><span class="w"> </span><span class="nt">-Port</span><span class="w"> </span><span class="nx">443</span><span class="w"> </span><span class="nt">-SslFlags</span><span class="w"> </span><span class="nx">0</span><span class="w">
</span></code></pre></div></div>

<h2 id="iis-로그-설정">IIS 로그 설정</h2>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 로그 위치 확인</span><span class="w">
</span><span class="n">Get-WebConfigurationProperty</span><span class="w"> </span><span class="nt">-PSPath</span><span class="w"> </span><span class="s2">"IIS:\"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Filter</span><span class="w"> </span><span class="s2">"system.applicationHost/sites/siteDefaults/logFile"</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">directory</span><span class="w">

</span><span class="c"># 로그 형식을 W3C로 설정 (권장)</span><span class="w">
</span><span class="n">Set-WebConfigurationProperty</span><span class="w"> </span><span class="nt">-PSPath</span><span class="w"> </span><span class="s2">"IIS:\"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Filter</span><span class="w"> </span><span class="s2">"system.applicationHost/sites/siteDefaults/logFile"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Name</span><span class="w"> </span><span class="nx">logFormat</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="s2">"W3C"</span><span class="w">
</span></code></pre></div></div>

<p>기본 로그 위치는 <code class="language-plaintext highlighter-rouge">C:\inetpub\logs\LogFiles\</code>입니다. 정기적으로 검토하여 비정상 접근을 확인하세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Windows" /><summary type="html"><![CDATA[Windows Server에 IIS(인터넷 정보 서비스)를 설치하고, 보안 강화를 위한 기본 설정을 적용하는 방법을 안내합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">리눅스 로그 분석: 침입 흔적을 찾는 방법</title><link href="https://tcp-80.net/blog/2023/03/27/linux-log-analysis/" rel="alternate" type="text/html" title="리눅스 로그 분석: 침입 흔적을 찾는 방법" /><published>2023-03-27T00:00:00+09:00</published><updated>2023-03-27T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2023/03/27/linux-log-analysis</id><content type="html" xml:base="https://tcp-80.net/blog/2023/03/27/linux-log-analysis/"><![CDATA[<p>서버가 해킹을 당했거나 의심스러운 상황이 발생했을 때, 로그 파일은 가장 중요한 단서가 됩니다. 이 글에서는 주요 로그 파일의 위치와 분석 방법을 알아봅니다.</p>

<h2 id="주요-로그-파일-위치">주요 로그 파일 위치</h2>

<table>
  <thead>
    <tr>
      <th>로그 파일</th>
      <th>내용</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/var/log/auth.log</code></td>
      <td>SSH 로그인, sudo 사용 내역</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/var/log/syslog</code></td>
      <td>시스템 전반 메시지</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/var/log/kern.log</code></td>
      <td>커널 메시지</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/var/log/nginx/access.log</code></td>
      <td>Nginx 접속 로그</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/var/log/nginx/error.log</code></td>
      <td>Nginx 에러 로그</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/var/log/mysql/error.log</code></td>
      <td>MySQL 에러</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/var/log/fail2ban.log</code></td>
      <td>fail2ban 차단 기록</td>
    </tr>
  </tbody>
</table>

<h2 id="ssh-침입-시도-분석">SSH 침입 시도 분석</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 로그인 실패 IP 상위 20개</span>
<span class="nb">grep</span> <span class="s2">"Failed password"</span> /var/log/auth.log | <span class="se">\</span>
  <span class="nb">awk</span> <span class="s1">'{print $(NF-3)}'</span> | <span class="se">\</span>
  <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># 특정 날짜 로그인 실패</span>
<span class="nb">grep</span> <span class="s2">"Failed password"</span> /var/log/auth.log | <span class="se">\</span>
  <span class="nb">grep</span> <span class="s2">"Jan 15"</span> | <span class="nb">wc</span> <span class="nt">-l</span>

<span class="c"># 성공한 SSH 로그인 확인</span>
<span class="nb">grep</span> <span class="s2">"Accepted"</span> /var/log/auth.log | <span class="se">\</span>
  <span class="nb">awk</span> <span class="s1">'{print $1, $2, $3, $9, $11}'</span>

<span class="c"># 비정상적인 시간대 로그인 확인 (야간)</span>
<span class="nb">grep</span> <span class="s2">"Accepted"</span> /var/log/auth.log | <span class="se">\</span>
  <span class="nb">awk</span> <span class="s1">'$3 ~ /^(00|01|02|03|04|05):/'</span>
</code></pre></div></div>

<h2 id="sudo-사용-내역-확인">sudo 사용 내역 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 모든 sudo 명령 확인</span>
<span class="nb">grep</span> <span class="s2">"sudo"</span> /var/log/auth.log | <span class="nb">grep</span> <span class="s2">"COMMAND"</span>

<span class="c"># root로 su 전환 시도</span>
<span class="nb">grep</span> <span class="s2">"su</span><span class="se">\[</span><span class="s2">"</span> /var/log/auth.log
</code></pre></div></div>

<h2 id="웹서버-로그에서-공격-패턴-탐지">웹서버 로그에서 공격 패턴 탐지</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SQL 인젝션 시도 탐지</span>
<span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"(union|select|insert|drop|update|delete|exec|script)"</span> <span class="se">\</span>
  /var/log/nginx/access.log <span class="nt">-i</span> | <span class="nb">grep</span> <span class="s2">"200</span><span class="se">\|</span><span class="s2">301</span><span class="se">\|</span><span class="s2">302"</span>

<span class="c"># 웹쉘 접근 시도</span>
<span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"</span><span class="se">\.</span><span class="s2">(php|asp|aspx|jsp)</span><span class="se">\?</span><span class="s2">"</span> /var/log/nginx/access.log | <span class="se">\</span>
  <span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"(cmd=|exec=|shell=|passthru)"</span>

<span class="c"># 404 에러 폭증 (디렉토리 스캔 의심)</span>
<span class="nb">awk</span> <span class="s1">'$9==404{print $1}'</span> /var/log/nginx/access.log | <span class="se">\</span>
  <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-20</span>

<span class="c"># 특정 IP의 모든 접근</span>
<span class="nb">grep</span> <span class="s2">"1.2.3.4"</span> /var/log/nginx/access.log

<span class="c"># 대용량 응답 (데이터 유출 의심)</span>
<span class="nb">awk</span> <span class="s1">'$10 &gt; 1000000 {print}'</span> /var/log/nginx/access.log
</code></pre></div></div>

<h2 id="시스템-변조-흔적-확인">시스템 변조 흔적 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 최근 24시간 내 수정된 실행 파일</span>
find /usr /bin /sbin <span class="nt">-newer</span> /var/log/dpkg.log <span class="nt">-type</span> f 2&gt;/dev/null

<span class="c"># SUID 파일 목록 (공격자가 추가했을 수 있음)</span>
find / <span class="nt">-perm</span> <span class="nt">-4000</span> <span class="nt">-type</span> f 2&gt;/dev/null | <span class="nb">sort</span>

<span class="c"># 숨겨진 디렉토리 확인</span>
find / <span class="nt">-name</span> <span class="s2">".*"</span> <span class="nt">-type</span> d 2&gt;/dev/null | <span class="nb">grep</span> <span class="nt">-v</span> <span class="s2">"^/proc</span><span class="se">\|</span><span class="s2">^/sys"</span>

<span class="c"># 크론 작업 전체 확인 (백도어 심는 데 자주 사용)</span>
<span class="k">for </span>user <span class="k">in</span> <span class="si">$(</span><span class="nb">cut</span> <span class="nt">-f1</span> <span class="nt">-d</span>: /etc/passwd<span class="si">)</span><span class="p">;</span> <span class="k">do
  </span>crontab <span class="nt">-u</span> <span class="nv">$user</span> <span class="nt">-l</span> 2&gt;/dev/null | <span class="nb">grep</span> <span class="nt">-v</span> <span class="s2">"^#"</span>
<span class="k">done
</span><span class="nb">cat</span> /etc/cron<span class="k">*</span> /etc/at<span class="k">*</span> 2&gt;/dev/null
</code></pre></div></div>

<h2 id="네트워크-연결-이상-확인">네트워크 연결 이상 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 알 수 없는 외부 연결 확인</span>
ss <span class="nt">-tnp</span> | <span class="nb">grep </span>ESTABLISHED

<span class="c"># 백도어 포트 확인 (알 수 없는 LISTEN 포트)</span>
ss <span class="nt">-tlnp</span>

<span class="c"># DNS 쿼리 로그 (dnsmasq 사용 시)</span>
<span class="nb">tail</span> <span class="nt">-100</span> /var/log/dnsmasq.log
</code></pre></div></div>

<h2 id="로그-보존-정책">로그 보존 정책</h2>

<p>로그는 공격자가 삭제하는 경우가 많습니다. 중요 로그를 외부 서버로 실시간 전송하는 것을 권장합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># rsyslog으로 원격 로그 서버 전송</span>
<span class="nb">echo</span> <span class="s2">"*.* @로그서버IP:514"</span> <span class="o">&gt;&gt;</span> /etc/rsyslog.conf
<span class="nb">sudo </span>systemctl restart rsyslog
</code></pre></div></div>

<p>정기적인 로그 검토는 침해사고를 조기에 발견하는 가장 효과적인 방법입니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[auth.log, syslog, 웹서버 로그 등 주요 리눅스 로그 파일을 분석하여 침입 시도와 이상 징후를 탐지하는 방법을 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Windows Server RDP 보안 강화 가이드</title><link href="https://tcp-80.net/blog/2023/01/19/windows-server-rdp-security/" rel="alternate" type="text/html" title="Windows Server RDP 보안 강화 가이드" /><published>2023-01-19T00:00:00+09:00</published><updated>2023-01-19T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2023/01/19/windows-server-rdp-security</id><content type="html" xml:base="https://tcp-80.net/blog/2023/01/19/windows-server-rdp-security/"><![CDATA[<p>Windows Server의 RDP(Remote Desktop Protocol)는 기본 3389 포트를 사용하며, 인터넷에 노출되면 자동화된 브루트포스 공격의 표적이 됩니다. 이 글에서는 단계별로 RDP 보안을 강화하는 방법을 설명합니다.</p>

<h2 id="1-rdp-포트-변경">1. RDP 포트 변경</h2>

<p>레지스트리 편집기(<code class="language-plaintext highlighter-rouge">regedit</code>)를 열고 다음 경로로 이동합니다:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">PortNumber</code> 값을 더블클릭 → 10진수로 변경 → 원하는 포트 번호 입력 (예: 33899)</p>

<p>이후 방화벽 규칙도 변경해야 합니다:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 기존 RDP 규칙 비활성화</span><span class="w">
</span><span class="n">netsh</span><span class="w"> </span><span class="nx">advfirewall</span><span class="w"> </span><span class="nx">firewall</span><span class="w"> </span><span class="nx">set</span><span class="w"> </span><span class="nx">rule</span><span class="w"> </span><span class="nx">name</span><span class="o">=</span><span class="s2">"Remote Desktop - User Mode (TCP-In)"</span><span class="w"> </span><span class="n">new</span><span class="w"> </span><span class="nx">enable</span><span class="o">=</span><span class="n">no</span><span class="w">

</span><span class="c"># 새 포트로 규칙 추가</span><span class="w">
</span><span class="n">netsh</span><span class="w"> </span><span class="nx">advfirewall</span><span class="w"> </span><span class="nx">firewall</span><span class="w"> </span><span class="nx">add</span><span class="w"> </span><span class="nx">rule</span><span class="w"> </span><span class="nx">name</span><span class="o">=</span><span class="s2">"RDP Custom Port"</span><span class="w"> </span><span class="n">protocol</span><span class="o">=</span><span class="n">TCP</span><span class="w"> </span><span class="nx">dir</span><span class="o">=</span><span class="kr">in</span><span class="w"> </span><span class="n">localport</span><span class="o">=</span><span class="mi">33899</span><span class="w"> </span><span class="n">action</span><span class="o">=</span><span class="n">allow</span><span class="w">

</span><span class="c"># 서비스 재시작</span><span class="w">
</span><span class="n">net</span><span class="w"> </span><span class="nx">stop</span><span class="w"> </span><span class="nx">TermService</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">net</span><span class="w"> </span><span class="nx">start</span><span class="w"> </span><span class="nx">TermService</span><span class="w">
</span></code></pre></div></div>

<h2 id="2-nla네트워크-수준-인증-활성화">2. NLA(네트워크 수준 인증) 활성화</h2>

<p>NLA는 RDP 세션 연결 전에 인증을 요구하여 미인증 연결을 차단합니다.</p>

<p><strong>설정 방법</strong>: 시스템 속성 → 원격 탭 → “네트워크 수준 인증을 사용하는 원격 데스크톱만 허용” 선택</p>

<p>또는 PowerShell:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Set-ItemProperty</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s1">'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"UserAuthentication"</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="nx">1</span><span class="w">
</span></code></pre></div></div>

<h2 id="3-계정-잠금-정책-설정">3. 계정 잠금 정책 설정</h2>

<p><code class="language-plaintext highlighter-rouge">gpedit.msc</code> → 컴퓨터 구성 → Windows 설정 → 보안 설정 → 계정 정책 → 계정 잠금 정책:</p>

<table>
  <thead>
    <tr>
      <th>설정</th>
      <th>권장값</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>계정 잠금 임계값</td>
      <td>5회</td>
    </tr>
    <tr>
      <td>계정 잠금 기간</td>
      <td>30분</td>
    </tr>
    <tr>
      <td>계정 잠금 카운터 재설정</td>
      <td>30분</td>
    </tr>
  </tbody>
</table>

<p>PowerShell로도 설정 가능합니다:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">net</span><span class="w"> </span><span class="nx">accounts</span><span class="w"> </span><span class="nx">/lockoutthreshold:5</span><span class="w"> </span><span class="nx">/lockoutduration:30</span><span class="w"> </span><span class="nx">/lockoutwindow:30</span><span class="w">
</span></code></pre></div></div>

<h2 id="4-특정-ip만-rdp-허용">4. 특정 IP만 RDP 허용</h2>

<p>방화벽에서 관리자 IP만 허용합니다:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 기존 규칙에 원본 IP 제한 추가</span><span class="w">
</span><span class="n">New-NetFirewallRule</span><span class="w"> </span><span class="nt">-DisplayName</span><span class="w"> </span><span class="s2">"RDP from Admin IP"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Direction</span><span class="w"> </span><span class="nx">Inbound</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Protocol</span><span class="w"> </span><span class="nx">TCP</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-LocalPort</span><span class="w"> </span><span class="nx">33899</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-RemoteAddress</span><span class="w"> </span><span class="s2">"203.0.113.1"</span><span class="w"> </span><span class="se">`
</span><span class="w">    </span><span class="nt">-Action</span><span class="w"> </span><span class="nx">Allow</span><span class="w">
</span></code></pre></div></div>

<h2 id="5-관리자-계정-이름-변경">5. 관리자 계정 이름 변경</h2>

<p>기본 <code class="language-plaintext highlighter-rouge">Administrator</code> 계정을 대상으로 한 공격이 많습니다:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>secpol.msc → 로컬 정책 → 보안 옵션 → "계정: Administrator 계정 이름 바꾸기"
</code></pre></div></div>

<h2 id="6-rdp-보안-로그-모니터링">6. RDP 보안 로그 모니터링</h2>

<p>이벤트 뷰어에서 RDP 로그인 시도를 확인합니다:</p>

<ul>
  <li><strong>이벤트 ID 4625</strong>: 로그인 실패</li>
  <li><strong>이벤트 ID 4624</strong>: 로그인 성공</li>
  <li><strong>이벤트 ID 4648</strong>: 명시적 자격 증명으로 로그온</li>
</ul>

<p>PowerShell로 최근 실패 로그인 확인:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Get-WinEvent</span><span class="w"> </span><span class="nt">-FilterHashtable</span><span class="w"> </span><span class="p">@{</span><span class="w">
    </span><span class="nx">LogName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'Security'</span><span class="w">
    </span><span class="nx">Id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">4625</span><span class="w">
    </span><span class="nx">StartTime</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">(</span><span class="nx">Get</span><span class="err">-</span><span class="nx">Date</span><span class="err">).</span><span class="nx">AddDays</span><span class="err">(-</span><span class="mi">1</span><span class="err">)</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nx">TimeCreated</span><span class="p">,</span><span class="w"> </span><span class="nx">Message</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Format-Table</span><span class="w"> </span><span class="nt">-AutoSize</span><span class="w">
</span></code></pre></div></div>

<h2 id="7-windows-defender-방화벽-고급-설정">7. Windows Defender 방화벽 고급 설정</h2>

<p>RDP에 대한 연결 보안 규칙을 추가하여 무결성 검사를 적용합니다:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wf.msc → 연결 보안 규칙 → 새 규칙 → 격리
</code></pre></div></div>

<p>이 7가지 설정만 적용해도 대부분의 자동화 RDP 공격을 방어할 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Windows" /><category term="보안" /><summary type="html"><![CDATA[원격 데스크톱(RDP) 포트 변경, NLA 활성화, 계정 잠금 정책 등 Windows Server RDP 보안을 강화하는 방법을 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">WordPress 서버 보안 강화 체크리스트</title><link href="https://tcp-80.net/blog/2022/11/08/wordpress-security/" rel="alternate" type="text/html" title="WordPress 서버 보안 강화 체크리스트" /><published>2022-11-08T00:00:00+09:00</published><updated>2022-11-08T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2022/11/08/wordpress-security</id><content type="html" xml:base="https://tcp-80.net/blog/2022/11/08/wordpress-security/"><![CDATA[<p>WordPress는 전 세계 웹사이트의 40% 이상을 차지하는 만큼, 해킹 시도의 주요 표적이기도 합니다. 플러그인이나 테마 취약점뿐 아니라 서버 설정도 함께 강화해야 합니다.</p>

<h2 id="파일-권한-설정">파일 권한 설정</h2>

<p>잘못된 파일 권한은 해킹의 주요 경로입니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># WordPress 루트 디렉토리</span>
find /var/www/html <span class="nt">-type</span> d <span class="nt">-exec</span> <span class="nb">chmod </span>755 <span class="o">{}</span> <span class="se">\;</span>
find /var/www/html <span class="nt">-type</span> f <span class="nt">-exec</span> <span class="nb">chmod </span>644 <span class="o">{}</span> <span class="se">\;</span>

<span class="c"># wp-config.php는 더 엄격하게</span>
<span class="nb">chmod </span>440 /var/www/html/wp-config.php

<span class="c"># 웹서버 소유권 설정</span>
<span class="nb">chown</span> <span class="nt">-R</span> www-data:www-data /var/www/html
</code></pre></div></div>

<h2 id="nginx에서-민감한-파일-차단">Nginx에서 민감한 파일 차단</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/nginx/sites-available/yourdomain</code> 에 추가합니다:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># wp-config.php 직접 접근 차단</span>
<span class="k">location</span> <span class="p">=</span> <span class="n">/wp-config.php</span> <span class="p">{</span>
    <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1"># .htaccess, .git 등 숨김 파일 차단</span>
<span class="k">location</span> <span class="p">~</span> <span class="sr">/\.</span> <span class="p">{</span>
    <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1"># xmlrpc.php 차단 (불필요하면)</span>
<span class="k">location</span> <span class="p">=</span> <span class="n">/xmlrpc.php</span> <span class="p">{</span>
    <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
    <span class="kn">access_log</span> <span class="no">off</span><span class="p">;</span>
    <span class="kn">log_not_found</span> <span class="no">off</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1"># 업로드 디렉토리에서 PHP 실행 차단</span>
<span class="k">location</span> <span class="p">~</span><span class="sr">*</span> <span class="n">/uploads/.*\.php</span>$ <span class="p">{</span>
    <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1"># 워드프레스 코어 파일 직접 접근 차단</span>
<span class="k">location</span> <span class="p">~</span><span class="sr">*</span> <span class="s">^/wp-admin/includes/</span> <span class="p">{</span>
    <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="wp-loginphp-보호">wp-login.php 보호</h2>

<p>로그인 페이지에 대한 브루트포스 공격을 제한합니다:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># IP 제한 (관리자 IP만 허용)</span>
<span class="k">location</span> <span class="p">=</span> <span class="n">/wp-login.php</span> <span class="p">{</span>
    <span class="kn">allow</span> <span class="mf">203.0</span><span class="s">.113.1</span><span class="p">;</span>
    <span class="kn">deny</span> <span class="s">all</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1"># 또는 Rate Limiting 적용</span>
<span class="k">limit_req_zone</span> <span class="nv">$binary_remote_addr</span> <span class="s">zone=wp_login:10m</span> <span class="s">rate=5r/m</span><span class="p">;</span>

<span class="k">location</span> <span class="p">=</span> <span class="n">/wp-login.php</span> <span class="p">{</span>
    <span class="kn">limit_req</span> <span class="s">zone=wp_login</span> <span class="s">burst=3</span> <span class="s">nodelay</span><span class="p">;</span>
    <span class="kn">fastcgi_pass</span> <span class="s">unix:/run/php/php8.1-fpm.sock</span><span class="p">;</span>
    <span class="kn">include</span> <span class="s">fastcgi_params</span><span class="p">;</span>
    <span class="kn">fastcgi_param</span> <span class="s">SCRIPT_FILENAME</span> <span class="nv">$document_root$fastcgi_script_name</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="php-설정-강화">PHP 설정 강화</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/php/8.1/fpm/php.ini</code> 편집:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 에러 메시지 외부 노출 금지
</span><span class="py">display_errors</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">Off</span>
<span class="py">log_errors</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">On</span>
<span class="py">error_log</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/php/error.log</span>
<span class="w">
</span><span class="c"># 파일 업로드 제한
</span><span class="py">upload_max_filesize</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10M</span>
<span class="py">post_max_size</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10M</span>
<span class="w">
</span><span class="c"># 실행 시간 제한
</span><span class="py">max_execution_time</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">60</span>
<span class="py">memory_limit</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">256M</span>
<span class="w">
</span><span class="c"># PHP 버전 정보 숨기기
</span><span class="py">expose_php</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">Off</span>
<span class="w">
</span><span class="c"># 위험한 함수 비활성화
</span><span class="py">disable_functions</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">exec,passthru,shell_exec,system,proc_open,popen</span>
</code></pre></div></div>

<h2 id="보안-http-헤더-추가">보안 HTTP 헤더 추가</h2>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="c1"># 클릭재킹 방지</span>
    <span class="kn">add_header</span> <span class="s">X-Frame-Options</span> <span class="s">"SAMEORIGIN"</span> <span class="s">always</span><span class="p">;</span>

    <span class="c1"># MIME 타입 스니핑 방지</span>
    <span class="kn">add_header</span> <span class="s">X-Content-Type-Options</span> <span class="s">"nosniff"</span> <span class="s">always</span><span class="p">;</span>

    <span class="c1"># XSS 필터 활성화</span>
    <span class="kn">add_header</span> <span class="s">X-XSS-Protection</span> <span class="s">"1</span><span class="p">;</span> <span class="kn">mode=block"</span> <span class="s">always</span><span class="p">;</span>

    <span class="c1"># HTTPS 강제 (SSL 적용 후)</span>
    <span class="kn">add_header</span> <span class="s">Strict-Transport-Security</span> <span class="s">"max-age=31536000</span><span class="p">;</span> <span class="kn">includeSubDomains"</span> <span class="s">always</span><span class="p">;</span>

    <span class="c1"># 서버 정보 숨기기</span>
    <span class="kn">server_tokens</span> <span class="no">off</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="정기-점검-체크리스트">정기 점검 체크리스트</h2>

<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />WordPress 코어, 플러그인, 테마 최신 버전 유지</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />비활성화된 플러그인/테마 삭제 (비활성화만으로는 취약점이 남음)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />관리자 계정 이름 <code class="language-plaintext highlighter-rouge">admin</code> 변경</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />강력한 비밀번호 사용 (최소 16자)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />2단계 인증(2FA) 플러그인 적용</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />정기 파일 무결성 검사</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />접속 로그 정기 검토</li>
</ul>

<h2 id="해킹-후-대응">해킹 후 대응</h2>

<p>이미 해킹이 의심된다면:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 최근 수정된 PHP 파일 확인</span>
find /var/www/html <span class="nt">-name</span> <span class="s2">"*.php"</span> <span class="nt">-newer</span> /var/www/html/wp-config.php <span class="nt">-ls</span>

<span class="c"># 알 수 없는 PHP 코드 패턴 검색</span>
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"eval(base64_decode"</span> /var/www/html <span class="nt">--include</span><span class="o">=</span><span class="s2">"*.php"</span>
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"&lt;?php </span><span class="se">\$</span><span class="s2">_"</span> /var/www/html <span class="nt">--include</span><span class="o">=</span><span class="s2">"*.php"</span>
</code></pre></div></div>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="보안" /><category term="Linux" /><summary type="html"><![CDATA[WordPress 사이트를 운영할 때 반드시 점검해야 할 서버 사이드 보안 설정을 체크리스트 형태로 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">리눅스 서버 실시간 모니터링 도구 총정리</title><link href="https://tcp-80.net/blog/2022/09/30/linux-system-monitoring/" rel="alternate" type="text/html" title="리눅스 서버 실시간 모니터링 도구 총정리" /><published>2022-09-30T00:00:00+09:00</published><updated>2022-09-30T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2022/09/30/linux-system-monitoring</id><content type="html" xml:base="https://tcp-80.net/blog/2022/09/30/linux-system-monitoring/"><![CDATA[<p>서버 운영에서 현재 상태를 빠르게 파악하는 능력은 매우 중요합니다. 특히 장애 발생 시 원인을 신속하게 진단하려면 모니터링 도구를 능숙하게 사용할 줄 알아야 합니다.</p>

<h2 id="cpu--메모리-htop">CPU &amp; 메모리: htop</h2>

<p><code class="language-plaintext highlighter-rouge">top</code>보다 훨씬 직관적인 대화형 프로세스 모니터입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> htop
htop
</code></pre></div></div>

<p>주요 단축키:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">F6</code>: 정렬 기준 변경 (CPU%, MEM% 등)</li>
  <li><code class="language-plaintext highlighter-rouge">F9</code>: 프로세스 종료 (kill)</li>
  <li><code class="language-plaintext highlighter-rouge">F4</code>: 프로세스 필터링</li>
  <li><code class="language-plaintext highlighter-rouge">t</code>: 트리 보기</li>
</ul>

<p>한 줄 CPU/메모리 요약:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># CPU 코어별 사용률</span>
mpstat <span class="nt">-P</span> ALL 1

<span class="c"># 메모리 상태 (MB 단위)</span>
free <span class="nt">-m</span>

<span class="c"># 상위 메모리 사용 프로세스</span>
ps aux <span class="nt">--sort</span><span class="o">=</span>-%mem | <span class="nb">head</span> <span class="nt">-10</span>

<span class="c"># 상위 CPU 사용 프로세스</span>
ps aux <span class="nt">--sort</span><span class="o">=</span>-%cpu | <span class="nb">head</span> <span class="nt">-10</span>
</code></pre></div></div>

<h2 id="디스크-df-du-iostat">디스크: df, du, iostat</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 디스크 사용량 (사람이 읽기 쉬운 형태)</span>
<span class="nb">df</span> <span class="nt">-h</span>

<span class="c"># 특정 디렉토리 크기</span>
<span class="nb">du</span> <span class="nt">-sh</span> /var/log/<span class="k">*</span>

<span class="c"># 큰 파일 찾기 (상위 10개)</span>
<span class="nb">du</span> <span class="nt">-ah</span> / 2&gt;/dev/null | <span class="nb">sort</span> <span class="nt">-rh</span> | <span class="nb">head</span> <span class="nt">-10</span>

<span class="c"># 디스크 I/O 실시간 모니터링</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> sysstat
iostat <span class="nt">-x</span> 1
</code></pre></div></div>

<p>iostat 결과에서 <code class="language-plaintext highlighter-rouge">%util</code>이 80% 이상이면 디스크 I/O 병목을 의심합니다.</p>

<h2 id="네트워크-ss-iftop-nethogs">네트워크: ss, iftop, nethogs</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 열린 포트 및 연결 상태 확인 (netstat 대체)</span>
ss <span class="nt">-tulnp</span>

<span class="c"># 특정 포트 확인</span>
ss <span class="nt">-tulnp</span> | <span class="nb">grep</span> :80

<span class="c"># 실시간 네트워크 대역폭 모니터링 (인터페이스별)</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> iftop
<span class="nb">sudo </span>iftop <span class="nt">-i</span> eth0

<span class="c"># 프로세스별 네트워크 사용량</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> nethogs
<span class="nb">sudo </span>nethogs eth0
</code></pre></div></div>

<h2 id="로그-journalctl-tail">로그: journalctl, tail</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 시스템 로그 실시간 확인</span>
<span class="nb">sudo </span>journalctl <span class="nt">-f</span>

<span class="c"># 특정 서비스 로그</span>
<span class="nb">sudo </span>journalctl <span class="nt">-u</span> nginx <span class="nt">-f</span>

<span class="c"># 마지막 부팅 이후 에러만</span>
<span class="nb">sudo </span>journalctl <span class="nt">-b</span> <span class="nt">-p</span> err

<span class="c"># 특정 시간대 로그</span>
<span class="nb">sudo </span>journalctl <span class="nt">--since</span> <span class="s2">"2024-01-01 00:00"</span> <span class="nt">--until</span> <span class="s2">"2024-01-01 23:59"</span>

<span class="c"># Nginx 접속 로그 실시간</span>
<span class="nb">sudo tail</span> <span class="nt">-f</span> /var/log/nginx/access.log

<span class="c"># 특정 IP 접속만 필터</span>
<span class="nb">sudo tail</span> <span class="nt">-f</span> /var/log/nginx/access.log | <span class="nb">grep</span> <span class="s2">"1.2.3.4"</span>
</code></pre></div></div>

<h2 id="종합-모니터링-glances">종합 모니터링: glances</h2>

<p>하나의 화면에서 CPU, 메모리, 디스크, 네트워크를 모두 볼 수 있습니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> glances
glances
</code></pre></div></div>

<p>웹 브라우저에서 접근하는 웹 서버 모드:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>glances <span class="nt">-w</span>
<span class="c"># http://서버IP:61208 접속</span>
</code></pre></div></div>

<h2 id="빠른-진단-원라이너">빠른 진단 원라이너</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 서버 기본 정보 한 번에</span>
<span class="nb">echo</span> <span class="s2">"=== CPU ==="</span> <span class="o">&amp;&amp;</span> lscpu | <span class="nb">grep</span> <span class="s2">"Model name"</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">echo</span> <span class="s2">"=== Memory ==="</span> <span class="o">&amp;&amp;</span> free <span class="nt">-h</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">echo</span> <span class="s2">"=== Disk ==="</span> <span class="o">&amp;&amp;</span> <span class="nb">df</span> <span class="nt">-h</span> / <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">echo</span> <span class="s2">"=== Load ==="</span> <span class="o">&amp;&amp;</span> <span class="nb">uptime</span>

<span class="c"># 연결 수 많은 IP 상위 10개</span>
ss <span class="nt">-tn</span> | <span class="nb">awk</span> <span class="s1">'NR&gt;1{print $5}'</span> | <span class="nb">cut</span> <span class="nt">-d</span>: <span class="nt">-f1</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-rn</span> | <span class="nb">head</span> <span class="nt">-10</span>

<span class="c"># 현재 TIME_WAIT 연결 수</span>
ss <span class="nt">-tan</span> | <span class="nb">grep </span>TIME-WAIT | <span class="nb">wc</span> <span class="nt">-l</span>
</code></pre></div></div>

<p>이 도구들을 익혀두면 장애 상황에서도 침착하게 원인을 찾을 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><summary type="html"><![CDATA[htop, netstat, iostat, iftop 등 리눅스 서버 상태를 실시간으로 모니터링하는 핵심 도구들의 사용법을 정리합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">MySQL 보안 강화: 설치 후 반드시 해야 할 설정</title><link href="https://tcp-80.net/blog/2022/08/14/mysql-security/" rel="alternate" type="text/html" title="MySQL 보안 강화: 설치 후 반드시 해야 할 설정" /><published>2022-08-14T00:00:00+09:00</published><updated>2022-08-14T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2022/08/14/mysql-security</id><content type="html" xml:base="https://tcp-80.net/blog/2022/08/14/mysql-security/"><![CDATA[<p>MySQL은 웹 서비스에서 가장 많이 사용되는 데이터베이스입니다. 기본 설치 상태로 운영하면 여러 보안 위험에 노출될 수 있습니다. 이 글에서는 운영 서버에 적용해야 할 MySQL 보안 설정을 정리합니다.</p>

<h2 id="1-보안-초기화-스크립트-실행">1. 보안 초기화 스크립트 실행</h2>

<p>MySQL 설치 후 가장 먼저 실행해야 할 명령입니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mysql_secure_installation
</code></pre></div></div>

<p>이 스크립트는 다음을 설정합니다:</p>
<ul>
  <li>root 비밀번호 설정</li>
  <li>익명 사용자 제거</li>
  <li>원격 root 로그인 비활성화</li>
  <li>test 데이터베이스 제거</li>
  <li>권한 테이블 갱신</li>
</ul>

<h2 id="2-root-계정-원격-접속-차단">2. root 계정 원격 접속 차단</h2>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- MySQL 접속</span>
<span class="n">sudo</span> <span class="n">mysql</span> <span class="o">-</span><span class="n">u</span> <span class="n">root</span> <span class="o">-</span><span class="n">p</span>

<span class="c1">-- root 계정의 호스트 확인</span>
<span class="k">SELECT</span> <span class="k">user</span><span class="p">,</span> <span class="k">host</span> <span class="k">FROM</span> <span class="n">mysql</span><span class="p">.</span><span class="k">user</span> <span class="k">WHERE</span> <span class="k">user</span> <span class="o">=</span> <span class="s1">'root'</span><span class="p">;</span>

<span class="c1">-- 원격 root 접속 제거 (localhost만 허용)</span>
<span class="k">DELETE</span> <span class="k">FROM</span> <span class="n">mysql</span><span class="p">.</span><span class="k">user</span> <span class="k">WHERE</span> <span class="k">user</span><span class="o">=</span><span class="s1">'root'</span> <span class="k">AND</span> <span class="k">host</span> <span class="k">NOT</span> <span class="k">IN</span> <span class="p">(</span><span class="s1">'localhost'</span><span class="p">,</span> <span class="s1">'127.0.0.1'</span><span class="p">,</span> <span class="s1">'::1'</span><span class="p">);</span>
<span class="n">FLUSH</span> <span class="k">PRIVILEGES</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="3-데이터베이스별-전용-계정-생성">3. 데이터베이스별 전용 계정 생성</h2>

<p>서비스마다 최소 권한의 전용 계정을 사용합니다:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 데이터베이스 생성</span>
<span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">myapp_db</span> <span class="nb">CHARACTER</span> <span class="k">SET</span> <span class="n">utf8mb4</span> <span class="k">COLLATE</span> <span class="n">utf8mb4_unicode_ci</span><span class="p">;</span>

<span class="c1">-- 전용 계정 생성 (로컬호스트만 허용)</span>
<span class="k">CREATE</span> <span class="k">USER</span> <span class="s1">'myapp_user'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="s1">'strong_password_here'</span><span class="p">;</span>

<span class="c1">-- 해당 DB에만 권한 부여</span>
<span class="k">GRANT</span> <span class="k">SELECT</span><span class="p">,</span> <span class="k">INSERT</span><span class="p">,</span> <span class="k">UPDATE</span><span class="p">,</span> <span class="k">DELETE</span> <span class="k">ON</span> <span class="n">myapp_db</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">'myapp_user'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
<span class="n">FLUSH</span> <span class="k">PRIVILEGES</span><span class="p">;</span>

<span class="c1">-- 권한 확인</span>
<span class="k">SHOW</span> <span class="n">GRANTS</span> <span class="k">FOR</span> <span class="s1">'myapp_user'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="4-mysql-포트-원격-노출-차단">4. MySQL 포트 원격 노출 차단</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/mysql/mysql.conf.d/mysqld.cnf</code> 파일을 편집합니다:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[mysqld]</span><span class="w">
</span><span class="c"># 로컬호스트에서만 수신
</span><span class="py">bind-address</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">127.0.0.1</span>
</code></pre></div></div>

<p>웹 서버와 DB가 같은 서버에 있다면 원격 접속 자체를 차단하는 것이 가장 안전합니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl restart mysql
</code></pre></div></div>

<h2 id="5-비밀번호-정책-강화">5. 비밀번호 정책 강화</h2>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- 현재 비밀번호 정책 확인</span>
<span class="k">SHOW</span> <span class="n">VARIABLES</span> <span class="k">LIKE</span> <span class="s1">'validate_password%'</span><span class="p">;</span>

<span class="c1">-- 정책 설정</span>
<span class="k">SET</span> <span class="k">GLOBAL</span> <span class="n">validate_password</span><span class="p">.</span><span class="n">policy</span> <span class="o">=</span> <span class="n">MEDIUM</span><span class="p">;</span>
<span class="k">SET</span> <span class="k">GLOBAL</span> <span class="n">validate_password</span><span class="p">.</span><span class="k">length</span> <span class="o">=</span> <span class="mi">12</span><span class="p">;</span>
<span class="k">SET</span> <span class="k">GLOBAL</span> <span class="n">validate_password</span><span class="p">.</span><span class="n">mixed_case_count</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">SET</span> <span class="k">GLOBAL</span> <span class="n">validate_password</span><span class="p">.</span><span class="n">number_count</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">SET</span> <span class="k">GLOBAL</span> <span class="n">validate_password</span><span class="p">.</span><span class="n">special_char_count</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">/etc/mysql/mysql.conf.d/mysqld.cnf</code>에 영구 설정:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[mysqld]</span><span class="w">
</span><span class="py">validate_password.policy</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">MEDIUM</span>
<span class="py">validate_password.length</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">12</span>
</code></pre></div></div>

<h2 id="6-일반-쿼리-로그-비활성화">6. 일반 쿼리 로그 비활성화</h2>

<p>운영 환경에서 일반 쿼리 로그는 디스크를 빠르게 소모하며 민감한 정보(비밀번호 등)가 기록될 수 있습니다:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[mysqld]</span><span class="w">
</span><span class="c"># 일반 로그 비활성화 (기본값)
</span><span class="py">general_log</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">0</span>
<span class="w">
</span><span class="c"># 슬로우 쿼리 로그는 성능 분석에 유용
</span><span class="py">slow_query_log</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">1</span>
<span class="py">slow_query_log_file</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/mysql/slow.log</span>
<span class="py">long_query_time</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2</span>
</code></pre></div></div>

<h2 id="7-정기-보안-점검">7. 정기 보안 점검</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 계정 목록 확인</span>
<span class="nb">sudo </span>mysql <span class="nt">-e</span> <span class="s2">"SELECT user, host, authentication_string FROM mysql.user;"</span>

<span class="c"># 익명 계정 확인</span>
<span class="nb">sudo </span>mysql <span class="nt">-e</span> <span class="s2">"SELECT user, host FROM mysql.user WHERE user='';"</span>

<span class="c"># 불필요한 계정 제거</span>
<span class="nb">sudo </span>mysql <span class="nt">-e</span> <span class="s2">"DROP USER ''@'localhost';"</span>
</code></pre></div></div>

<p>데이터베이스 보안은 한 번 설정하고 끝나는 것이 아닙니다. 정기적으로 계정과 권한을 점검하는 습관이 중요합니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[MySQL 설치 후 기본 보안 설정, 사용자 권한 관리, 원격 접속 제한 등 운영 환경에서 반드시 적용해야 할 보안 설정을 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">UFW로 리눅스 서버 방화벽 설정하기</title><link href="https://tcp-80.net/blog/2022/06/22/ufw-firewall-setup/" rel="alternate" type="text/html" title="UFW로 리눅스 서버 방화벽 설정하기" /><published>2022-06-22T00:00:00+09:00</published><updated>2022-06-22T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2022/06/22/ufw-firewall-setup</id><content type="html" xml:base="https://tcp-80.net/blog/2022/06/22/ufw-firewall-setup/"><![CDATA[<p>UFW(Uncomplicated Firewall)는 iptables의 복잡한 문법을 단순화한 Ubuntu 기본 방화벽 도구입니다. 직관적인 명령어로 포트 제어를 할 수 있어 서버 보안의 첫 번째 단계로 적합합니다.</p>

<h2 id="기본-개념">기본 개념</h2>

<p>방화벽 정책의 기본 원칙은 <strong>화이트리스트</strong> 방식입니다. 모든 접속을 차단하고 필요한 것만 허용합니다.</p>

<h2 id="ufw-설치-및-활성화">UFW 설치 및 활성화</h2>

<p>Ubuntu에는 기본 설치되어 있습니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> ufw
</code></pre></div></div>

<p><strong>중요</strong>: 활성화 전에 반드시 SSH 포트를 허용해야 합니다. 그렇지 않으면 서버에서 잠깁니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># SSH 허용 (기본 22번)</span>
<span class="nb">sudo </span>ufw allow 22/tcp

<span class="c"># 또는 변경한 포트</span>
<span class="nb">sudo </span>ufw allow 2222/tcp

<span class="c"># UFW 활성화</span>
<span class="nb">sudo </span>ufw <span class="nb">enable</span>

<span class="c"># 상태 확인</span>
<span class="nb">sudo </span>ufw status verbose
</code></pre></div></div>

<h2 id="주요-서비스-포트-허용">주요 서비스 포트 허용</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 웹 서버</span>
<span class="nb">sudo </span>ufw allow 80/tcp     <span class="c"># HTTP</span>
<span class="nb">sudo </span>ufw allow 443/tcp    <span class="c"># HTTPS</span>

<span class="c"># 데이터베이스 (내부 접근만 필요하면 허용하지 않음)</span>
<span class="nb">sudo </span>ufw allow 3306/tcp   <span class="c"># MySQL</span>
<span class="nb">sudo </span>ufw allow 5432/tcp   <span class="c"># PostgreSQL</span>

<span class="c"># 메일 서버</span>
<span class="nb">sudo </span>ufw allow 25/tcp     <span class="c"># SMTP</span>
<span class="nb">sudo </span>ufw allow 587/tcp    <span class="c"># SMTP (제출)</span>
<span class="nb">sudo </span>ufw allow 993/tcp    <span class="c"># IMAPS</span>
</code></pre></div></div>

<h2 id="특정-ip에서만-허용">특정 IP에서만 허용</h2>

<p>관리자 IP에서만 SSH를 허용하는 것이 가장 안전합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 특정 IP에서 SSH만 허용</span>
<span class="nb">sudo </span>ufw allow from 203.0.113.1 to any port 2222

<span class="c"># 특정 IP 대역에서 허용</span>
<span class="nb">sudo </span>ufw allow from 203.0.113.0/24 to any port 2222

<span class="c"># 특정 IP의 모든 접근 차단</span>
<span class="nb">sudo </span>ufw deny from 1.2.3.4
</code></pre></div></div>

<h2 id="규칙-확인-및-삭제">규칙 확인 및 삭제</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 번호와 함께 규칙 목록 확인</span>
<span class="nb">sudo </span>ufw status numbered

<span class="c"># 번호로 규칙 삭제</span>
<span class="nb">sudo </span>ufw delete 3

<span class="c"># 규칙 내용으로 삭제</span>
<span class="nb">sudo </span>ufw delete allow 80/tcp
</code></pre></div></div>

<h2 id="기본-정책-설정">기본 정책 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 들어오는 트래픽 기본 차단</span>
<span class="nb">sudo </span>ufw default deny incoming

<span class="c"># 나가는 트래픽 기본 허용</span>
<span class="nb">sudo </span>ufw default allow outgoing
</code></pre></div></div>

<h2 id="로깅-설정">로깅 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 로깅 활성화</span>
<span class="nb">sudo </span>ufw logging on

<span class="c"># 로그 수준 설정 (low, medium, high, full)</span>
<span class="nb">sudo </span>ufw logging medium

<span class="c"># 로그 확인</span>
<span class="nb">sudo tail</span> <span class="nt">-f</span> /var/log/ufw.log
</code></pre></div></div>

<h2 id="docker-사용-시-주의사항">Docker 사용 시 주의사항</h2>

<p>Docker를 사용하면 UFW 규칙을 우회할 수 있습니다. Docker는 iptables를 직접 수정하기 때문입니다. 이 경우 <code class="language-plaintext highlighter-rouge">/etc/docker/daemon.json</code>에 다음을 추가합니다:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"iptables"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>그 후 iptables 규칙을 직접 관리하거나, Docker Compose에서 포트 바인딩을 <code class="language-plaintext highlighter-rouge">127.0.0.1:8080:80</code>처럼 루프백으로 제한하는 방식을 사용합니다.</p>

<h2 id="권장-최소-설정">권장 최소 설정</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>ufw default deny incoming
<span class="nb">sudo </span>ufw default allow outgoing
<span class="nb">sudo </span>ufw allow from <span class="o">[</span>관리자IP] to any port <span class="o">[</span>SSH포트]
<span class="nb">sudo </span>ufw allow 80/tcp
<span class="nb">sudo </span>ufw allow 443/tcp
<span class="nb">sudo </span>ufw <span class="nb">enable</span>
</code></pre></div></div>

<p>이 설정만으로도 대부분의 자동화 공격을 차단할 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[Ubuntu의 기본 방화벽 도구인 UFW(Uncomplicated Firewall)를 이용해 서버 방화벽을 설정하는 방법을 설명합니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">fail2ban으로 브루트포스 공격 자동 차단하기</title><link href="https://tcp-80.net/blog/2022/05/18/fail2ban-setup/" rel="alternate" type="text/html" title="fail2ban으로 브루트포스 공격 자동 차단하기" /><published>2022-05-18T00:00:00+09:00</published><updated>2022-05-18T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2022/05/18/fail2ban-setup</id><content type="html" xml:base="https://tcp-80.net/blog/2022/05/18/fail2ban-setup/"><![CDATA[<p>fail2ban은 로그 파일을 실시간으로 감시하여 일정 횟수 이상 로그인에 실패한 IP를 방화벽으로 자동 차단하는 도구입니다. SSH, Nginx, Apache, WordPress 등 다양한 서비스에 적용할 수 있습니다.</p>

<h2 id="설치">설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> fail2ban
<span class="nb">sudo </span>systemctl <span class="nb">enable </span>fail2ban
<span class="nb">sudo </span>systemctl start fail2ban
</code></pre></div></div>

<h2 id="기본-설정">기본 설정</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/fail2ban/jail.local</code> 파일을 생성합니다 (기본 설정 파일인 <code class="language-plaintext highlighter-rouge">jail.conf</code>는 직접 수정하지 않습니다):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo cp</span> /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
<span class="nb">sudo </span>nano /etc/fail2ban/jail.local
</code></pre></div></div>

<p>기본 설정 부분을 수정합니다:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[DEFAULT]</span><span class="w">
</span><span class="c"># 차단 지속 시간 (초, -1이면 영구 차단)
</span><span class="py">bantime</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">3600</span>
<span class="w">
</span><span class="c"># 감시 시간 범위 (초)
</span><span class="py">findtime</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">600</span>
<span class="w">
</span><span class="c"># 허용 실패 횟수
</span><span class="py">maxretry</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">5</span>
<span class="w">
</span><span class="c"># 차단에서 제외할 IP (관리자 IP)
</span><span class="py">ignoreip</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">127.0.0.1/8 ::1 203.0.113.1</span>
</code></pre></div></div>

<h2 id="ssh-차단-설정">SSH 차단 설정</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[sshd]</span><span class="w">
</span><span class="py">enabled</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">true</span>
<span class="py">port</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">2222</span>
<span class="py">filter</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">sshd</span>
<span class="py">logpath</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/auth.log</span>
<span class="py">maxretry</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">3</span>
<span class="py">bantime</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">86400</span>
</code></pre></div></div>

<h2 id="nginx-로그인-실패-차단">Nginx 로그인 실패 차단</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[nginx-http-auth]</span><span class="w">
</span><span class="py">enabled</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">true</span>
<span class="py">filter</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">nginx-http-auth</span>
<span class="py">logpath</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/nginx/error.log</span>
<span class="py">maxretry</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">5</span>
<span class="py">bantime</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">3600</span>
<span class="w">
</span><span class="nn">[nginx-limit-req]</span><span class="w">
</span><span class="py">enabled</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">true</span>
<span class="py">filter</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">nginx-limit-req</span>
<span class="py">logpath</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/nginx/error.log</span>
<span class="py">maxretry</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">10</span>
<span class="py">bantime</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">600</span>
</code></pre></div></div>

<h2 id="wordpress-로그인-보호">WordPress 로그인 보호</h2>

<p>WordPress 로그인 URL에 대한 차단 필터를 생성합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>nano /etc/fail2ban/filter.d/wordpress.conf
</code></pre></div></div>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Definition]</span><span class="w">
</span><span class="py">failregex</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">^&lt;HOST&gt; .* "POST /wp-login.php</span>
<span class="py">ignoreregex</span><span class="w"> </span><span class="p">=</span>
</code></pre></div></div>

<p>jail.local에 추가:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[wordpress]</span><span class="w">
</span><span class="py">enabled</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">true</span>
<span class="py">filter</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">wordpress</span>
<span class="py">logpath</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">/var/log/nginx/access.log</span>
<span class="py">maxretry</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">5</span>
<span class="py">bantime</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">7200</span>
<span class="py">findtime</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">300</span>
</code></pre></div></div>

<h2 id="설정-적용-및-상태-확인">설정 적용 및 상태 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl restart fail2ban

<span class="c"># 전체 jail 상태 확인</span>
<span class="nb">sudo </span>fail2ban-client status

<span class="c"># 특정 jail 상태 확인</span>
<span class="nb">sudo </span>fail2ban-client status sshd

<span class="c"># 차단된 IP 목록</span>
<span class="nb">sudo </span>fail2ban-client status sshd | <span class="nb">grep</span> <span class="s2">"Banned IP"</span>
</code></pre></div></div>

<h2 id="ip-수동-차단해제">IP 수동 차단/해제</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 수동 차단</span>
<span class="nb">sudo </span>fail2ban-client <span class="nb">set </span>sshd banip 1.2.3.4

<span class="c"># 차단 해제 (실수로 자신을 차단했을 때)</span>
<span class="nb">sudo </span>fail2ban-client <span class="nb">set </span>sshd unbanip 1.2.3.4
</code></pre></div></div>

<h2 id="차단-알림-이메일-설정">차단 알림 이메일 설정</h2>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[DEFAULT]</span><span class="w">
</span><span class="py">destemail</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">admin@example.com</span>
<span class="py">sendername</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">Fail2Ban</span>
<span class="py">action</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">%(action_mwl)s</span>
</code></pre></div></div>

<p>fail2ban은 가장 기본적이면서도 효과적인 서버 보안 도구 중 하나입니다. 반드시 설치해 두세요.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[fail2ban을 설치하고 설정하여 SSH, Nginx, WordPress 등에 대한 반복 로그인 실패를 자동으로 감지하고 IP를 차단하는 방법을 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">SSH 보안 강화: 포트 변경부터 키 인증까지</title><link href="https://tcp-80.net/blog/2022/04/05/ssh-security-hardening/" rel="alternate" type="text/html" title="SSH 보안 강화: 포트 변경부터 키 인증까지" /><published>2022-04-05T00:00:00+09:00</published><updated>2022-04-05T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2022/04/05/ssh-security-hardening</id><content type="html" xml:base="https://tcp-80.net/blog/2022/04/05/ssh-security-hardening/"><![CDATA[<p>SSH는 서버 관리의 핵심 도구이지만, 기본 설정 그대로 사용하면 자동화된 브루트포스 공격의 표적이 됩니다. 실제로 새 서버를 개설하면 수분 내에 22번 포트로 로그인 시도가 시작됩니다. 이 글에서는 SSH 보안을 단계적으로 강화하는 방법을 설명합니다.</p>

<h2 id="1-ssh-키-페어-생성">1. SSH 키 페어 생성</h2>

<p>클라이언트(로컬 PC)에서 SSH 키 쌍을 생성합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># ED25519 알고리즘 (권장)</span>
ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-C</span> <span class="s2">"your_email@example.com"</span>

<span class="c"># 또는 RSA 4096</span>
ssh-keygen <span class="nt">-t</span> rsa <span class="nt">-b</span> 4096 <span class="nt">-C</span> <span class="s2">"your_email@example.com"</span>
</code></pre></div></div>

<p>키 파일 위치: <code class="language-plaintext highlighter-rouge">~/.ssh/id_ed25519</code> (개인키), <code class="language-plaintext highlighter-rouge">~/.ssh/id_ed25519.pub</code> (공개키)</p>

<h2 id="2-공개키를-서버에-등록">2. 공개키를 서버에 등록</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-copy-id <span class="nt">-i</span> ~/.ssh/id_ed25519.pub user@server_ip
</code></pre></div></div>

<p>또는 수동으로 서버에 추가:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 서버에서 실행</span>
<span class="nb">mkdir</span> <span class="nt">-p</span> ~/.ssh
<span class="nb">chmod </span>700 ~/.ssh
<span class="nb">echo</span> <span class="s2">"공개키내용"</span> <span class="o">&gt;&gt;</span> ~/.ssh/authorized_keys
<span class="nb">chmod </span>600 ~/.ssh/authorized_keys
</code></pre></div></div>

<h2 id="3-ssh-설정-강화">3. SSH 설정 강화</h2>

<p><code class="language-plaintext highlighter-rouge">/etc/ssh/sshd_config</code> 파일을 편집합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>nano /etc/ssh/sshd_config
</code></pre></div></div>

<p>다음 항목을 수정합니다:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 포트 변경 (1024~65535 중 선택)
</span><span class="na">Port</span><span class="w"> </span><span class="na">2222</span><span class="w">

</span><span class="c"># 루트 직접 로그인 비활성화
</span><span class="na">PermitRootLogin</span><span class="w"> </span><span class="na">no</span><span class="w">

</span><span class="c"># 비밀번호 로그인 비활성화 (키 인증 설정 후)
</span><span class="na">PasswordAuthentication</span><span class="w"> </span><span class="na">no</span><span class="w">

</span><span class="c"># 빈 비밀번호 비활성화
</span><span class="na">PermitEmptyPasswords</span><span class="w"> </span><span class="na">no</span><span class="w">

</span><span class="c"># 최대 인증 시도 횟수
</span><span class="na">MaxAuthTries</span><span class="w"> </span><span class="na">3</span><span class="w">

</span><span class="c"># 접속 타임아웃 (초)
</span><span class="na">LoginGraceTime</span><span class="w"> </span><span class="na">30</span><span class="w">

</span><span class="c"># X11 포워딩 비활성화 (불필요한 경우)
</span><span class="na">X11Forwarding</span><span class="w"> </span><span class="na">no</span><span class="w">

</span><span class="c"># 특정 사용자만 접속 허용
</span><span class="na">AllowUsers</span><span class="w"> </span><span class="na">myuser</span><span class="w">
</span></code></pre></div></div>

<p>설정 적용:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl restart sshd
</code></pre></div></div>

<blockquote>
  <p><strong>주의</strong>: 설정을 저장하기 전에 현재 세션은 유지한 채로 새 터미널에서 접속 테스트를 먼저 하세요. 잘못된 설정으로 잠기면 IPMI나 콘솔 접근이 필요합니다.</p>
</blockquote>

<h2 id="4-방화벽에서-새-포트-허용">4. 방화벽에서 새 포트 허용</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>ufw allow 2222/tcp
<span class="nb">sudo </span>ufw delete allow 22/tcp
</code></pre></div></div>

<h2 id="5-접속-확인">5. 접속 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh <span class="nt">-p</span> 2222 <span class="nt">-i</span> ~/.ssh/id_ed25519 myuser@server_ip
</code></pre></div></div>

<h2 id="보안-수준-확인">보안 수준 확인</h2>

<p><code class="language-plaintext highlighter-rouge">/var/log/auth.log</code>에서 로그인 시도를 모니터링합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo tail</span> <span class="nt">-f</span> /var/log/auth.log | <span class="nb">grep </span>sshd
</code></pre></div></div>

<p>포트 변경만으로도 자동화 공격의 90% 이상을 차단할 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[기본 포트 변경, 비밀번호 로그인 비활성화, SSH 키 인증 설정으로 서버 SSH 접속을 안전하게 만드는 방법을 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Nginx에 Let’s Encrypt SSL 인증서 적용하기</title><link href="https://tcp-80.net/blog/2022/03/10/nginx-ssl-letsencrypt/" rel="alternate" type="text/html" title="Nginx에 Let’s Encrypt SSL 인증서 적용하기" /><published>2022-03-10T00:00:00+09:00</published><updated>2022-03-10T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2022/03/10/nginx-ssl-letsencrypt</id><content type="html" xml:base="https://tcp-80.net/blog/2022/03/10/nginx-ssl-letsencrypt/"><![CDATA[<p>웹사이트에 HTTPS를 적용하는 것은 이제 선택이 아닌 필수입니다. 검색엔진 순위에도 영향을 미치며, 방문자의 데이터를 안전하게 보호할 수 있습니다. Let’s Encrypt는 무료로 SSL 인증서를 발급해 주는 비영리 인증기관으로, Certbot 도구를 통해 쉽게 적용할 수 있습니다.</p>

<h2 id="사전-준비">사전 준비</h2>

<ul>
  <li>Nginx가 설치된 Ubuntu/Debian 서버</li>
  <li>도메인이 서버 IP로 DNS 연결된 상태</li>
  <li>80번, 443번 포트 오픈</li>
</ul>

<h2 id="certbot-설치">Certbot 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> certbot python3-certbot-nginx
</code></pre></div></div>

<h2 id="ssl-인증서-발급">SSL 인증서 발급</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>certbot <span class="nt">--nginx</span> <span class="nt">-d</span> example.com <span class="nt">-d</span> www.example.com
</code></pre></div></div>

<p>이메일 주소 입력과 약관 동의 후 자동으로 인증서가 발급되고 Nginx 설정이 수정됩니다.</p>

<h2 id="nginx-설정-확인">Nginx 설정 확인</h2>

<p>Certbot이 자동으로 수정한 <code class="language-plaintext highlighter-rouge">/etc/nginx/sites-available/default</code> 파일을 확인합니다:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">example.com</span> <span class="s">www.example.com</span><span class="p">;</span>

    <span class="kn">ssl_certificate</span> <span class="n">/etc/letsencrypt/live/example.com/fullchain.pem</span><span class="p">;</span>
    <span class="kn">ssl_certificate_key</span> <span class="n">/etc/letsencrypt/live/example.com/privkey.pem</span><span class="p">;</span>

    <span class="c1"># HTTPS 보안 강화 헤더</span>
    <span class="kn">add_header</span> <span class="s">Strict-Transport-Security</span> <span class="s">"max-age=31536000</span><span class="p">;</span> <span class="kn">includeSubDomains"</span> <span class="s">always</span><span class="p">;</span>
    <span class="kn">add_header</span> <span class="s">X-Frame-Options</span> <span class="s">DENY</span><span class="p">;</span>
    <span class="kn">add_header</span> <span class="s">X-Content-Type-Options</span> <span class="s">nosniff</span><span class="p">;</span>

    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
        <span class="kn">root</span> <span class="n">/var/www/html</span><span class="p">;</span>
        <span class="kn">index</span> <span class="s">index.html</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1"># HTTP → HTTPS 리다이렉트</span>
<span class="k">server</span> <span class="p">{</span>
    <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
    <span class="kn">server_name</span> <span class="s">example.com</span> <span class="s">www.example.com</span><span class="p">;</span>
    <span class="kn">return</span> <span class="mi">301</span> <span class="s">https://</span><span class="nv">$host$request_uri</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="자동-갱신-설정">자동 갱신 설정</h2>

<p>Let’s Encrypt 인증서는 90일 유효기간을 가집니다. Certbot은 자동 갱신 cron 작업을 등록합니다. 정상 동작 여부를 확인합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>certbot renew <span class="nt">--dry-run</span>
</code></pre></div></div>

<p>갱신 cron 작업 확인:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl status certbot.timer
</code></pre></div></div>

<h2 id="ssl-등급-확인">SSL 등급 확인</h2>

<p>설정 완료 후 <a href="https://www.ssllabs.com/ssltest/">SSL Labs</a>에서 도메인을 검사하면 보안 등급을 확인할 수 있습니다. A+ 등급을 목표로 하세요.</p>

<h2 id="주의사항">주의사항</h2>

<ul>
  <li>서버 IP가 변경되면 DNS 연결을 먼저 수정한 후 인증서를 재발급해야 합니다</li>
  <li>발급 한도: 동일 도메인에 주당 5회 제한이 있습니다</li>
  <li>와일드카드 인증서(<code class="language-plaintext highlighter-rouge">*.example.com</code>)는 DNS 방식으로 별도 발급합니다</li>
</ul>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="보안" /><summary type="html"><![CDATA[Certbot을 이용해 Nginx 웹서버에 무료 SSL 인증서를 발급하고 HTTPS를 적용하는 방법을 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-dedicated.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-dedicated.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Linux 자동 백업 스크립트 작성하기</title><link href="https://tcp-80.net/blog/2021/12/23/linux-auto-backup/" rel="alternate" type="text/html" title="Linux 자동 백업 스크립트 작성하기" /><published>2021-12-23T00:00:00+09:00</published><updated>2021-12-23T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2021/12/23/linux-auto-backup</id><content type="html" xml:base="https://tcp-80.net/blog/2021/12/23/linux-auto-backup/"><![CDATA[<p>서버 운영에서 백업은 가장 중요한 요소 중 하나입니다. 아무리 안정적인 서버라도 하드웨어 장애, 실수로 인한 파일 삭제, 랜섬웨어 감염 등 예상치 못한 상황이 발생할 수 있습니다. 이번 글에서는 cron과 rsync를 활용하여 자동 백업 스크립트를 구성하는 방법을 알아보겠습니다.</p>

<h2 id="백업-전략">백업 전략</h2>

<p>백업을 구성하기 전에 먼저 전략을 세워야 합니다:</p>

<ul>
  <li><strong>무엇을 백업할 것인가</strong>: 웹 파일, 데이터베이스, 설정 파일</li>
  <li><strong>얼마나 자주 백업할 것인가</strong>: 일별, 주별</li>
  <li><strong>얼마나 오래 보관할 것인가</strong>: 7일, 30일</li>
</ul>

<h2 id="rsync를-이용한-파일-백업">rsync를 이용한 파일 백업</h2>

<p>rsync는 Linux에서 가장 많이 사용되는 파일 동기화 도구입니다. 변경된 파일만 전송하므로 효율적입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>

<span class="c"># 백업 설정</span>
<span class="nv">BACKUP_SRC</span><span class="o">=</span><span class="s2">"/var/www/html"</span>
<span class="nv">BACKUP_DEST</span><span class="o">=</span><span class="s2">"/backup/web"</span>
<span class="nv">DATE</span><span class="o">=</span><span class="si">$(</span><span class="nb">date</span> +%Y%m%d<span class="si">)</span>
<span class="nv">BACKUP_DIR</span><span class="o">=</span><span class="s2">"</span><span class="nv">$BACKUP_DEST</span><span class="s2">/</span><span class="nv">$DATE</span><span class="s2">"</span>

<span class="c"># 백업 디렉토리 생성</span>
<span class="nb">mkdir</span> <span class="nt">-p</span> <span class="s2">"</span><span class="nv">$BACKUP_DIR</span><span class="s2">"</span>

<span class="c"># rsync로 백업 실행</span>
rsync <span class="nt">-avz</span> <span class="nt">--delete</span> <span class="se">\</span>
  <span class="s2">"</span><span class="nv">$BACKUP_SRC</span><span class="s2">/"</span> <span class="se">\</span>
  <span class="s2">"</span><span class="nv">$BACKUP_DIR</span><span class="s2">/"</span>

<span class="nb">echo</span> <span class="s2">"백업 완료: </span><span class="nv">$BACKUP_DIR</span><span class="s2">"</span>
</code></pre></div></div>

<h2 id="mysql-데이터베이스-백업">MySQL 데이터베이스 백업</h2>

<p>웹 서비스에서 데이터베이스 백업은 필수입니다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>

<span class="nv">DB_USER</span><span class="o">=</span><span class="s2">"root"</span>
<span class="nv">DB_PASS</span><span class="o">=</span><span class="s2">"your_password"</span>
<span class="nv">DB_NAME</span><span class="o">=</span><span class="s2">"your_database"</span>
<span class="nv">BACKUP_DIR</span><span class="o">=</span><span class="s2">"/backup/db"</span>
<span class="nv">DATE</span><span class="o">=</span><span class="si">$(</span><span class="nb">date</span> +%Y%m%d_%H%M%S<span class="si">)</span>

<span class="nb">mkdir</span> <span class="nt">-p</span> <span class="s2">"</span><span class="nv">$BACKUP_DIR</span><span class="s2">"</span>

mysqldump <span class="nt">-u</span><span class="s2">"</span><span class="nv">$DB_USER</span><span class="s2">"</span> <span class="nt">-p</span><span class="s2">"</span><span class="nv">$DB_PASS</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$DB_NAME</span><span class="s2">"</span> <span class="se">\</span>
  | <span class="nb">gzip</span> <span class="o">&gt;</span> <span class="s2">"</span><span class="nv">$BACKUP_DIR</span><span class="s2">/</span><span class="k">${</span><span class="nv">DB_NAME</span><span class="k">}</span><span class="s2">_</span><span class="k">${</span><span class="nv">DATE</span><span class="k">}</span><span class="s2">.sql.gz"</span>

<span class="nb">echo</span> <span class="s2">"DB 백업 완료: </span><span class="k">${</span><span class="nv">DB_NAME</span><span class="k">}</span><span class="s2">_</span><span class="k">${</span><span class="nv">DATE</span><span class="k">}</span><span class="s2">.sql.gz"</span>
</code></pre></div></div>

<h2 id="cron으로-자동화하기">cron으로 자동화하기</h2>

<p><code class="language-plaintext highlighter-rouge">crontab -e</code> 명령으로 cron 작업을 등록합니다:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># 매일 새벽 3시에 웹 파일 백업
0 3 * * * /home/backup/web_backup.sh &gt;&gt; /var/log/backup.log 2&gt;&amp;1

# 매일 새벽 3시 30분에 DB 백업
30 3 * * * /home/backup/db_backup.sh &gt;&gt; /var/log/backup.log 2&gt;&amp;1
</code></pre></div></div>

<h2 id="오래된-백업-자동-삭제">오래된 백업 자동 삭제</h2>

<p>디스크 용량 관리를 위해 오래된 백업을 자동으로 삭제합니다:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 30일 이상 된 백업 파일 삭제</span>
find /backup <span class="nt">-mtime</span> +30 <span class="nt">-delete</span>
</code></pre></div></div>

<h2 id="tcp-80net의-내부망-백업">TCP-80.NET의 내부망 백업</h2>

<p>TCP-80.NET에서는 모든 서버에 내부 네트워크를 통한 무료 백업 서비스를 제공합니다. 외부 인터넷을 거치지 않고 빠른 내부망으로 백업이 이루어지므로 서버 성능에 영향을 최소화합니다.</p>

<p>개인적인 백업 솔루션과 병행하여 사용하면 더욱 안전하게 데이터를 보호할 수 있습니다.</p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="Linux" /><category term="백업" /><summary type="html"><![CDATA[cron과 rsync를 활용한 Linux 서버 자동 백업 스크립트를 작성하는 방법을 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">가상 데스크톱 비밀번호 변경 방법</title><link href="https://tcp-80.net/blog/2021/08/01/change-virtual-desktop-password/" rel="alternate" type="text/html" title="가상 데스크톱 비밀번호 변경 방법" /><published>2021-08-01T00:00:00+09:00</published><updated>2021-08-01T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2021/08/01/change-virtual-desktop-password</id><content type="html" xml:base="https://tcp-80.net/blog/2021/08/01/change-virtual-desktop-password/"><![CDATA[<p>가상 데스크톱 비밀번호를 정기적으로 변경하는 것은 보안을 유지하는 중요한 습관입니다. 이 글에서는 Windows 원격 데스크톱 환경에서 비밀번호를 변경하는 방법을 안내합니다.</p>

<h2 id="windows에서-비밀번호-변경하기">Windows에서 비밀번호 변경하기</h2>

<h3 id="방법-1-단축키-사용-권장">방법 1: 단축키 사용 (권장)</h3>

<p>원격 데스크톱(RDP)으로 접속한 상태에서:</p>

<ol>
  <li><strong>Ctrl + Alt + End</strong> 키를 누릅니다
    <ul>
      <li>(일반 Windows에서는 Ctrl + Alt + Delete이지만, 원격 데스크톱에서는 End 키를 사용합니다)</li>
    </ul>
  </li>
  <li>나타나는 화면에서 <strong>“암호 변경”</strong> 클릭</li>
  <li>현재 암호와 새 암호를 입력합니다</li>
  <li>확인 버튼 클릭</li>
</ol>

<h3 id="방법-2-제어판-사용">방법 2: 제어판 사용</h3>

<ol>
  <li>시작 메뉴 → <strong>제어판</strong> 클릭</li>
  <li><strong>사용자 계정</strong> 선택</li>
  <li><strong>암호 변경</strong> 클릭</li>
  <li>현재 암호와 새 암호 입력 후 확인</li>
</ol>

<h3 id="방법-3-powershell-사용">방법 3: PowerShell 사용</h3>

<p>관리자 권한의 PowerShell에서 다음 명령을 실행합니다:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">net</span><span class="w"> </span><span class="nx">user</span><span class="w"> </span><span class="err">사용자명</span><span class="w"> </span><span class="err">새비밀번호</span><span class="w">
</span></code></pre></div></div>

<p>예시:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">net</span><span class="w"> </span><span class="nx">user</span><span class="w"> </span><span class="nx">Administrator</span><span class="w"> </span><span class="nx">MyNewPassword123</span><span class="o">!</span><span class="w">
</span></code></pre></div></div>

<h2 id="안전한-비밀번호-만들기">안전한 비밀번호 만들기</h2>

<p>좋은 비밀번호의 조건:</p>

<ul>
  <li><strong>길이</strong>: 최소 12자 이상</li>
  <li><strong>복잡성</strong>: 대문자, 소문자, 숫자, 특수문자 조합</li>
  <li><strong>고유성</strong>: 다른 사이트와 동일한 비밀번호 사용 금지</li>
  <li><strong>예측 불가</strong>: 생일, 이름 등 개인정보 사용 금지</li>
</ul>

<p><strong>좋은 예시</strong>: <code class="language-plaintext highlighter-rouge">Tcp80!Server#2024</code></p>

<p><strong>나쁜 예시</strong>: <code class="language-plaintext highlighter-rouge">password123</code>, <code class="language-plaintext highlighter-rouge">admin</code>, <code class="language-plaintext highlighter-rouge">1234</code></p>

<h2 id="비밀번호-분실-시">비밀번호 분실 시</h2>

<p>비밀번호를 분실하신 경우 텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요. 본인 확인 후 비밀번호를 초기화해 드립니다.</p>

<h2 id="rdp-접속-보안-팁">RDP 접속 보안 팁</h2>

<ul>
  <li>RDP 기본 포트(3389) 변경 권장</li>
  <li>접속 IP를 특정 IP로 제한</li>
  <li>2단계 인증 설정 (가능한 경우)</li>
  <li>정기적인 비밀번호 변경 (3개월마다 권장)</li>
</ul>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="가상데스크톱" /><category term="가이드" /><summary type="html"><![CDATA[TCP-80.NET 가상 데스크톱의 Windows 로그인 비밀번호를 변경하는 방법을 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">가상 서버와 전용 서버의 차이점</title><link href="https://tcp-80.net/blog/2021/08/01/virtual-vs-dedicated/" rel="alternate" type="text/html" title="가상 서버와 전용 서버의 차이점" /><published>2021-08-01T00:00:00+09:00</published><updated>2021-08-01T00:00:00+09:00</updated><id>https://tcp-80.net/blog/2021/08/01/virtual-vs-dedicated</id><content type="html" xml:base="https://tcp-80.net/blog/2021/08/01/virtual-vs-dedicated/"><![CDATA[<p>서버 호스팅을 처음 시작하는 분들이 가장 많이 혼동하는 부분이 바로 가상 서버(VPS)와 전용 서버의 차이입니다. 이번 글에서는 두 서버의 구조적 차이와 각각 어떤 상황에 적합한지 설명하겠습니다.</p>

<h2 id="가상-서버-vps란">가상 서버 (VPS)란?</h2>

<p>VPS(Virtual Private Server)는 하나의 물리 서버를 가상화 기술로 여러 개의 독립된 환경으로 분할한 것입니다. 각 VPS는 독립된 OS, CPU, RAM, 스토리지를 갖지만 실제 하드웨어는 다른 VPS들과 공유합니다.</p>

<p><strong>장점:</strong></p>
<ul>
  <li>전용 서버보다 저렴한 비용</li>
  <li>빠른 서버 개설 (즉시 ~ 수 시간)</li>
  <li>필요에 따라 유연한 리소스 조정</li>
  <li>물리 서버 문제 시 다른 노드로 이동 가능</li>
</ul>

<p><strong>단점:</strong></p>
<ul>
  <li>같은 물리 서버의 다른 VPS가 리소스를 과다 사용할 경우 영향받을 수 있음</li>
  <li>물리 서버의 실제 성능보다 낮을 수 있음</li>
</ul>

<h2 id="전용-서버란">전용 서버란?</h2>

<p>전용 서버는 물리 서버 전체를 혼자 사용하는 방식입니다. CPU, RAM, 스토리지 모두 다른 사용자와 공유하지 않습니다.</p>

<p><strong>장점:</strong></p>
<ul>
  <li>물리 서버의 전체 리소스를 독점 사용</li>
  <li>예측 가능하고 일정한 성능</li>
  <li>보안 격리가 완전함</li>
  <li>하드웨어 커스터마이징 가능</li>
</ul>

<p><strong>단점:</strong></p>
<ul>
  <li>VPS보다 높은 비용</li>
  <li>서버 개설에 다소 시간이 소요될 수 있음</li>
</ul>

<h2 id="어떤-서버를-선택해야-할까">어떤 서버를 선택해야 할까?</h2>

<table>
  <thead>
    <tr>
      <th>상황</th>
      <th>추천</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>개인 블로그, 소규모 쇼핑몰</td>
      <td>가상 서버 (VPS)</td>
    </tr>
    <tr>
      <td>중소규모 웹 서비스</td>
      <td>가상 서버 또는 전용 서버</td>
    </tr>
    <tr>
      <td>대규모 트래픽 서비스</td>
      <td>전용 서버</td>
    </tr>
    <tr>
      <td>게임 서버</td>
      <td>전용 서버</td>
    </tr>
    <tr>
      <td>데이터베이스 서버</td>
      <td>전용 서버</td>
    </tr>
    <tr>
      <td>테스트 / 개발 환경</td>
      <td>가상 서버 (VPS)</td>
    </tr>
  </tbody>
</table>

<h2 id="tcp-80net의-서버-선택-가이드">TCP-80.NET의 서버 선택 가이드</h2>

<p>저희에게 문의하시면 현재 운영하시는 서비스 규모와 트래픽에 맞는 최적의 서버를 추천해 드립니다.</p>

<p>월 방문자 10만 명 이하의 웹 서비스라면 2~3 vCore VPS로 충분히 운영할 수 있습니다. 그 이상이라면 전용 서버 Eco 플랜부터 시작하는 것을 권장합니다.</p>

<p>텔레그램 <a href="https://t.me/tcp80net">@tcp80net</a>으로 문의해 주세요.</p>

<p>→ <a href="/virtual-server/">일본 가상 서버(VPS) 요금제 확인하기</a>
→ <a href="/dedicated-server/">일본 전용 서버 요금제 확인하기</a></p>]]></content><author><name>TCP-80.NET</name><email>support@tcp-80.net</email></author><category term="서버" /><category term="가이드" /><summary type="html"><![CDATA[가상 서버(VPS)와 전용 서버는 어떻게 다를까요? 각각의 장단점과 어떤 상황에 무엇을 선택해야 하는지 알아봅니다.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://tcp-80.net/assets/img/og-vps.png" /><media:content medium="image" url="https://tcp-80.net/assets/img/og-vps.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>