「自宅や外出先からブラウザだけでLinux開発環境にアクセスしたい」そんな要件を満たすため、WSL2 + Apache Guacamole + Tailscale + code-server を組み合わせた構成を構築しました。
クライアント側に専用アプリは一切不要で、ブラウザさえあればどこからでも VS Code ライクな開発環境をフル操作できます。本記事では AlmaLinux 9 をベースに、ゼロから同じ環境を再現できるよう設定値・コマンド・構成図をまとめています。
目次
- システム全体概要
- WSL2 デスクトップ環境 (xrdp + XFCE4)
- Apache Guacamole (ブラウザ RDP ゲートウェイ)
- Tailscale (セキュア VPN・サービス公開)
- code-server (ブラウザ VS Code)
- 接続フローとクイックリファレンス
1. システム全体概要
1-1. アーキテクチャ概要
Windows ホスト上の WSL2 (AlmaLinux 9) をベースとし、複数のサービスを組み合わせることでブラウザのみでリモート開発が行えるシステムを構成しています。
1-2. 接続の流れ(通信フロー詳細)
- 接続要求:ユーザーがブラウザで Guacamole にアクセス
-
プロトコル変換:
guacamoleコンテナがguacdに RDP 接続を依頼 -
トンネリング:
guacdが Tailscale ネットワーク (MagicDNS 名等) を通じて WSL2 の 3389 番ポートに到達 -
セッション管理:WSL2 の
xrdpが接続を受け、sesmanがユーザー認証を行う -
描画開始:認証成功後、
startwm.shが実行され XFCE デスクトップが起動 - 画面転送:Xorg/Xvnc の画面データが RDP プロトコルとして Guacamole に送られ、ブラウザに描画される
1-3. コンポーネント一覧
| コンポーネント | 役割・概要 |
|---|---|
| WSL2 + AlmaLinux 9 | Windows 上で動作する Linux 環境。全サービスのベース。 |
| XFCE4 + xrdp | WSL2 上の GUI デスクトップ。RDP プロトコルで外部から接続可能。 |
| Apache Guacamole | ブラウザから RDP/VNC/SSH へ接続するクライアントレスゲートウェイ。Docker Compose で動作。 |
| Tailscale | WireGuard ベースの VPN。セキュアなリモートアクセスと内部サービスの外部公開を担う。 |
| code-server | VS Code をブラウザで動作させる IDE サーバー。WSL2 上でポート 4200 で待機。 |
1-4. 重要ファイル・ディレクトリ一覧
Guacamole 関連 (Docker)
| パス | 内容 |
|---|---|
/root/guacamole/ |
Compose プロジェクトルート |
/root/guacamole/docker-compose.yml |
コンテナ定義 |
/root/guacamole/.env |
環境変数(Tailscale の Auth Key 等) |
/root/guacamole/data/ |
PostgreSQL のデータ永続化ディレクトリ |
/root/guacamole/init/initdb.sql |
初期データベーススキーマ |
xrdp / WSL 関連 (Host)
| パス | 内容 |
|---|---|
/etc/xrdp/xrdp.ini |
xrdp メイン設定 |
/etc/xrdp/sesman.ini |
セッションマネージャー設定 |
/etc/xrdp/startwm.sh |
セッション起動スクリプト(XFCE 強制起動の核心) |
/home/<YOUR_USERNAME>/.xsession |
ユーザー別起動設定 |
/var/log/xrdp.log |
RDP 通信ログ |
/var/log/xrdp-sesman.log |
セッション起動ログ |
2. WSL2 デスクトップ環境 (xrdp + XFCE4)
2-1. 構成コンポーネント
- xrdp:Windows RDP プロトコルを受け付けるサーバー (ポート 3389)
- xorgxrdp:xrdp が X11 画面を描画するためのドライバ
- XFCE4:軽量デスクトップ環境
- D-Bus:プログラム間通信バス(WSL2 でのデスクトップ安定動作に必須)
2-2. 構築手順
① パッケージのインストール
# システムの更新
sudo dnf update -y
# EPEL リポジトリの有効化(xrdp / XFCE4 に必要)
sudo dnf install -y epel-release
# xrdp と XFCE4 のインストール
sudo dnf install -y xrdp xorgxrdp xfce4-session xfce4-settings xfce4-panel xfconf dbus-x11
② systemd の有効化 (/etc/wsl.conf)
systemd を有効にすることで service / systemctl コマンドが使えるようになります。
# /etc/wsl.conf を編集
sudo nano /etc/wsl.conf
# 以下を追記
[boot]
systemd=true
# WSL2 を再起動して設定を反映
wsl --shutdown
③ xrdp メイン設定 (/etc/xrdp/xrdp.ini)
[Globals]
address=0.0.0.0 ; 全インターフェースで接続許可
security_layer=negotiate ; TLS と RDP の自動交渉(接続エラー防止)
crypt_level=high ; 暗号化レベルを高に設定
[Xvnc]
ip=127.0.0.1 ; VNC サーバー接続先をローカルに固定("no IP set" エラー回避)
port=-1 ; ポートを動的割り当て
④ セッション起動スクリプト (/etc/xrdp/startwm.sh)
⚠️ 「Oh no! Something has gone wrong.」エラーを防ぐための核心的な設定です。
#!/bin/sh
# 既存セッション情報をクリア (WSL2 特有の干渉を防止)
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
# XFCE4 を D-Bus セッション経由で起動
# PolicyKit や各種アプレットが正しく動作するために必要
exec dbus-run-session startxfce4
# 実行権限を付与
sudo chmod +x /etc/xrdp/startwm.sh
⑤ ユーザー別 .xsession の設定
echo 'exec dbus-run-session startxfce4' > /home/<YOUR_USERNAME>/.xsession
chmod +x /home/<YOUR_USERNAME>/.xsession
⑥ xrdp サービスの有効化・起動
# OS 起動時に自動起動するよう有効化
sudo systemctl enable xrdp
# サービスを起動
sudo systemctl start xrdp
# 起動確認
sudo systemctl status xrdp
2-3. 運用・管理コマンド
# xrdp の起動 / 停止 / 再起動
sudo service xrdp start
sudo service xrdp stop
sudo service xrdp restart
# 状態確認
sudo service xrdp status
# 3389 番ポートの待受確認
sudo ss -lnpt | grep 3389
2-4. ログファイルの場所
| ログファイル | 用途 |
|---|---|
/var/log/xrdp.log |
接続の確立やプロトコルエラーの確認 |
/var/log/xrdp-sesman.log |
ユーザー認証やプロセス起動失敗の確認 |
/home/<YOUR_USERNAME>/.xorgxrdp.10.log |
画面描画・グラフィック関連のエラー確認 |
# リアルタイムログ確認
tail -f /var/log/xrdp.log
tail -f /var/log/xrdp-sesman.log
2-5. トラブルシューティング
「Oh no! Something has gone wrong.」エラー
- 原因:GNOME など不要なデスクトップ環境が干渉しているか、D-Bus の起動失敗
-
対処:
startwm.shを上記の通りに修正後、WSL2 を再起動
wsl --shutdown
# その後 WSL2 を再起動して xrdp を起動
sudo service xrdp start
「Upstream error」または接続直後に切断される
-
原因:xrdp サービスが停止しているか、
xrdp.iniの IP 設定が不適切 -
対処:xrdp を再起動し、設定ファイルの
address=0.0.0.0を確認
sudo service xrdp restart
「Login failed」エラー
-
原因:パスワードの誤り、またはユーザーが
tsusersグループに未登録 - 対処:パスワードを再設定する
sudo passwd <YOUR_USERNAME>
ブラウザコンソールで「TypeError: can't access property 'bind'」
- 原因:Guacamole の音声転送機能とブラウザの相性
-
対処:Guacamole の接続設定で「Disable audio」にチェックを入れる(
disable-audio=true)
3. Apache Guacamole (ブラウザ RDP ゲートウェイ)
3-1. システムアーキテクチャ
Docker Compose により、相互に連携する 3 つのコンテナで構成されます。
3-2. 構築手順
① ディレクトリの準備
mkdir -p /root/guacamole/init
mkdir -p /root/guacamole/data
cd /root/guacamole
② initdb.sql の生成
# Guacamole スキーマ初期化 SQL を生成
docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --postgresql \
> ./init/initdb.sql
③ docker-compose.yml の作成
/root/guacamole/docker-compose.yml として以下を保存します。
パスワード類は .env ファイルで管理することを推奨します。
services:
guacd:
image: guacamole/guacd
container_name: guacd
restart: always
postgres:
image: postgres:15
container_name: guacd-db
environment:
POSTGRES_PASSWORD: <YOUR_DB_PASSWORD>
POSTGRES_DB: guacamole_db
POSTGRES_USER: guacamole_user
volumes:
- ./data:/var/lib/postgresql/data
- ./init:/docker-entrypoint-initdb.d
guacamole:
image: guacamole/guacamole
container_name: guacamole
depends_on:
- guacd
- postgres
environment:
GUACD_HOSTNAME: guacd
POSTGRESQL_HOSTNAME: postgres
POSTGRESQL_DATABASE: guacamole_db
POSTGRESQL_USER: guacamole_user
POSTGRESQL_PASSWORD: <YOUR_DB_PASSWORD>
ports:
- "8080:8080"
restart: always
④ コンテナの起動
cd /root/guacamole
docker compose up -d
# 起動確認
docker compose ps
3-3. 認証・データベース情報
| 項目 | 値 |
|---|---|
| DB 名 | guacamole_db |
| DB ユーザー | guacamole_user |
| DB パスワード | <YOUR_DB_PASSWORD> |
| DB ホスト(Docker 内部) | postgres |
3-4. RDP 接続設定パラメータ
接続名「wsl」(Connection ID: 1) に設定されている DB 内パラメータです。
| パラメータ名 | 設定値 | 目的・説明 |
|---|---|---|
| hostname | 172.19.0.1 |
Docker ブリッジのゲートウェイ(WSL2 ホスト) |
| port | 3389 |
標準 RDP ポート |
| username | <YOUR_USERNAME> |
WSL2 内のログインユーザー |
| password | <YOUR_PASSWORD> |
RDP 認証用パスワード |
| security | any |
xrdp との互換性向上のための自動交渉 |
| ignore-cert | true |
自己署名証明書の警告を無視 |
| disable-audio | true |
JS エラー回避・動作軽量化 |
| clipboard-encoding | UTF-8 |
日本語等マルチバイト文字対応 |
3-5. 運用・管理コマンド
# コンテナの死活確認
docker compose ps
# ログの確認(接続失敗時の調査)
docker logs -f guacamole
docker logs -f guacd
# 登録済み接続の一覧表示
docker exec -it guacd-db psql -U guacamole_user -d guacamole_db \
-c "SELECT connection_name, protocol FROM guacamole_connection;"
# 接続 ID:1 のパラメータ詳細表示
docker exec -it guacd-db psql -U guacamole_user -d guacamole_db \
-c "SELECT parameter_name, parameter_value FROM guacamole_connection_parameter WHERE connection_id = 1;"
# guacd コンテナから WSL2 の RDP ポートへの疎通確認
docker exec -it guacd nc -zv 172.19.0.1 3389
3-6. データ永続化
- すべてのデータは
/root/guacamole/dataディレクトリに保存されます。 - バックアップはこのディレクトリを丸ごと保存してください。
💡 WSL2 の IP が変わった場合は
hostnameパラメータ (172.19.0.1) を DB で再確認してください。
4. Tailscale (セキュア VPN・サービス公開)
4-1. 基本情報
| 項目 | 値 |
|---|---|
| MagicDNS ドメイン | <YOUR_TAILNET>.ts.net |
| 管理ユーザー | <YOUR_EMAIL> |
| Auth Key 保存場所 | /root/guacamole/.env |
4-2. インストール手順
# Tailscale のインストール
curl -fsSL https://tailscale.com/install.sh | sh
# Tailscale の起動・認証
sudo tailscale up
# Docker ネットワーク経路を広報しつつ起動(推奨)
sudo tailscale up --advertise-routes=172.19.0.0/16 --accept-dns=false
💡 管理コンソール (https://login.tailscale.com/admin/machines) から経路を「Approve」する必要があります。
4-3. 公開サービス設定
経路広報 (Advertise Routes)
Docker コンテナネットワークに Tailnet 内の他デバイスから直接アクセスできるよう経路を広報します。
sudo tailscale up --advertise-routes=172.19.0.0/16
Tailscale Serve — SSH ポートの変更公開
# SSH (ポート 22) を Tailnet 内のポート 10000 で公開
tailscale serve tcp:10000 tcp://localhost:22
code-server の公開(オプション)
# code-server (ポート 4200) を Tailnet 内に HTTP:80 で公開
tailscale serve http:80 http://localhost:4200
4-4. 公開サービス一覧
| サービス | 設定内容 |
|---|---|
| SSH アクセス | 内部: localhost:22 → tcp:10000 で Tailnet 内公開 |
| code-server(任意) | 内部: 127.0.0.1:4200 → http:80 で Tailnet 内公開可能 |
4-5. DNS 設定
WSL2 の DNS 不整合を防ぐため、Tailscale による /etc/resolv.conf の上書きを無効化します。
tailscale set --accept-dns=false
4-6. 確認・運用コマンド
# 全体の接続状態と他ノードの確認
tailscale status
# 自身の Tailscale IP アドレス確認
tailscale ip -4
# 広報経路 (Routes) の確認
tailscale status --routes
# Funnel / Serve の状況確認
tailscale funnel status
tailscale serve status
# 接続性テスト (ping)
tailscale ping <ノード名 or IP>
# ネットワーク状態 (DERP/STUN) の診断
tailscale netcheck
# 経路広報をリセットして再設定
sudo tailscale up --reset --advertise-routes=172.19.0.0/16
5. code-server (ブラウザ VS Code)
5-1. システム概要
| 項目 | 設定値 |
|---|---|
| バージョン | 4.121.0 |
| 待機ポート | 4200 (TCP) |
| バインドアドレス |
127.0.0.1(localhost のみ) |
| 認証方式 | パスワード認証 |
| デフォルトワークスペース | /root/my-app |
5-2. アーキテクチャ
code-server は WSL2 上でローカルにのみ待機し、外部からのアクセスは RDP(Guacamole 経由)または Tailscale Serve のいずれかを通じて行います。
5-3. インストール手順
# code-server のインストール(公式スクリプト)
curl -fsSL https://code-server.dev/install.sh | sh
# バージョン確認
code-server --version
5-4. 設定ファイル
メイン設定 (~/.config/code-server/config.yaml)
bind-addr: 127.0.0.1:4200 # localhost のみアクセス許可
auth: password # パスワード認証を有効化
password: <YOUR_CODE_SERVER_PASSWORD> # 任意の強固なパスワードを設定
cert: false # SSL/TLS はプロキシ経由で処理
設定・データの格納場所
| パス | 内容 |
|---|---|
/root/.config/code-server/ |
メイン設定ファイル |
/root/.local/share/code-server/extensions/ |
インストール済み VS Code 拡張機能 |
/root/.local/share/code-server/User/ |
ユーザー設定 (settings.json) / キーバインド |
/root/.local/share/code-server/coder.json |
最後に開いたフォルダ等のメタデータ |
/root/my-app/ |
デフォルトのプロジェクトワークスペース |
5-5. アクセス方法
方法 A: RDP 経由(推奨)
- Tailscale 経由で Guacamole にログイン
- WSL2 デスクトップを開く
- デスクトップ内のブラウザから
http://localhost:4200にアクセス
方法 B: Tailscale Serve で直接公開
# ポート 4200 を Tailnet 内 HTTP:80 で公開
tailscale serve http:80 http://localhost:4200
# アクセス URL(例)
# http://<YOUR_TAILNET>.ts.net
5-6. 管理・運用コマンド
# バックグラウンドで起動
nohup code-server &
# プロセス確認
ps aux | grep code-server
# 停止
pkill -f code-server
5-7. パスワードの変更
# config.yaml を編集して password の値を書き換える
nano ~/.config/code-server/config.yaml
# code-server を再起動
pkill -f code-server && nohup code-server &
5-8. バックアップ対象
| パス | 内容 |
|---|---|
/root/.config/code-server/ |
設定ファイル |
/root/.local/share/code-server/extensions/ |
拡張機能 |
/root/my-app/ |
プロジェクトソースコード |
6. 接続フローとクイックリファレンス
6-1. 標準的なアクセスフロー
6-2. システム起動チェックリスト
| チェック項目 | 確認コマンド |
|---|---|
| WSL2 起動確認 | wsl --list --running |
| xrdp 稼働確認 | sudo service xrdp status |
| xrdp ポート待受確認 | sudo ss -lnpt | grep 3389 |
| Docker コンテナ確認 |
docker compose ps(/root/guacamole で実行) |
| Tailscale 接続確認 | tailscale status |
| code-server 稼働確認 | ps aux | grep code-server |
| RDP 疎通確認 | docker exec -it guacd nc -zv 172.19.0.1 3389 |
6-3. ネットワーク設定サマリ
| アドレス / ポート | 説明 |
|---|---|
172.19.0.1 |
Docker ブリッジゲートウェイ(WSL2 ホスト) |
172.19.0.0/16 |
Docker ネットワーク帯域(Tailscale で広報) |
127.0.0.1:4200 |
code-server リスニングアドレス |
0.0.0.0:3389 |
xrdp RDP リスニングアドレス |
0.0.0.0:8080 |
Guacamole Web UI |
<YOUR_TAILNET>.ts.net |
Tailscale MagicDNS ドメイン |
6-4. 全サービス一括起動スクリプト
WSL2 起動後に全サービスをまとめて起動するスクリプトの例です。
#!/bin/bash
# start_all.sh — WSL2 全サービス起動スクリプト
echo '[1/4] xrdp を起動します...'
sudo service xrdp start
echo '[2/4] Guacamole コンテナを起動します...'
cd /root/guacamole && docker compose up -d
echo '[3/4] Tailscale を起動します...'
sudo tailscale up --advertise-routes=172.19.0.0/16 --accept-dns=false
echo '[4/4] code-server を起動します...'
nohup code-server > /tmp/code-server.log 2>&1 &
echo '=== 全サービスの起動が完了しました ==='
echo "Guacamole: http://$(tailscale ip -4):8080/guacamole"
echo 'code-server: RDP 経由で http://localhost:4200'
⚠️ このスクリプトはサービスの起動のみを行います。Tailscale の初回認証や Docker イメージのプルは事前に完了させておいてください。
資料作成日: 2026年05月25日 | 本資料は WSL2 + AlmaLinux 9 環境での構築実績をもとに作成しています。