プライベートなNPMパッケージ管理で便利なVerdaccioレジストリをConoHa VPSへお引越しする


2022/12/03
【Dockerで開発環境構築】Verdaccio on DockerでコンテナのローカルIPを調べる方法
蛸壺の技術ブログ|プライベートなNPMパッケージ管理で便利なVerdaccioレジストリをConoHa VPSへお引越しする

長らく社内のオンプレサーバー内にて社外秘の自作NPMパッケージの運用してきた
Verdaccioレジストリですが、ここ最近で別のISPプロバイダーに契約を切り替えたこともあり、どうせなら『ConoHa VPS』の料金控えめのLinuxインスタンスで構築し直そうと考えていました。

合同会社タコスキングダム|蛸壺の技術ブログ

以前のローカル環境でVerdaccioサーバーを構築して動かしてみた記事については、以下を記事リンクをご覧ください。

合同会社タコスキングダム|蛸壺の技術ブログ
【Dockerで開発環境構築】Verdaccio on DockerでコンテナのローカルIPを調べる方法

古いバージョンからVerdaccio5へのマイグレーションするときの注意点を考えてみます。

また、円安の影響の煽りで、npm公式のプライベートレポジトリのプランも割高に感じている方も多いのではないかと思います。

合同会社タコスキングダム|蛸壺の技術ブログ

参考|npm pricing

企業によっては、
「$7✕エンジニア数の利用料」をしっかり支払われているところも多いかも知れません。

これから円安のリスクや電気代の高騰などのコストに関わるリスクに備えて可能な限り開発コストを節約してみたいのなら、VerdaccioとConoHa VPSを組み合わせることで、
利用人数関係なく月々数百円ポッキリの支払いで済ませられるのは非常に魅力的です。

ということで今回はConoHa VPSなどのリモートのLinuxサーバーへVerdaccioを引っ越しさせたときの個人的な技術防備録になります。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】nodejsをこれから学びたい人のためのオススメ書籍&教材特集

合同会社タコスキングダム|蛸壺の技術ブログ

準備 〜 ConoHa VPSインスタンス(Debian)にDockerを導入する

Verdaccioを起動するためには、npmパッケージ版なども利用可能ですが、よりサクッと使いたい場合にはコンテナ内にサービス機能一式があらかじめ詰め込まれたr「Dockerイメージ版」をチョイスしましょう。

まずはConoHa VPSで立ち上げたインスタンスに
dockerdocker-composeをインストールします。

なおConoHa VPSの初期設定の話としては以下の以前の記事内容を参考にしてみてください。

合同会社タコスキングダム|蛸壺の技術ブログ
【VPS・Linuxサーバー入門】ConoHa VPSでDebianインスタンスの初期設定〜ユーザーの追加してみる

『ConoHa VPS』で立ち上げたのDebianベースのVPSインスタンスにroot以外のユーザーを追加する手順を解説します。

まずDebian OSへのdockerの導入方法は、リソースビルドするしか無かった時代と比べると、かなり楽になっています。

以下のようにインストールスクリプトが用意されているので、このスクリプトを走らせるだけで簡単にdockerを導入することができます。

            
            $ curl -sSL https://get.docker.com | sh
        
これで問題が出なければDockerの準備は完了です。

次にdocker-composeですが、
pip3経由でインストールするのがもっとも簡単なやり方です。

ちなみに現状のDebian OSはデフォルトでpython3がインストールされていますが、pip3はデフォルトで入ってはいないと思います。

pip3の導入には、aptを使ってインストールできます。

            
            $ sudo apt install python3-pip
        
pip3が使えるようになったら、簡単にdocker-composeもインストールできます。

            
            $ sudo pip3 install docker-compose
        
ここまででもうDockerは使えるようになっていますが、もう一つ設定しておきたいのが、ルートユーザーでない場合にsudo無しdockerコマンドでは、以下のようなエラーが発生してしまいます。

            
            $ docker ...
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/create?fromImage=alpine&tag=edge: dial unix /var/run/docker.sock: connect: permission denied
        
これはroot以外のユーザーにdockerコマンドを直接実行する権限がないと言われているために起こるものです。

毎回
sudoしてdockerを呼び出すのは面倒ですので、現在のユーザーにdockerグループに参加することでPermissionを与えておきます。

            
            $ whoami
hoge
#👇権限を与えたいユーザーに"hoge"の箇所を置換える
$ sudo usermod -g docker hoge
$ sudo systemctl restart docker.service
$ id hoge
#👇ユーザーにdockerの実行権限が付与されている
uid=1000(hoge) gid=995(docker) groups=995(docker),...
        
設定を有効にするためには、一度Ctrl + Dでログアウトしてログインし直すか、インスタンス自体を再起動すると、次回からのdockerコマンドの実行にはsudoの枕詞が要らなくて済みます。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】nodejsをこれから学びたい人のためのオススメ書籍&教材特集

合同会社タコスキングダム|蛸壺の技術ブログ

Verdaccioの起動テスト

先程まででdocker周りの実行環境を整えたので、DockerHubからVerdaccioのコンテナイメージを取得して利用します。

ConoHa VPSのインスタンスにSSH接続したら、適当な作業フォルダを作成し、
docker-compose.ymlファイルを以下の感じに編集します。

            
            version: '3'

services:
  verdaccio:
    image: verdaccio/verdaccio:5
    container_name: verdaccio-vps
    environment:
      NODE_ENV: development
    ports:
      - "54321:4873"
    volumes:
        - "./storage:/verdaccio/storage"
        - "./conf:/verdaccio/conf"
volumes:
  verdaccio:
    driver: local
        
なお、Verdaccioのデフォルトのサービスポートの番号は「4873」ですが、デフォルトのままでは攻撃されやすいので、外部からのアクセスには例えば「54321」などに繋ぎ変えておきましょう。

また、
confフォルダを作成し、config.yamlというVerdaccioの設定ファイルを作成します。

            
            $ mkdir conf
$ touch conf/config.yaml
        
とりあえず試しに最初のconfig.yamlには以下のような内容にしておきましょう。

            
            storage: /verdaccio/storage

auth:
  htpasswd:
    file: /verdaccio/conf/htpasswd
    algorithm: bcrypt

security:
  api:
    jwt:
      sign:
        expiresIn: 60d
        notBefore: 1
  web:
    sign:
      expiresIn: 7d

uplinks:
  npmjs:
    url: https://registry.npmjs.org/

packages:
  '@*/*':
    access: $authenticated
    publish: $authenticated

  '**':
    access: $all
    publish: $authenticated
    proxy: npmjs

middlewares:
  audit:
    enabled: true

logs: { type: stdout, format: pretty, level: http }
        

なお、より詳しい設定ファイル・
config.yamlの書式に関しては、こちらのドキュメントでご確認ください。

ここまでで、以下のようなプロジェクトフォルダになっていると思います。

            
            $ tree
.
├── conf
│   └── config.yaml
└── docker-compose.yml
        

コンテナを起動すると、

            
            $ docker-compose up
Recreating verdaccio-vps ... done
Attaching to verdaccio-vps
verdaccio-vps |  warn --- config file  - /verdaccio/conf/config.yaml
verdaccio-vps |  info --- plugin successfully loaded: verdaccio-htpasswd
verdaccio-vps |  info --- plugin successfully loaded: verdaccio-audit
verdaccio-vps |  warn --- http address - http://0.0.0.0:4873/ - verdaccio/5.18.0
        
というようにコンテナが起動状態になり、http://<VPSのIPアドレス>:54321で直接ブラウザからアクセスすると、Verdaccioのダッシュボードが確認できるようになります。

合同会社タコスキングダム|蛸壺の技術ブログ

問題なく確認したら
Ctrl+Cでコンテナから抜けて、一旦コンテナをを止めておきましょう。

            
            $ docker-compose down
        
ということでConoHa VPSでも問題なくVerdaccioレジストリが動作していることが確認できました。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】nodejsをこれから学びたい人のためのオススメ書籍&教材特集

合同会社タコスキングダム|蛸壺の技術ブログ

VerdaccioのSSL対応

パスワードによるログイン認証を行う場合、ローカルの外へ通信の閉じた環境と違って、すべてオンライン越しになるとパスワードを盗み取られるリスクも増大します。

デフォルトのままの
httpアクセスだと通信自体が筒抜けですので、リモートのVerdaccioサーバーへアクセスする際には、きちんとSSLに対応させたhttpsでのアクセスに手直ししておきたいところです。

手順としては公式の内容通りです。

参考|Set up the SSL Certificates

また、以下では
localhostをオレオレSSL証明して試すサンドボックス的な手順を紹介しますが、あくまでローカル開発環境だけの範囲で有効です。

もし、本番環境を想定したVPSでのVerdaccioサーバー運用を検討している場合には、きちんとしたドメイン名を取得し、
Let's Encrypt等のしっかりとした第三者の提供するSSL認証サービスを検討しましょう。

opensslでオレオレ認証を発行してつかう(ローカル環境のみ)

とりあえずは公式のドキュメントにも紹介してあるように「openssl」でSSL認証を行うやり方をやってみます。

まずはSSL認証キーとなるファイルを生成します。

なお、ConoHa VPSのDebianOSインスタンスだとopensslコマンドは最初から使えると思いますが、無い場合には別途インストールしてください。

            
            #👇confフォルダ内に認証キーを生成
$ openssl genrsa -out conf/verdaccio-key.pem 2048
#👇認証キーから秘密キーを生成
$ openssl req -new -sha256 -key conf/verdaccio-key.pem -out conf/verdaccio-csr.pem
#👇SSL認証キーを作成
$ openssl x509 -req -in conf/verdaccio-csr.pem -signkey conf/verdaccio-key.pem -out conf/verdaccio-cert.pem
        
これらのキーができたらconfig.yamlに以下のフィールドを追加します。

            
            #...
https:
  key: /verdaccio/conf/verdaccio-key.pem
  cert: /verdaccio/conf/verdaccio-cert.pem
  ca: /verdaccio/conf/verdaccio-csr.pem
#...
        
生成したファイルを確認すると、通常のユーザーに読み込み権限がない場合があるので、一度権限グループの設定をよく見ておきましょう。

            
            $ ls -la conf/
-rw-r--r-- 1 hoge docker 1918 Nov 29 13:48 config.yaml
-rw-r--r-- 1 hoge docker 1289 Nov 29 13:41 verdaccio-cert.pem
-rw-r--r-- 1 hoge docker 1082 Nov 29 13:38 verdaccio-csr.pem
-rw------- 1 hoge docker 1675 Nov 29 13:29 verdaccio-key.pem
        
この場合、verdaccio-key.pemがルートユーザーだけしか読めない設定になっているので、chmodコマンドでファイルのアクセス権限を変更しておきましょう。

            
            $ sudo chmod 644 conf/verdaccio-key.pem
$ ls -la conf/
#...
-rw-r--r-- 1 hoge docker 1675 Nov 29 13:29 verdaccio-key.pem
        
これでSSL対応になりましたので、あとはdocker-composeで起動する際に、環境変数にVERDACCIO_PROTOCOL=httpsとなるようにしてあげるだけです。

            
            version: '3'

services:
  #...
    environment:
      NODE_ENV: development
      #👇追加
      VERDACCIO_PROTOCOL: https
#...
        

再度、
docker-compose upでコンテナを起動してみると、Firefoxのようなブラウザでは自分でSSL認証したサイトは怪しいサイトとして警告は出てしまいますが、気にせず開くと、

合同会社タコスキングダム|蛸壺の技術ブログ

ちゃんとVerdaccioのダッシュボードがhttpsでアクセス可能になりました。

ちなみにこの
「オレオレSSL認証」を使った場合、後述にて説明している「ユーザー登録」の操作などnpmコマンドから、リモートのverdaccioレジストリにアクセスすることができないかも知れません。

            
            $ npm --version
8.19.2

$ npm adduser --registry https://xxx.xxx.xxx.xxx:54321
npm WARN adduser `adduser` will be split into `login` and `register` in a future version. `adduser` will become an alias of `register`. `login` (currently an alias) will become its own command.
npm notice Log in on https://xxx.xxx.xxx.xxx:54321/
npm ERR! code DEPTH_ZERO_SELF_SIGNED_CERT
npm ERR! errno DEPTH_ZERO_SELF_SIGNED_CERT
npm ERR! request to https://xxx.xxx.xxx.xxx:54321/-/v1/login failed, reason: self-signed certificate

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/node/.npm/_logs/2022-11-29T08_00_46_660Z-debug-0.log
        
おおよそちょっと以前のnpmコマンドでは、DEPTH_ZERO_SELF_SIGNED_CERTなどのセキュリティ関連のエラーを回避する方法を解説されている記事を多数見つけることが出来ます。

ですが最近では悪意のあるマルウェアが巧妙に仕込まれたNPMパッケージがたびたび報告されるケースもテックニュース界隈で話題となっています。

この辺の事情もあり、現行のnpmではセキュリティ強化の観点から、「オレオレSSL認証局」で建てた本番環境で運用しているリモートサーバー側へのhttpsアクセスの『裏ワザ』は許可されていないのではと推測します。

mkcertによるSSL認証の置き換えで試す(ローカル環境のみ)

もう一つ、高機能なローカル開発環境のSSL認証を実現させる「mkcert」ではどうなのか、opensslとの比較として、著者の興味本位でこちらも試してみることにします。

なお、この項目の内容に興味がなければ、次の項目へスキップして頂いても構いません。

合同会社タコスキングダム|蛸壺の技術ブログ
【Angular】ローカル環境下のSPA(シングルページアプリケーション)を常時SSL(https)化に対応させる方法

Angularで使えるローカル開発時にmkcertを用いた常時SSL化をする方法をまとめました。

こちらだとせめて、ブラウザのアクセスブロッキングだけでもどうにかなる...?と期待はしていましたが、結論からいうと、mkcertといえどもリモートサーバー越しのhttpsアクセスはブロックされる仕様です。

セキュリティ面でも、「openssl」も「mkcert」もリモート側で運用するような本番環境ではリスクがあるので、オンライン等でリモート間の利用は避けたほうが良いようです。

まずはConoHa VPS側で、DebianOSインスタンスに
mkcertを導入しましょう。

            
            $ sudo apt install libnss3-tools

$ curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"
$ ls
#👇最新のバイナリバージョンの確認
mkcert-v1.4.4-linux-amd64
$ chmod +x mkcert-v1.4.4-linux-amd64
$ sudo cp mkcert-v1.4.4-linux-amd64 /usr/local/bin/mkcert
$ mkcert --version
v1.4.4
#👇インストール後の後片付け
$ rm -rf mkcert-v1.4.4-linux-amd64
        
mkcertがインストールできたので、早速自分認証を発行してみます。

            
            $ mkcert -install
Created a new local CA 💥
The local CA is now installed in the system trust store! ⚡️
        
これでローカルにオレオレCA(認証局)が発行されたようです。

これでmkcertの準備が完了し、実際に利用したいドメイン名(複数名指定可能)を指定して以下のようにコマンドを叩くと、

            
            $ mkcert localhost 127.0.0.1 <ConoHa VPSのIPアドレス> ...

Created a new certificate valid for the following names 📜
 - "localhost"
 - "127.0.0.1"
 - "xxx.xxx.xxx.xxx"

The certificate is at "./localhost+2.pem" and the key at "./localhost+2-key.pem" ✅

It will expire on 1 March 2025 🗓
        
というように現在のフォルダにlocalhost+2.pemlocalhost+2-key.pemの2つのキーファイルが生成されました。このファイルのアクセス権限を確認・修正し、作業ファイルのconfフォルダに移動します。

            
            $ sudo chmod 644 localhost+2-key.pem
$ mv localhost+2.pem localhost+2-key.pem conf/
        
これらのキーを再びconfig.yamlに以下のhttpsフィールドに置き換えます。

            
            #...
https:
  key: /verdaccio/conf/localhost+2-key.pem
  cert: /verdaccio/conf/localhost+2.pem
#...
        
これでVerdaccioを立ち上げて、https://...でブラウザからアクセスしてみると、

合同会社タコスキングダム|蛸壺の技術ブログ

...症状としてはopensslでも同じですね。オレオレ証明書のセキュリティで引っかかるようです。

ということでここまでの教訓として、Verdaccioサーバーを本格導入・運営していくためには、

            
            1. 独自ドメインを取得&信頼のある第三者認証局を利用したSSL対応
2. JWT(JSON Web Token)などを利用したHTTPリクエストヘッダーでのユーザー認証
3. iptableなどを利用したファイヤーウォールでのアクセス制限
        
のような対策が別途必要になることが分かります。

Verdaccioサーバーへのユーザー認証などセキュリティ面の設定の話は長くなりそうなので一旦保留し、この記事では
httpのままでnpmコマンドを利用することでもう少し話を進めていきます。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】nodejsをこれから学びたい人のためのオススメ書籍&教材特集

合同会社タコスキングダム|蛸壺の技術ブログ

ConoHa VPSのVerdaccioレジストリでパッケージを操作する

前項までの内容で、シンプルなVerdaccioレジストリがリモートで立ち上がるようになりました。

せっかくなので、自作のnpmパッケージをpublishしたり、ダウンロードしてみたりと、簡単なnpmコマンドからの基本操作が行えるかも検証してみます。

Verdaccioのパッケージ管理について

リモートのVerdaccioサーバーでパッケージの操作をしていく前に、Verdaccio独自の「パッケージ・アクセス」の規約を簡単におさらいしましょう。

通常、パッケージのアクセスに関する設定は
[config.yaml] > [packages]のフィールドに記述します。

            
            packages:
  #👇スコープ付きのパッケージ①
  #誰でも読み込みOK&パブリッシュは登録ユーザーのみ
  '@hoge/*':
    access: $all
    publish: $authenticated

  #👇スコープ付きのパッケージ②
  #誰でも読み込みOK&パブリッシュは登録ユーザーのみ
  #パッケージがない場合、通常のnpmレポジトリへ探しに行く
  '@piyo/*':
    access: $all
    publish: $authenticated
    proxy: npmjs

  #👇ユーザー指定のパッケージ①
  #fugaの専用パッケージ...登録ユーザーのみ読み込み&fugaのみパブリッシュOK
  'fuga-*':
    access: $authenticated
    publish: fuga

  #👇ユーザー指定のパッケージ②
  #mogeの専用パッケージ...moge/fugaのみ読み込み&mogeのみパブリッシュOK
  'moge-*':
    access: moge fuga
    publish: moge

  #👇上記以外のその他のパッケージ
  #ログイン不要で誰でも取得&パブリッシュ可
  '**':
    access: $all
    publish: $all
    proxy: npmjs
        
基本的には、packagesでより先に記述した設定が優先されるため、「**」の全てのパッケージのルートにキャプチャする項目を使う場合には、それより上の項目に個別のパッケージルートを記述する必要があります。

各パッケージルートにそれぞれのアクセス属性を書いていくわけですが、必須フィールドなのが
accesspublishです。

文字通り、「誰に」パッケージを閲覧可能するか、またパッケージをパブリッシュ可能にするかの属性を制御します。ここで指定できるトークンとしては種類がありますが、覚えておくのは
$anonymous$all$authenticated<ユーザー名>くらいを使えれば結構かと思います。

パッケージのアクセス権限は
$anonymous$all$authenticated<ユーザー名>の順で協力になります。

$anonymous$allはVerdaccioへログインしなくても誰でも権限が与えられます。$anonymous$allはちょっとした違いですが、ログインしたときに、ログインしたユーザー名が表示されるかされないかの違いがあります。

$authenticatedはVerdaccioへログイン済みのメンバーにしか操作できない相当のトークンです。

さらに、
<ユーザー名>を直接指定することで権限を持つメンバーを制限することもできます。

また、
proxyの属性では、Verdaccioサーバーにお目当てのパッケージが無い場合に、別のレポジトリへ探しにいく宛先を記述できます。

これについては、基本的に
npmjsだけを覚えていれば問題ないと思います。もし、proxynpmjsを指定していれば、そのパッケージが無いときに、通常のnpmパッケージを探しに行ってくれます。proxyフィールドを指定していない場合で、Verdaccioサーバーに指定したパッケージが無いなら、npmエラーでインストールが止まらせることも可能です。

クライアント側からユーザーの登録

ここからはパッケージの操作を行っていきます。

最初にユーザーを登録する必要があります。

まずはリモート側のVerdaccioサーバーを起動しておきましょう。

            
            $ docker-compose up
        
ローカルのクライアント側から「npm-adduser」コマンドで、ユーザーを登録&ログインします。

            
            $ npm adduser --registry http://<ConoHa VPSのIPアドレス>:54321
        
問題なく接続出来ていたらOKです。

なお、npm v8以前では
「npm-adduser」コマンドがユーザーの新規登録かつログインの2つの役割を持つコマンドでしたが、npm v9から「npm-login」コマンドが追加され、npm-adduserコマンドはユーザー登録、npm-loginコマンドはログイン操作のみに分割されました。

もし、お手元のnpmコマンドがv9以上ならば、
adduserコマンドとloginコマンドを使い分ける必要があります。

NPMパッケージをVerdaccioサーバーへアップロードする

自作パッケージのパブリッシュに関しては、[config.yaml] > [packages]フィールドに記述したパッケージルートによって、ログインする必要の有無が変わります。

npm-publishコマンドの詳細は公式のリファレンスを参照していただくとして、以下のようなコマンドでpackage.jsonの内容がVerdaccio側にパブリッシュされることを確認しましょう。

            
            $ npm publish --registry http://<ConoHa VPSのIPアドレス>:54321
        
問題なければ、開発中のNPMパッケージがパブリッシュ出来ているはずです。

合同会社タコスキングダム|蛸壺の技術ブログ


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】nodejsをこれから学びたい人のためのオススメ書籍&教材特集

合同会社タコスキングダム|蛸壺の技術ブログ

まとめ

今回はConoHa VPSを利用して、Verdaccioサーバーをリモートで提供できるサービスを作る最初の概論のようなものを解説してみました。

現行のNPM公式のTeamsプラン相当だと、月々$7/userの利用コストがかかるので、組織として運用していくならばVerdaccio+ConoHa VPSで代替すると非常に経済的です。

また課題として、本番環境でのVerdaccioサーバーへのセキュリティ面での話も考えなくてはいけないので、今後時間が許せば、じっくりと設定方法の紹介をしていこうかと思います。