<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Portainer on Chanyeol Dev</title>
    <link>https://chanyeols.com/tags/portainer/</link>
    <description>Recent content in Portainer on Chanyeol Dev</description>
    <generator>Hugo</generator>
    <language>ko-kr</language>
    <lastBuildDate>Sat, 28 Mar 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://chanyeols.com/tags/portainer/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>노트북으로 홈서버 구축하기 - Portainer CE로 Docker GUI 관리하기 (6편)</title>
      <link>https://chanyeols.com/posts/part-06-portainer/</link>
      <pubDate>Sat, 28 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://chanyeols.com/posts/part-06-portainer/</guid>
      <description>컨테이너가 늘어나면서 CLI 관리가 번거로워졌다. Portainer CE를 Docker Compose로 설치해서 웹 UI로 컨테이너를 관리하는 환경을 구성합니다.</description>
      <content:encoded><![CDATA[<h2 id="왜-portainer인가">왜 Portainer인가</h2>
<p>Filebrowser, Immich, Vaultwarden, Prometheus, Grafana&hellip; 서비스가 하나씩 늘어나다 보니 컨테이너가 어느새 8개가 넘었다. 매번 SSH 접속해서 <code>docker ps</code>, <code>docker logs</code>, <code>docker compose restart</code> 치는 게 점점 번거로워졌다.</p>
<p>Portainer CE는 Docker를 웹 UI로 관리할 수 있는 오픈소스 도구다. 컨테이너 시작/중지/재시작, 실시간 로그 확인, 볼륨/네트워크 관리까지 브라우저에서 다 된다. CE(Community Edition)는 무료다.</p>
<hr>
<h2 id="설치">설치</h2>
<h3 id="1-디렉토리-생성">1. 디렉토리 생성</h3>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir -p ~/portainer <span style="color:#ff7b72;font-weight:bold">&amp;&amp;</span> cd ~/portainer
</span></span></code></pre></div><h3 id="2-docker-composeyml-작성">2. docker-compose.yml 작성</h3>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#7ee787">services</span>:<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#7ee787">portainer</span>:<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">    </span><span style="color:#7ee787">image</span>:<span style="color:#6e7681"> </span><span style="color:#a5d6ff">portainer/portainer-ce:latest</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">    </span><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"> </span><span style="color:#a5d6ff">portainer</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">    </span><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"> </span><span style="color:#a5d6ff">always</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">    </span><span style="color:#7ee787">ports</span>:<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">      </span>- <span style="color:#a5d6ff">&#34;19000:9000&#34;</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">      </span>- <span style="color:#a5d6ff">&#34;18000:8000&#34;</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">    </span><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">      </span>- <span style="color:#a5d6ff">/var/run/docker.sock:/var/run/docker.sock</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">      </span>- <span style="color:#a5d6ff">portainer_data:/data</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#7ee787">portainer_data</span>:<span style="color:#6e7681">
</span></span></span></code></pre></div><p>핵심은 <code>/var/run/docker.sock</code>을 마운트하는 것이다. 이를 통해 Portainer가 호스트의 Docker 데몬에 직접 접근할 수 있다.</p>
<p>포트는 기존 서비스들과 충돌하지 않도록 10000번대로 설정했다.</p>
<table>
  <thead>
      <tr>
          <th>포트</th>
          <th>용도</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>19000</td>
          <td>Portainer 웹 UI</td>
      </tr>
      <tr>
          <td>18000</td>
          <td>Edge Agent 터널 (원격 환경 연결용)</td>
      </tr>
  </tbody>
</table>
<h3 id="3-실행">3. 실행</h3>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose up -d
</span></span></code></pre></div><h3 id="4-초기-설정">4. 초기 설정</h3>
<p>브라우저에서 <code>http://100.109.108.36:19000</code> 접속 후 admin 계정을 생성한다.</p>
<blockquote>
<p>⚠️ 컨테이너 실행 후 <strong>5분 이내</strong>에 초기 계정을 만들어야 한다. 시간이 지나면 보안상 접근이 차단되므로 <code>docker compose restart portainer</code>로 재시작해야 한다.</p>
</blockquote>
<hr>
<h2 id="결과">결과</h2>
<p><img alt="Portainer 대시보드 - 컨테이너 목록" loading="lazy" src="/images/homeserver-06-portainer.png"></p>
<p>설치 후 현재 홈서버에서 실행 중인 모든 컨테이너를 한눈에 볼 수 있다.</p>
<table>
  <thead>
      <tr>
          <th>컨테이너</th>
          <th>상태</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>filebrowser</td>
          <td>healthy ✅</td>
      </tr>
      <tr>
          <td>grafana</td>
          <td>running ✅</td>
      </tr>
      <tr>
          <td>immich_machine_learning</td>
          <td>healthy ✅</td>
      </tr>
      <tr>
          <td>immich_postgres</td>
          <td>healthy ✅</td>
      </tr>
      <tr>
          <td>immich_redis</td>
          <td>healthy ✅</td>
      </tr>
      <tr>
          <td>immich_server</td>
          <td>healthy ✅</td>
      </tr>
      <tr>
          <td>portainer</td>
          <td>running ✅</td>
      </tr>
      <tr>
          <td>prometheus</td>
          <td>running ✅</td>
      </tr>
  </tbody>
</table>
<p>컨테이너별로 로그 확인, 시작/중지, 환경변수, 마운트 볼륨 정보까지 GUI에서 바로 볼 수 있다.</p>
<hr>
<h2 id="접근-방식">접근 방식</h2>
<p>Portainer는 Docker 소켓에 직접 접근하는 민감한 도구라 외부에 열지 않고 Tailscale VPN 안에서만 접근한다.</p>
<pre tabindex="0"><code>Portainer UI → http://100.109.108.36:19000 (Tailscale VPN으로만 접근)
</code></pre><p>Nginx 리버스 프록시로 외부에 노출하지 않는다. 누군가 Portainer에 접근하면 서버의 모든 컨테이너를 제어할 수 있기 때문이다.</p>
<hr>
<h2 id="정리">정리</h2>
<ul>
<li>Docker Compose 파일 하나로 설치가 끝난다</li>
<li><code>/var/run/docker.sock</code> 마운트가 핵심</li>
<li>컨테이너 실행 후 5분 안에 초기 계정 생성할 것</li>
<li>보안상 VPN 안에서만 접근하고 외부에는 절대 열지 말 것</li>
</ul>
<p>다음 편에서는 Prometheus + Grafana + Node Exporter로 홈서버와 OCI 서버를 동시에 모니터링하는 환경을 구성한다.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
