西出正美です。有益なことや無益なことなどいろいろ書いています。

OnionドメインのウェブサイトをDockerで構築して公開する

OnionドメインのウェブサイトをDockerで構築して公開したいこと、ありますよね。
僕はあるので自分用にメモです。

なお、このレポートを書くにあたってO'Reilly Dockerを参考にしました。

最小構成で作る

構築の土台となる部分を最小構成で作成します。
最小構成で一旦動かしてみることで動きなども理解できます。

Docker

まずcompose.yamlを作ります。

compose.yaml
version: '3.8'

services:
  nginx:
    image: nginx:alpine
    networks:
      - tor_network
    volumes:
      - ./htdocs:/usr/share/nginx/html:ro
    restart: unless-stopped
  tor:
    build:
      dockerfile: ./tor/Dockerfile
    networks:
      - tor_network
      - front
    volumes:
      - ./data:/var/lib/tor
      - ./tor/settings:/etc/tor
    restart: unless-stopped

networks:
  front:
  tor_network:
    internal: true

ネットワークは、外部に接続するためのfrontネットワークと、外部とつながっていない内部だけで独立したネットワークのtor_networkを作成します。
torコンテナだけ外部と接続し、nginxコンテナを外部と遮断し、そしてtorコンテナとnginxコンテナをtor_networkネットワークでつなげることにします。

ネットワーク図に表すと以下のようになります。

  fronttor_networkDocker内部 nginxinternetDocker仮想ブリッジtornginx

nginxコンテナは、余計なものが入っていないnginx:alpineを使用します。
torコンテナは、後述のDockerfileを使用します。

また、どちらもrestart: unless-stoppedで、落ちたら再起動するようにしています。不要だったかもしれません。

Tor

torコンテナのDockerfileは、alpine:latestにtorを追加して起動するだけのものです。

tor/Dockerfile
FROM alpine:latest

RUN apk update
RUN apk add tor

CMD ["tor", "-f", "/etc/tor/torrc"]

torの設定ファイルであるtorrcで、80ポートへの接続をnginxコンテナに向けています。
※Dockerネットワーク内ではコンテナ名で名前解決をすることができる

tor/settings/torrc
SocksPort 0
HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 80 nginx:80

誰かの踏み台にされるのだけは防ぐためにSocksPort 0の設定をしていますが、自分でもTorプロクシとして利用したい場合はここをSocksPort 0.0.0.0:9150として、DockerfileEXPOSE 9150をしてからcompose.yamlでtorのportsに"9150:9150"を追加することでSOCKSホストとして利用できます。

Nginx

Nginxはnginx:alpineイメージをそのまま使います。
なにも表示されないと動いているかどうかわかりにくいのでindex.htmlを配置しておきます。

htdocs/index.html
<!DOCTYPE html>
<html>
  <head>
    <title>docker hidden service test title</title>
  </head>
  <body>
    <div>docker hidden service test body div</div>
  </body>
</html>

以上で最小構成は作成完了です。

起動する

Dockerは普通にdocker-compose up -dコマンドで起動します。

起動確認(Onionドメインの疎通確認)

正常に起動すると、data/hidden_service/hostnameに以下のようなファイルが出力されています。

data/hidden_service/hostname
kxal3j4zblhjt4jinnbly6icciqbh2ihq4u2opsu4qhqyqazwsgaq3ad.onion

このアドレスにTorブラウザなどで接続し、作成したindex.htmlが表示されていることを確認します。

WindowsでDockerを立てている場合、ここで既にdata/hidden_serviceが存在すると、以下のようなエラーメッセージが出て終了してしまいます。

[notice] Tor 0.4.7.13 running on Linux with Libevent 2.1.12-stable, OpenSSL 3.0.7, Zlib 1.2.13, Liblzma 5.2.9, Libzstd 1.5.2 and Unknown N/A as libc.
[notice] Tor can't help you if you use it wrong! Learn how to be safe at https://support.torproject.org/faq/staying-anonymous/
[notice] Read configuration file "/etc/tor/torrc".
[warn] Permissions on directory /var/lib/tor/hidden_service/ are too permissive.
[warn] Failed to parse/validate config: Failed to configure rendezvous options. See logs for details.
[err] Reading config failed--see warnings above.

既にWindows側の既存のディレクトリをDockerでマウントするとディレクトリのパーミッションが777になります。
そのためSSH接続時の証明書と同様に、パーミッションがあまりにもオープンすぎるとTorが判断するとエラーで止まるようです。
なので既存のhidden_serviceを使用したい場合は、tor/Dockerfile内でCOPYしたりchmod -R 700 /var/lib/tor/hidden_service/を叩く必要がありそうですが、今回は最小構成だけ作りたいのでここでは説明を省きます。

Torブラウザで表示できたところ
Torブラウザで表示できたところ

無事に動いていることが確認できました。

nginxコンテナは外部に接続できないようになっていますから、セキュリティは高いです。
もし更にセキュリティを向上させるのであれば、nginxコンテナやtorコンテナをdistrolessscratchでマルチステージビルドで組み立てると良いでしょう。その方法についてはまた後日投稿します。

NISHIDEMASAMI.GITHUB.IO
NISHIDE, Masami

西出正美です。有益なことや無益なことなどいろいろ書いています。

©NISHIDE, Masami Some Rights Reserved