code-server にリバースプロキシを組み合わせてマルチユーザー対応の Web IDE 環境にしてみた

code-server にリバースプロキシを組み合わせてマルチユーザー対応の Web IDE 環境にしてみた

Clock Icon2025.03.29

はじめに

プログラミングやバイオインフォマティクスを学ぶ講義では、実習環境の準備が欠かせません。しかし、受講者ごとに環境を準備するのは大変な作業です。そこで、複数ユーザーが同時に利用できるブラウザベースの開発環境として、code-server の活用を検討しました。

以前検証した単一 EC2 上でのマルチユーザー向け code-server 環境を受講者視点で使いやすいように改善しました。具体的にはリバースプロキシの追加と HTTPS 対応しました。

https://dev.classmethod.jp/articles/multi-user-code-server-on-single-ec2/

検証環境

今回の検証では以下の構成で code-server 環境を導入しました。

項目 内容
EC2 インスタンス t3.small
EBS(gp3) 12GB
OS Ubuntu 24.04
code-server v4.98.2
SSL 証明書 Let's Encrypt

構成図

今回の構成はシンプルです。1 台の EC2 インスタンス上に code-server とリバースプロキシ(Caddy)を配置します。

JupyterHub(1).png

証明書はLet's Encrypt

Let's Encrypt は無料で SSL 証明書を提供する認証局です。自動化されたプロセスにより、証明書の取得と更新が簡単に行えます。今回は Let's Encrypt を使用して、セキュアな HTTPS 接続を実現しています。

https://letsencrypt.org/ja/

環境構築手順

Route 53でドメイン設定

まず、Route 53 でドメインを設定します。今回はcode.ohmura.example.comというドメインを使用しました。EC2 にアタッチした EIP のパブリック IP アドレスを A レコードとして登録します。

Route 53の設定画面

セキュリティグループの設定

EC2 インスタンスのセキュリティグループで、HTTP と HTTPS アクセスを許可します。HTTP ポート(80 番)は Let's Encrypt の認証に必要なため、事前に開放しておきます。

セキュリティグループ設定

code-serverのインストールと設定

code-server の設定と Caddy の設定用の自動化スクリプトを用意しました。このスクリプトでは以下の処理を行います。

  1. code-server と Caddy のインストール
  2. 指定した数のユーザーアカウント(Linux のユーザー)の作成
  3. 各ユーザー用の code-server 設定
  4. Caddy によるリバースプロキシ設定
  5. ユーザーアクセス情報の生成
setup.sh
#!/bin/bash
set -e

DOMAIN_NAME="code.ohmura.example.com
USER_COUNT=20
BASE_PORT=50443
CSV_FILE="/home/ubuntu/code-server-users.csv"

# 必要なパッケージのインストール
echo "必要なパッケージをインストールしています..."
sudo apt update
sudo apt install -y pwgen jq curl

# code-serverのインストール
CODER_VERSION=$(curl -s https://api.github.com/repos/coder/code-server/releases/latest | jq -r .tag_name | sed 's/v//')
DOWNLOAD_URL="https://github.com/coder/code-server/releases/download/v${CODER_VERSION}/code-server_${CODER_VERSION}_amd64.deb"

if [ ! -f "/usr/bin/code-server" ]; then
    echo "code-server ${CODER_VERSION} をダウンロードしています..."
    curl -fOL ${DOWNLOAD_URL}
    echo "code-server をインストールしています..."
    apt install -y ./code-server_${CODER_VERSION}_amd64.deb
    rm -f code-server_${CODER_VERSION}_amd64.deb
else
    echo "code-server はすでにインストールされています"
fi

# Caddyのインストール
echo "Caddyをインストールしています..."
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

# ユーザー情報CSVファイルの作成
echo "username,cs_password,access_url" > $CSV_FILE

# Webページ用ディレクトリの作成
sudo mkdir -p /var/www/code-server

# インデックスHTMLの作成
cat > /tmp/index.html << EOF
<!DOCTYPE html>
<html>
<head>
    <title>Code Server Instances</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
        h1 { color: #333; }
        ul { list-style-type: none; padding: 0; }
        li { margin: 10px 0; }
        a { color: #0066cc; text-decoration: none; padding: 10px; display: inline-block; border: 1px solid #ddd; border-radius: 4px; }
        a:hover { background-color: #f0f0f0; }
    </style>
</head>
<body>
    <h1>Code Server Instances</h1>
    <ul>
EOF

# Caddyfile の作成開始
cat > /tmp/Caddyfile << EOF
${DOMAIN_NAME} {
    handle / {
        root * /var/www/code-server
        file_server
    }

EOF

# ユーザーごとの設定
for i in $(seq 1 $USER_COUNT); do
    USERNAME="guest-$i"
    USER_HOME="/home/$USERNAME"
    PORT=$((BASE_PORT + i - 1))

    echo "ユーザー $USERNAME を設定しています..."

    # ユーザーが存在しない場合は作成
    if ! id -u "$USERNAME" &>/dev/null; then
        sudo useradd -m -s /bin/bash "$USERNAME"
    fi

    # code-server の設定ディレクトリを作成
    sudo mkdir -p "$USER_HOME/.config/code-server/"

    # code-server 用パスワードを生成
    CS_PASSWORD=$(pwgen -s -n -c 32 1)

    # 設定ファイルを作成
    sudo bash -c "cat > $USER_HOME/.config/code-server/config.yaml << EOF
bind-addr: localhost:$PORT
auth: password
password: $CS_PASSWORD
cert: false
EOF"

    # 所有権を設定
    sudo chown -R "$USERNAME:$USERNAME" "$USER_HOME/.config"

    # systemd サービスファイルを作成
    sudo bash -c "cat > /etc/systemd/system/code-server@$USERNAME.service << EOF
[Unit]
Description=code-server for $USERNAME
After=network.target

[Service]
Type=simple
User=$USERNAME
ExecStart=/usr/bin/code-server
Restart=always
WorkingDirectory=$USER_HOME

[Install]
WantedBy=multi-user.target
EOF"

    # サービスを有効化して開始
    sudo systemctl daemon-reload
    sudo systemctl enable --now "code-server@$USERNAME"

    # アクセスURLを作成
    ACCESS_URL="https://${DOMAIN_NAME}/${USERNAME}/"

    # CSVファイルに情報を追加
    echo "$USERNAME,$CS_PASSWORD,$ACCESS_URL" >> $CSV_FILE

    # インデックスHTMLにユーザーを追加
    echo "        <li><a href=\"/${USERNAME}/\">${USERNAME}</a></li>" >> /tmp/index.html

    # Caddyfileにユーザー設定を追加
    cat >> /tmp/Caddyfile << EOF
    handle /${USERNAME}/* {
        uri strip_prefix /${USERNAME}
        reverse_proxy http://localhost:$PORT
    }
    redir /${USERNAME} /${USERNAME}/ 301

EOF
done

# インデックスHTMLの終了タグ
cat >> /tmp/index.html << EOF
    </ul>
</body>
</html>
EOF

# Caddyfileの終了
cat >> /tmp/Caddyfile << EOF
    log {
        output file /var/log/caddy/code-server.log
    }
}
EOF

# 設定ファイルを適用
sudo mv /tmp/index.html /var/www/code-server/index.html
sudo mv /tmp/Caddyfile /etc/caddy/Caddyfile

# 権限設定
sudo chown -R caddy:caddy /var/www/code-server
sudo chmod -R 755 /var/www/code-server
sudo chown ubuntu:ubuntu $CSV_FILE
sudo chmod 600 $CSV_FILE

# Caddyサービスを再起動
sudo systemctl restart caddy

# サマリーを表示
echo "--- セットアップ完了 ---"
echo "各ユーザーのアクセス情報は以下のファイルに保存されています:"
echo "$CSV_FILE"
echo ""
echo "トップページ: https://${DOMAIN_NAME}"

スクリプトを実行すると、以下のような出力が表示されます。

--- セットアップ完了 ---
各ユーザーのアクセス情報は以下のファイルに保存されています:
/home/ubuntu/code-server-users.csv

トップページ: https://code.ohmura.example.com

管理者向け情報

各ユーザーの code-server パスワードは自動生成され、CSV ファイルに保存されます。

/home/ubuntu/code-server-users.csv
username,cs_password,access_url
guest-1,qgPwwppzzrkEEmWGgv9nQqL10cpPkg6s,https://code.ohmura.example.com/guest-1/
guest-2,xKsLmXWKRrUhIH9qw7x2oyCxHoVVCxbW,https://code.ohmura.example.com/guest-2/
guest-3,VVKWB5GnCvtgZoMOrx6qIIG2izweVLvw,https://code.ohmura.example.com/guest-3/
guest-4,VQunlw4g2YeSS1nfNDJWh7oND9KsEb9i,https://code.ohmura.example.com/guest-4/
guest-5,HkX80de45ADZyMlVNdvf5qfaJYLmFJIy,https://code.ohmura.example.com/guest-5/

Caddy の設定

リバースプロキシの設定は以下のファイルが作成されます。各ユーザー名に対応したパスへのアクセスを想定しています。

折りたたみ
/etc/caddy/Caddyfile
code.ohmura.example.com {
    handle / {
        root * /var/www/code-server
        file_server
    }

    handle /guest-1/* {
        uri strip_prefix /guest-1
        reverse_proxy http://localhost:50443
    }
    redir /guest-1 /guest-1/ 301

    handle /guest-2/* {
        uri strip_prefix /guest-2
        reverse_proxy http://localhost:50444
    }
    redir /guest-2 /guest-2/ 301

    handle /guest-3/* {
        uri strip_prefix /guest-3
        reverse_proxy http://localhost:50445
    }
    redir /guest-3 /guest-3/ 301

    handle /guest-4/* {
        uri strip_prefix /guest-4
        reverse_proxy http://localhost:50446
    }
    redir /guest-4 /guest-4/ 301

    handle /guest-5/* {
        uri strip_prefix /guest-5
        reverse_proxy http://localhost:50447
    }
    redir /guest-5 /guest-5/ 301

    handle /guest-6/* {
        uri strip_prefix /guest-6
        reverse_proxy http://localhost:50448
    }
    redir /guest-6 /guest-6/ 301

    handle /guest-7/* {
        uri strip_prefix /guest-7
        reverse_proxy http://localhost:50449
    }
    redir /guest-7 /guest-7/ 301

    handle /guest-8/* {
        uri strip_prefix /guest-8
        reverse_proxy http://localhost:50450
    }
    redir /guest-8 /guest-8/ 301

    handle /guest-9/* {
        uri strip_prefix /guest-9
        reverse_proxy http://localhost:50451
    }
    redir /guest-9 /guest-9/ 301

    handle /guest-10/* {
        uri strip_prefix /guest-10
        reverse_proxy http://localhost:50452
    }
    redir /guest-10 /guest-10/ 301

    handle /guest-11/* {
        uri strip_prefix /guest-11
        reverse_proxy http://localhost:50453
    }
    redir /guest-11 /guest-11/ 301

    handle /guest-12/* {
        uri strip_prefix /guest-12
        reverse_proxy http://localhost:50454
    }
    redir /guest-12 /guest-12/ 301

    handle /guest-13/* {
        uri strip_prefix /guest-13
        reverse_proxy http://localhost:50455
    }
    redir /guest-13 /guest-13/ 301

    handle /guest-14/* {
        uri strip_prefix /guest-14
        reverse_proxy http://localhost:50456
    }
    redir /guest-14 /guest-14/ 301

    handle /guest-15/* {
        uri strip_prefix /guest-15
        reverse_proxy http://localhost:50457
    }
    redir /guest-15 /guest-15/ 301

    handle /guest-16/* {
        uri strip_prefix /guest-16
        reverse_proxy http://localhost:50458
    }
    redir /guest-16 /guest-16/ 301

    handle /guest-17/* {
        uri strip_prefix /guest-17
        reverse_proxy http://localhost:50459
    }
    redir /guest-17 /guest-17/ 301

    handle /guest-18/* {
        uri strip_prefix /guest-18
        reverse_proxy http://localhost:50460
    }
    redir /guest-18 /guest-18/ 301

    handle /guest-19/* {
        uri strip_prefix /guest-19
        reverse_proxy http://localhost:50461
    }
    redir /guest-19 /guest-19/ 301

    handle /guest-20/* {
        uri strip_prefix /guest-20
        reverse_proxy http://localhost:50462
    }
    redir /guest-20 /guest-20/ 301

    log {
        output file /var/log/caddy/code-server.log
    }
}

トップページはこちらです。各ユーザーのパスへのリンクを作成しています。

/var/www/code-server/index.html

折りたたみ
/etc/caddy/Caddyfile
<!DOCTYPE html>
<html>
<head>
    <title>Code Server Instances</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
        h1 { color: #333; }
        ul { list-style-type: none; padding: 0; }
        li { margin: 10px 0; }
        a { color: #0066cc; text-decoration: none; padding: 10px; display: inline-block; border: 1px solid #ddd; border-radius: 4px; }
        a:hover { background-color: #f0f0f0; }
    </style>
</head>
<body>
    <h1>Code Server Instances</h1>
    <ul>
        <li><a href="/guest-1/">guest-1</a></li>
        <li><a href="/guest-2/">guest-2</a></li>
        <li><a href="/guest-3/">guest-3</a></li>
        <li><a href="/guest-4/">guest-4</a></li>
        <li><a href="/guest-5/">guest-5</a></li>
        <li><a href="/guest-6/">guest-6</a></li>
        <li><a href="/guest-7/">guest-7</a></li>
        <li><a href="/guest-8/">guest-8</a></li>
        <li><a href="/guest-9/">guest-9</a></li>
        <li><a href="/guest-10/">guest-10</a></li>
        <li><a href="/guest-11/">guest-11</a></li>
        <li><a href="/guest-12/">guest-12</a></li>
        <li><a href="/guest-13/">guest-13</a></li>
        <li><a href="/guest-14/">guest-14</a></li>
        <li><a href="/guest-15/">guest-15</a></li>
        <li><a href="/guest-16/">guest-16</a></li>
        <li><a href="/guest-17/">guest-17</a></li>
        <li><a href="/guest-18/">guest-18</a></li>
        <li><a href="/guest-19/">guest-19</a></li>
        <li><a href="/guest-20/">guest-20</a></li>
    </ul>
</body>
</html>

各ユーザーの code-server の設定

~/.config/code-server/config.yaml配下に各ユーザーのホームディレクトリ配下にポート別の code-server の設定ファイルが作成されます。

~/.config/code-server/config.yaml
bind-addr: localhost:50443
auth: password
password: qgPwwppzzrkEEmWGgv9nQqL10cpPkg6s
cert: false

動作確認

セットアップが完了したら、ブラウザからアクセスして動作確認を行います。

まず、トップページにアクセスすると、各ユーザーの code-server インスタンスへのリンクが表示されます。

トップページ

各ユーザーのリンクをクリックすると、各ユーザーに対応した code-server のログイン画面が表示されます。CSV ファイルに記録されたパスワードを入力してログインします。

ログイン画面

ログイン後は通常の code-server の環境が利用できます。各ユーザーは独立した環境で作業できます。

code-server画面

code-server の基本的な機能は以下の記事で検証しましたので参考にしてください。

https://dev.classmethod.jp/articles/code-server-multi-user-ec2-review/

まとめ

今回は、EC2 インスタンス 1 台でマルチユーザー対応の code-server 環境を構築しました。Caddy をリバースプロキシとして利用することで、各ユーザー専用の URL を提供し、Let's Encrypt による HTTPS 対応も実現できました。

この構成の主なメリットは以下の通りです。

  • 単一サーバーで複数ユーザーに開発環境を提供できる
  • ユーザーごとに独立した環境を提供できる
  • HTTPS 対応でセキュアな接続が可能

小規模向けの Linux の演習環境として、手軽に導入できて良いのではないでしょうか。

おわりに

code-server はシングルユーザー向けのプロダクトなこともあり、そのままではマルチユーザーで使うには難しいことは以前検証して把握していました。

EC2 1 台で複数ユーザーが利用可能な Web IDE 環境を code-server で実現できるのか試してみた | DevelopersIO

その後、HTTPS 対応のためにリバースプロキシを経由する方法を検証しました。

Caddy で簡単構築!code-server の HTTPS 環境セットアップ | DevelopersIO

リバースプロキシを配置してアクセスできるならやりようがあるではないかということで今回の検証に至りました。複数ユーザーアクセス時のメモリ消費量が気がかりですので、負荷かけて試したいところです。

code-server の代わりに JupyterHub の活用も検討しました。

https://dev.classmethod.jp/articles/jupyterhub-on-aws-for-linux-training/

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.