Portainer를 사용하여 Vaultwarden 설치하기

시놀로지 NAS에 비밀번호 관리 도구인 Vaultwarden을 설치하여 2주 정도 테스트를 진행했다. 그런데 만족도가 예상보다 훨씬 높았다. 마스터 비밀번호가 아닌 PIN 번호를 사용해 인증하면 비밀번호를 입력할 수 있기도 하고 Vaultwarden이 설치된 시놀로지 NAS가 종료되어 있는 상태에서도 사용할 수 있었다. 브라우저의 플러그인에 캐싱된 비밀번호를 사용할 수 있는 것으로 보인다. 이제 Vaultwarden을 계속 사용할 것인지 결정해야 한다.

시놀로지 NAS의 Valultwarden을 계속 사용할 것인가

Vaultwarden을 계속 사용할 이유는 차고도 넘친다. 유료인 Bitwarden 클라우드가 아닌 직접 설치(셀프 호스팅)하여 사용할 수 있는 프리웨어를 리눅스에 설치해 사용하더라도 안전하고 편리했다. 그리고 중요한 백업과 복구도 문제 없이 잘 동작했다. 심지어 백업된 json 파일도 암호화하여 백업하고 암호화된 json 파일로 복구도 문제가 없었다.

하지만 문제는 시놀로지 NAS의 컨테이너 매니저를 계속 사용할 것인가 하는 점이었다. 시놀로지 NAS는 DDNS를 사용해 외부에서 접속할 수 있지만 밤에는 꺼지고 오전에 다시 켜지도록 구성되어 있기도 하고 이런 저런 장난(?)을 치다보면 NAS의 구성이 수시로 변경되기도 하며 통신사에서 제공받은 공유기의 NAT 설정도 신경써줘야 한다. 즉 지속적으로 사용하기에는 조금 문제가 있다.

그래서 결론은 내가 사용하고 있는 오라클 클라우드의 가상서버에 설치하기로 했다.

오라클 클라우드 가상서버의 Portainer (웹 기반 도커 관리 도구)

필자는 오라클 클라우드의 서울리전과 춘천리전 두 곳을 사용한다. 서울리전에는 2개의 가상서버를 사용해 블로그를 구축하여 운영하고 있고 ARM 프로세서를 사용하는 4 Core / 24 GiB의 서버를 서울과 춘천에 모두 2대를 테스트 용으로 사용하고 있다.

그래서 이 두 ARM 기반 가상서버 2대에 도커를 설치하고 1대에 웹 기반 컨테이너 관리 도구인 Portainer를 설치하고 Portainer를 사용해 Vaultwarden을 컨테이너로 설치하기로 했다.

Portainer에 등록되어 있는 2개의 노드 중 app 노드에 Vaultwarden을 설치한다.

사전 준비 사항

Vaultwarden은 https로만 접속해야 한다. 왜냐하면 ID와 비밀번호가 인터넷을 통해 평문으로 전송되면 절대 안되기 때문이다. 즉 도메인 주소가 있어야 하고 도메인 주소에 SSL 인증서를 발급해 적용해야 한다. 하지만 컨테이너 이미지로 제공되는 Vaultwarden은 https 접속을 지원하지 않는다. 즉 컨테이너 바로 앞까지는 HTTPS로 통신하고 컨테이너로 전달되는 트래픽만 HTTP로 전환해 컨테이너로 전달하도록 구성해야 한다.

첫 번째는 바로 도메인 주소다.

필자의 경우 도커가 설치된 app 노드(서버)에는 예전부터 구입해 사용하던 g***e.pe.kr이라는 도메인 주소에 호스트네임은 app로 할당했다. 즉 app.g***e.pe.kr 라는 주소를 사용하기로 했다. SSL 인증서는 수동으로 발급받지 않아도 된다. Revers-Proxy 매니저인 Caddy가 자동으로 발급 받아 처리해준다.

두 번째는 데이터를 저장할 디렉토리(볼륨)다.

Vaultwarden 컨테이너는 추가된 사이트 정보와 크리덴셜(ID, 비밀번호 등)을 SQLite라는 경량 DBMS를 통해 DB에 저장한다. 하지만 이 DB는 기본적으로 메모리에만 유지되며 컨테이너를 재구동하면 추가된 크리덴셜은 사라진다. 때문에 Vaultwarden이 추가된 크리덴셜을 저장하는 SQLite DB의 경로를 컨테이너 외부의 호스트(가상머신)에 디렉토리를 만들고 데이터를 저장할 볼륨으로 마운트해줘야 한다.

Vaultwarden에 마운트할 /data/vaultwarden과 Reverse Proxy인 Caddy의 설정을 저장할 /data/caddy라는 두개의 디렉토리를 미리 생성해둬야 한다. (경로의 이름은 변경 가능함)

caddy vaultwarden volume
caddy vaultwarden volume

세 번째는 리버스 프록시용 브릿지 인터페이스다.

리버스 프록시는 일반 프록시(정방향 프록시)와는 반대로 여러 웹서버의 앞단에서 웹서버에 접속하고자 하는 클라이언트의 트래픽을 웹서버로 분배해주는 역할을 수행하는 프록시다. (자세한 설명은 생략함) 이 리버스 프록시로 사용할 SW가 바로 Caddy다. 이 Caddy에서 사용할 브릿지 네트워크 인터페이스를 다음 명령으로 생성해준다.

$ docker network create reverse_proxy
revers prox interface creation
revers prox interface creation

리버스 프록시의 이름을 잘 기억해두자. Caddy를 Deploy(설치)하는 yaml을 작성할 때 이 이름을 입력해줘야 한다.

Vaultwarden 컨테이너 Deploy(디플로이)하기

Portainer에서 다음과 같이 Stacks로 이동해서 Add stack을 누른다. 스택은 Portainer에서 사용하는 컨테이너 등 자원의 집합체를 지칭하는 용어다. 그냥 컨테이너를 만든다고 보면 된다. 다만 여러개의 컨테이너와 서비스를 포함할 수 있다.

포테이너에서 스택 생성
포테이너에서 스택 생성

스택의 이름(Name)을 지정하고 Web editor를 선택하면 아래에 표시되는 에디터 창에 vaultwarden을 deploy하기 위한 yaml 파일을 입력한다.

포테이너에서 vaultwarden 컨테이너 생성을 위한 yaml 입력
포테이너에서 vaultwarden 컨테이너 생성을 위한 yaml 입력

다음 코드는 필자가 vaultwarden을 deploy할 때 사용한 코드다.

version: '3'

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: always
    environment:
      - WEBSOCKET_ENABLED=fals
      - ADMIN_TOKEN=1234567890abcdefghijk  # 길고 복잡하고 어려운 코드 암호키 지정할 것
    expose:
      - "80"   # 외부에는 노출 안 하고, reverse proxy용으로만 사용. 클라이언트의 접속은 Caddy Reverse proxy가 처리하여 이 vaultwarden 컨테이너의 80으로 전달하도록 구성할 예정
    volumes:
      - /data/vaultwarden:/data    # vaultwarden의 SQLite DB가 저장될 호스트(VM)의 경로
    networks:
      - reverse_proxy    # Caddy Reverse Proxy와 통신할 인터페이스

networks:
  reverse_proxy:
    external: true

yaml을 입력하고 Deploy한다.

Portainer vaultwarden deploy
Portainer vaultwarden deploy

컨테이너가 정상적으로 Deploy되었다면 동일한 방법으로 Caddy를 Stacks 메뉴에서 생성할 차례다.

Caddy(리버스 프록시) Deploy 하기

클라이언트의 https 요청을 http로 변환하여 Vaultwarden 컨테이너로 전달해주는 역할은 Reverse Proxy인 Caddy가 수행한다. 그래서 Caddy를 설치하기 전에는 Vaultwarden 웹페이지에 접속할 수 없다. Caddy는 Caddyfile 이라는 정책 파일에 정의된 대로 Caddy가 Listen하고 있는 6690 포트로 app.***.pe.kr 도메인에 접근하는 HTTPS 연결을 vaultwarden 컨테이너의 80 포트로 전달해준다. Caddy를 디플로이 할 때는 비어있는 Caddyfile이 반드시 있어야 마운트할 수 있으며 하며 아래의 연결 설정을 미리 입력해두어도 된다.

Caddyfile은 앞의 사전 준비 사항에서 언급한 호스트의 /data/caddy 디렉토리에 생성해야 한다. Caddyfile을 생성해두면 Caddy 컨테이너가 다음에 설명할 yaml 파일의 volumes에서 /data 경로가 마운트될 /data/caddy 디렉토리에서 Caddyfile을 찾아 읽어들인다.

Caddyfile
Caddyfile

app.g***.pe.kr 은 vaultwarden 컨테이너가 실행되고 있는 호스트(리눅스 가상서버)의 DNS 서버에 등록된 도메인주소다. 그리고 reverse_proxy는 “docker create network” 명령으로 생성한 브릿지 네트워크 인터페이스의 이름이고 이 인터페이스를 vaultwarden 컨테이너에서도 사용하도록 yaml에서 지정해주었다.

이 Caddyfile의 내용은 Caddy가 클리이언트 중 app.g***.pe.kr 도메인 주소로 접근하는 웹 트래픽을 reverse_proxy 인터페이스를 통해 vaultwarden 컨테이너의 80 포트로 전달하라는 의미다.

이 Caddyfile을 생성하고 정책을 입력한 다음 Portainer의 Stacks 메뉴에서 다음과 같이 Caddy 컨테이너를 디플로이 한다.

Portainer caddy yaml
포테이너의 Stacks 메뉴에서 Caddy 디플로이하기

yaml 코드는 다음과 같다.

version: '3'

services:
  caddy:
    image: caddy:latest
    container_name: caddy
    restart: always
    ports:
      - "80:80"    # 80은 Caddy가 Caddyfile에 등록된 도메인주소의 SSL 인증서 관리를 위해 열어주어야 한다고 한다.
      - "6690:443"  # 호스트의 6690으로 들어오는 트래픽을 Caddy 컨테이너의 https(tcp/443)으로 전달한다. 포트 번호 6690은 호스트에서 사용하지 않는 안전한 번호로 변경한다.
    volumes:
      - /data/caddy/Caddyfile:/etc/caddy/Caddyfile
      - /data/caddy/data:/data
      - /data/caddy/config:/config
    networks:
      - reverse_proxy     # docker create network 명령으로 생성한 인어페이스를 Caddy가 사용함

networks:
  reverse_proxy:
    external: true

이 yaml을 입력하고 Deploy 하면 된다.

두 개의 컨테이너 (Caddy와 Vaultwarden) 상태 확인

Caddy와 Vaultwarden 컨테이너를 Portainer의 Stacks 메뉴에서 생성하면 다음과 같이 Deploy된 Stack을 확인할 수 있다.

Portainer stack list
Portainer stack list

Stack의 이름을 클릭하면 다음과 같이 Stack에 포함된 컨테이너의 상태를 확인할 수 있다. 그리고 좌측 메인 메뉴의 Stacks 메뉴 아래에 Containers 메뉴를 클릭하면 전체 컨테이너를 확인할 수 있다.

Portainer container list
Portainer로 Deploy된 vaultwarden과 Caddy 컨테이너

가운데 보이는 Agent는 App 노드에 Deploy된 portainer의 에이전트다. 이 에이전트를 통해 원격 서버의 Docker를 Portainer가 관리한다.

이제 vaultwarden의 관리자 페이지에 웹 브라우저를 통해 접속할 수 있다. 단, Deploy된 리눅스 서버의 iptable, firewalld 또는 클라우드의 방화벽(Security Group 또는 Security List 등)에서 Caddy가 사용하는 80과 6690을 열어주어야 한다.

포트가 정상적으로 열려 있다면 다음과 같이 vaultwarden admin 페이지가 보이게 된다.

https://app.g****.pe.kr:6690/admin
Vaultwarden admin page
Vaultwarden admin page

성공적으로 Vaultwarden을 오라클 클라우드의 ARM CPU를 지원하는 Rocky Linux VM에 컨테이너로 설치했다.

이후의 설정은 앞의 포스트에서 올린 “시놀로지 NAS의 컨테이너 매니저에 Vaultwarden 설치하기” 포스트의 내용을 참고하자.

#OCI #portainer #vaultwarden

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다