NENEKOLAB

WindowsをLinuxに変えて、VPNで繋げてみた

大学の時に使っていたDELLのノートPCが、Windows 10のまま眠っていた。

メモリは8GB。Windows 11にしても重くなるだけだし、かといって捨てるのはもったいない。

だったら Ubuntu Serverを入れて、自宅のバックエンド実験サーバーにしてしまおう、というのがこの記事の話。

メインのMacに開発ツールやDBを全部入れると、環境がぐちゃぐちゃになる。

それを避けるために、古いPCをLinuxサーバー化して「壊してもいい箱」として運用する。

VPN(Tailscale)で外からも安全に触れるようにして、Docker上にPostgreSQLなどの実験環境を立てるところまでをまとめた。

Part 1:Ubuntu Serverのインストールと初期設定

なぜWindows → Ubuntu Server なのか

サーバー用途で旧PCを再利用するなら、Ubuntu Serverが合理的な選択肢になる。

  • 軽い:GUIがないぶんリソース消費が小さく、8GB RAMでも余裕で動く
  • アップデートを自分で制御できる:Windowsの強制アップデートによる事故がない
  • リモート管理が前提の設計:SSHで完結する
  • バックエンドとの相性が良い:PostgreSQL、Python、Dockerなどが自然に動く

ブータブルUSBの作成

インストールにはUSBメモリ(8GB以上)が必要。

  1. ubuntu.com から Ubuntu Server 24.04 LTS のISOをダウンロード
  2. balenaEtcher(etcher.balena.io)でISOをUSBに書き込む
  3. USBの中身は上書きされるので、必要なデータは事前にバックアップ

BIOS設定の変更

DELLの場合、起動時に F2連打 でBIOSに入れる。

  • Secure BootAudit Mode(実質Disabled)に変更
  • Boot Order → USBを最優先に設定
  • 保存して再起動

インストール時の設定ポイント

項目設定値
言語English(Server版は日本語を選べない)
ストレージUse an entire disk
LVM有効
暗号化(LUKS)無効
Ubuntu ProSkip
OpenSSH Serverインストール必須

サーバー名とユーザー名は任意のものを設定する。

インストール完了後、「Reboot Now」でUSBを抜いて再起動。


ネットワーク設定:最初の「鶏と卵」問題

Ubuntu Serverをインストールした直後、Wi-Fiを使うには wpasupplicant が必要だが、そのインストールにはネット接続が要るという問題にぶつかる。

解決策はシンプルで、まず有線LANでルーターに直結する

① 有線LANをnetplanで有効化

sudo nano /etc/netplan/01-netcfg.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp1s0:         # ← デバイス名は `ip a` で確認
      dhcp4: true
      dhcp6: false
sudo chmod 600 /etc/netplan/01-netcfg.yaml
sudo netplan apply

ip a でIPv4アドレスが取得できていればOK。

② wpasupplicantをインストールしてWi-Fiを設定

sudo apt update && sudo apt install -y wpasupplicant

同じnetplanファイルにWi-Fiの設定を追加する。

wifis:
  wlo1:           # ← デバイス名は `ip a` で確認
    dhcp4: true
    access-points:
      "<SSID名>":
        password: "<パスワード>"
sudo netplan apply

Wi-FiでIPが取れたら、有線を抜いても大丈夫。

注意:netplanのYAMLはインデントに厳しい。スペースがずれるとエラーになる。また、設定ファイルは chmod 600 でパーミッションを絞っておくこと。


SSH接続と鍵認証

サーバーのIPが分かったら、別のPC(Macなど)からSSHで入る。

ssh <ユーザー>@<サーバーのローカルIP>

毎回パスワードを打つのは面倒なので、鍵認証に切り替える。

# クライアント側で鍵を生成
ssh-keygen -t ed25519 -C "my-server"

# 公開鍵をサーバーに送る
ssh-copy-id <ユーザー>@<サーバーのローカルIP>

Macの場合はキーチェーンに登録しておくと便利。

ssh-add --apple-use-keychain ~/.ssh/id_ed25519

ノートPCサーバーの落とし穴:蓋を閉じるとスリープする

ノートPCをサーバー転用すると、蓋を閉じた瞬間にスリープして接続が切れる。

/etc/systemd/logind.conf を編集して無効化する。

sudo nano /etc/systemd/logind.conf

以下の行のコメントを外して ignore に変更:

HandleLidSwitch=ignore
sudo systemctl restart systemd-logind

これでサーバーは蓋を閉じたまま稼働し続ける。

Part 2:Tailscale VPNで外から安全にアクセスする

VPNの2種類を整理する

「VPN」と聞くと、SurfsharkやNordVPNのような「IP秘匿サービス」を思い浮かべるかもしれないが、今回使いたいのはそれとは目的が違うVPN

種類目的イメージ
商用VPN(Surfshark等)IPアドレスの秘匿、地域制限の回避変装して街を歩く
Tailscale自分のデバイス同士をプライベートにつなぐ自分の部屋同士を秘密の通路でつなぐ

Tailscaleは後者。自宅にいなくても、カフェから自宅サーバーにまるで隣にあるかのようにアクセスできるようにするのが目的。


Tailscaleの仕組み

  • WireGuardベースのメッシュ型VPN
  • 中央サーバーを経由せず、デバイス同士がP2Pで直接通信するため高速
  • インストールすると各デバイスに 100.x.y.z という専用のIPアドレスが付与される
  • この専用IP宛ての通信だけが暗号化トンネルを通る。普段のネット通信には影響しない

つまり、PCからサーバーの Tailscale IP にアクセスすれば暗号化された安全な経路を通り、通常のWebブラウジングはいつも通り。全通信を迂回させる商用VPNとはここが違う


導入手順

サーバー側(Ubuntu)

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
tailscale status

tailscale up を実行するとログイン用のURLが表示されるので、ブラウザで開いて認証する。

クライアント側(Mac / Windows / スマホ)

公式サイトまたはApp Storeからアプリをインストールして、同じアカウントでログインするだけ

これで、サーバーとクライアントが同じ Tailscale ネットワーク(tailnet)に入る。


おすすめの追加設定

MagicDNS

管理画面(login.tailscale.com/admin/dns)でMagicDNSを有効にすると、IPの代わりにホスト名でアクセスできるようになる。

Tailscale Funnel(一時的なWeb公開)

開発中のアプリを一時的に外部に見せたい場合:

sudo tailscale funnel 3000

Tailscaleを入れていない人でもブラウザでアクセスできるURLが発行される。

止めたい時は:

sudo tailscale funnel --reset

ただしFunnelはHTTPS(443)のみで帯域制限もあるため、数人に見せる程度の用途向き。本格的な公開にはCloudflare TunnelやVPSへの移管を検討する。


SSH接続をTailscale経由に切り替える

Tailscaleを導入したら、SSHの接続先をローカルIPからTailscale IPに変更する。

ssh <ユーザー>@<サーバーのTailscale IP>

これで、自宅の外からでもサーバーにSSH接続できるようになる。

ルーターのポート開放は不要で、Tailscaleの暗号化トンネルを通るのでセキュリティも高い。


VSCode Remote-SSHとの組み合わせ

Tailscale + VSCode Remote-SSH の組み合わせは非常に快適。

  1. VSCodeに「Remote - SSH」拡張をインストール
  2. Ctrl+Shift+P(Macなら Cmd+Shift+P)→ 「Remote-SSH: Connect to Host」
  3. <ユーザー名>@<サーバーのTailscale IP> を入力
  4. 鍵認証でログイン

接続すると、VSCodeの拡張機能は自動的にローカル用とサーバー用に分かれる

  • ローカル側:テーマ、キーバインドなどUI系
  • サーバー側:Python、Docker、GitLensなど開発系

つまり、手元のPCには「VSCodeとブラウザ」だけあれば開発できる状態になる。

Python、Node.js、Dockerなどのランタイムは全部サーバー側に置けばいい。

Part 3:Dockerで実験環境を作る

Dockerとは

Dockerは、アプリケーションとその実行環境(OS、ライブラリ、設定ファイルなど)をまとめて1つの 「コンテナ」 として動かす技術。

1台のサーバー上に、互いに干渉しない独立した環境を複数作れる。


DockerとPython仮想環境(venv)の違い

比較項目Dockervenv
隔離のレベルOS・ライブラリごと丸ごとPythonパッケージだけ
用途本番アプリ、DB、APIなど軽い実験、スクリプト
重さやや重い軽い

ちょっとした実験やスクリプトなら venv で十分。本番寄りのサービスや複数言語が絡むならDockerを使う。


コンテナ分割の考え方:「機能単位」で分ける

コンテナは「アプリ単位」ではなく、機能(役割)ごとに分けるのが原則。

たとえば「ダッシュボードアプリ」を作る場合:

  • フロントエンド(Next.js)→ 1コンテナ
  • バックエンドAPI(FastAPI)→ 1コンテナ
  • データベース(PostgreSQL)→ 1コンテナ

こう分けるメリットは3つ。

  • 障害の隔離:DBが壊れてもフロントは動く
  • 個別アップデート:PostgreSQLだけバージョンを上げたい時、そのコンテナだけ差し替え
  • 再利用:PostgreSQLは複数のアプリで共有できる

ポート番号の管理ルール

Dockerでは各コンテナにポートを割り当てて区別する。

ルールを決めておかないと衝突して事故るので、番号帯で分けるのがおすすめ。

番号帯用途
3000番台フロントエンド(Next.js、Reactなど)
5000番台管理ツール(pgAdminなど)
8000番台バックエンドAPI(FastAPI、Expressなど)
9000番台モニタリング(Grafana、Prometheusなど)

同じ種類のアプリが複数ある場合は、末尾をずらす(8000、8001、8002…)。

使えるポートは1024〜65535。1024未満はシステム予約なので避ける。


Dockerのインストール

sudo apt update
sudo apt install docker.io docker-compose-v2 -y
sudo usermod -aG docker $USER

usermod の後は一度ログアウトして再ログインが必要。

再ログイン後に groups コマンドで docker が含まれていることを確認する。


PostgreSQL + pgAdmin をDocker Composeで立てる

ディレクトリを作成

mkdir -p ~/docker/postgres
cd ~/docker/postgres

docker-compose.yml を作成

services:
  db:
    image: postgres:16
    restart: always
    environment:
      POSTGRES_USER: <DBユーザー名>
      POSTGRES_PASSWORD: <DBパスワード>
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data

  pgadmin:
    image: dpage/pgadmin4
    restart: always
    environment:
      PGADMIN_DEFAULT_EMAIL: <メールアドレス>
      PGADMIN_DEFAULT_PASSWORD: <pgAdminパスワード>
    ports:
      - "5050:80"

volumes:
  pgdata:

各項目の意味

項目意味
image使用するDockerイメージ(Docker Hubから自動取得)
restart: alwaysサーバー再起動時にコンテナも自動起動
environmentコンテナに渡す環境変数
ports: "5432:5432"ホスト側ポート:コンテナ内ポート のマッピング
volumesデータの永続化(コンテナを消してもデータが残る)

起動・確認・停止

docker compose up -d       # バックグラウンドで起動
docker compose ps          # 起動中のコンテナ一覧
docker compose logs -f     # ログをリアルタイム表示
docker compose down        # 全コンテナ停止

pgAdminからPostgreSQLに接続する

ブラウザで http://<サーバーのTailscale IP>:5050 にアクセスし、設定したメールアドレスとパスワードでログイン。

「Add New Server」から以下を入力:

  • Hostdb(docker-compose.yml内のサービス名で名前解決される)
  • Port5432
  • Username / Password:docker-compose.ymlで設定した値

pgAdminはWebアプリなので、Tailscale経由ならスマホやiPadからでもアクセスできる。ただし画面はPC向けなので、スマホでは使いづらい。


データ永続化について

volumes で指定したデータは、コンテナを削除して作り直しても消えない。

ただし、PostgreSQLのメジャーバージョンを変える場合(例:16→17)はデータ形式が変わる可能性があるため、バックアップしてから移行すること。


次のステップ:pgvector

PostgreSQLにベクトル検索機能を追加したい場合は pgvector を導入する。

docker-compose.yml のイメージを差し替えるだけで済む。

# 変更前
image: postgres:16

# 変更後
image: pgvector/pgvector:pg16

同じPostgreSQL 16ベースなので、既存データはそのまま引き継がれる。


まとめ:運用の5つのルール

この構成で事故らないために押さえておくポイント。

  1. 外部アクセスはTailscale経由のみ:ルーターのポート開放は不要
  2. 開発作業はRemote-SSH:手元にランタイムを入れず、サーバー側で完結させる
  3. コンテナは機能単位で分ける:DB、API、フロントをそれぞれ独立に
  4. ポート番号はルール化:3000/5000/8000/9000番台で用途を分類
  5. データはvolumesで永続化:コンテナ削除=データ消滅にしない

おわりに

メインPCに全部入れても動くが、メイン環境が崩れた時の回復コストは高い。

古いPCをLinuxサーバーとして転生させておけば、

  • 失敗してもサーバーだけ吹き飛ばせる
  • 実験用のバックエンドを継続的に積み上げていける
  • 外出先からも安全に触れる

という、地味だけど長期的に強い基盤になる。

次はこのサーバー上にFastAPIでAPIを立てたり、Grafana/Prometheusで監視を入れたり、pgvectorでベクトル検索を試したりと、拡張の余地はいくらでもある。

ゆうか

化学・IT・AIについて、学んだことをつらつらと。