<?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>보안 on Chanyeol Dev</title>
    <link>https://chanyeols.com/tags/%EB%B3%B4%EC%95%88/</link>
    <description>Recent content in 보안 on Chanyeol Dev</description>
    <generator>Hugo</generator>
    <language>ko-kr</language>
    <lastBuildDate>Fri, 27 Mar 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://chanyeols.com/tags/%EB%B3%B4%EC%95%88/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>노트북으로 홈서버 구축하기 - Vaultwarden으로 비밀번호 자체 호스팅하기 (5편)</title>
      <link>https://chanyeols.com/posts/part-05-vaultwarden/</link>
      <pubDate>Fri, 27 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://chanyeols.com/posts/part-05-vaultwarden/</guid>
      <description>Bitwarden 호환 서버인 Vaultwarden을 Docker로 설치하고, 구글 비밀번호를 이전한 후 브라우저 확장 프로그램과 연동하는 과정을 정리합니다.</description>
      <content:encoded><![CDATA[<h2 id="vaultwarden이란">Vaultwarden이란?</h2>
<p>Bitwarden의 오픈소스 서버 구현체다. 공식 Bitwarden 앱, 브라우저 확장 프로그램과 100% 호환되면서, 내 서버에서 직접 운영할 수 있다.</p>
<p>구글 비밀번호 관리자를 쭉 써왔는데, 비밀번호를 외부 서비스에 맡기는 게 항상 마음에 걸렸다. 홈서버가 생겼으니 직접 호스팅하기로 했다.</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 ~/vaultwarden <span style="color:#ff7b72;font-weight:bold">&amp;&amp;</span> cd ~/vaultwarden
</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">vaultwarden</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">vaultwarden/server: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">vaultwarden</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;11000:80&#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">vaultwarden_data:/data</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">    </span><span style="color:#7ee787">environment</span>:<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">      </span>- <span style="color:#a5d6ff">DOMAIN=https://vault.yourdomain.com</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">      </span>- <span style="color:#a5d6ff">SIGNUPS_ALLOWED=true</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">vaultwarden_data</span>:<span style="color:#6e7681">
</span></span></span></code></pre></div><p><code>DOMAIN</code>에 실제 접근할 도메인을 설정해야 한다. Vaultwarden이 HTTPS 환경에서 동작한다고 인식해야 브라우저 확장 연동이 정상적으로 된다.</p>
<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><hr>
<h2 id="oci-nginx-리버스-프록시-설정">OCI Nginx 리버스 프록시 설정</h2>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo vi /etc/nginx/sites-available/vault.yourdomain.com
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#ff7b72">server</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">listen</span> <span style="color:#a5d6ff">80</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">server_name</span> <span style="color:#a5d6ff">vault.yourdomain.com</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> <span style="color:#a5d6ff">301</span> <span style="color:#a5d6ff">https://</span><span style="color:#79c0ff">$host$request_uri</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">server</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">listen</span> <span style="color:#a5d6ff">443</span> <span style="color:#a5d6ff">ssl</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">server_name</span> <span style="color:#a5d6ff">vault.yourdomain.com</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">ssl_certificate</span>     <span style="color:#a5d6ff">/ssl/live/yourdomain.com/fullchain.pem</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">ssl_certificate_key</span> <span style="color:#a5d6ff">/ssl/live/yourdomain.com/privkey.pem</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">ssl_protocols</span> <span style="color:#a5d6ff">TLSv1.2</span> <span style="color:#a5d6ff">TLSv1.3</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">ssl_prefer_server_ciphers</span> <span style="color:#79c0ff;font-weight:bold">on</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">location</span> <span style="color:#a5d6ff">/</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#ff7b72">proxy_pass</span> <span style="color:#a5d6ff">http://100.109.108.36:11000</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#ff7b72">proxy_set_header</span> <span style="color:#a5d6ff">Host</span> <span style="color:#79c0ff">$host</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#ff7b72">proxy_set_header</span> <span style="color:#a5d6ff">X-Real-IP</span> <span style="color:#79c0ff">$remote_addr</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#ff7b72">proxy_set_header</span> <span style="color:#a5d6ff">X-Forwarded-For</span> <span style="color:#79c0ff">$proxy_add_x_forwarded_for</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#ff7b72">proxy_set_header</span> <span style="color:#a5d6ff">X-Forwarded-Proto</span> <span style="color:#79c0ff">$scheme</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo ln -s /etc/nginx/sites-available/vault.yourdomain.com /etc/nginx/sites-enabled/
</span></span><span style="display:flex;"><span>sudo nginx -t <span style="color:#ff7b72;font-weight:bold">&amp;&amp;</span> sudo systemctl reload nginx
</span></span></code></pre></div><hr>
<h2 id="초기-계정-생성">초기 계정 생성</h2>
<p><code>https://vault.yourdomain.com</code> 접속 후 계정을 생성한다.</p>
<p><img alt="Vaultwarden 초기 화면" loading="lazy" src="/images/homeserver-05-vaultwarden.png"></p>
<blockquote>
<p>⚠️ <strong>마스터 비밀번호는 절대 잊으면 안 된다.</strong> 서버 관리자도 복구가 불가능하고, 분실하면 저장된 비밀번호 전부 날아간다.</p>
</blockquote>
<p>계정 생성 완료 후 신규 가입을 막는다. 혼자 쓰는 서버라 추가 가입이 필요 없다.</p>
<p><code>docker-compose.yml</code> 수정:</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#7ee787">environment</span>:<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span>- <span style="color:#a5d6ff">SIGNUPS_ALLOWED=false</span><span style="color:#6e7681">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose up -d
</span></span></code></pre></div><hr>
<h2 id="구글-비밀번호-가져오기">구글 비밀번호 가져오기</h2>
<h3 id="1-구글-비밀번호-내보내기">1. 구글 비밀번호 내보내기</h3>
<p><code>passwords.google.com</code> 접속 → 우측 상단 설정(⚙️) → <strong>비밀번호 내보내기</strong> → CSV 다운로드</p>
<h3 id="2-vaultwarden으로-가져오기">2. Vaultwarden으로 가져오기</h3>
<p><code>vault.yourdomain.com</code> 로그인 → <strong>Tools</strong> → <strong>Import data</strong></p>
<ul>
<li>형식: <code>Google Chrome (csv)</code> 선택</li>
<li>다운로드한 CSV 파일 업로드</li>
<li><strong>Import</strong> 클릭</li>
</ul>
<blockquote>
<p>⚠️ CSV 파일에 비밀번호가 평문으로 들어있다. 가져오기 완료 후 즉시 삭제할 것.</p>
</blockquote>
<hr>
<h2 id="브라우저-확장-연동">브라우저 확장 연동</h2>
<p>크롬 웹스토어에서 <strong>Bitwarden</strong> 확장 프로그램을 설치한다.</p>
<p>확장 아이콘 클릭 → 로그인 화면 좌측 상단 <strong>지구본 아이콘</strong> 클릭 → <strong>Self-hosted</strong> 선택</p>
<p>Server URL에 <code>https://vault.yourdomain.com</code> 입력 후 Save.</p>
<p>이후 Vaultwarden 계정으로 로그인하면 기존 구글 자동완성과 동일하게 사이트마다 비밀번호를 자동완성해준다.</p>
<hr>
<h2 id="정리">정리</h2>
<ul>
<li>Vaultwarden은 Bitwarden과 완전 호환이라 앱, 확장 프로그램 그대로 쓸 수 있다</li>
<li><code>DOMAIN</code> 환경변수를 HTTPS 도메인으로 설정해야 브라우저 확장이 정상 동작한다</li>
<li>계정 생성 후 <code>SIGNUPS_ALLOWED=false</code>로 꼭 닫아두자</li>
<li>마스터 비밀번호 분실 시 복구 방법이 없으므로 안전하게 보관할 것</li>
</ul>
<p>다음 편에서는 Portainer CE를 설치해서 Docker 컨테이너를 GUI로 관리하는 환경을 구성한다.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
