0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

steam://connect がDNS名を使えないので Cloudflare WorkersでDynamic DNS対応した

0
Posted at

自宅で 7 Days to Die の Dedicated Server を運用しています。

Steamには、ブラウザからゲームサーバーへ接続できる steam://connect というURLがあります。

steam://connect/<IPアドレス>:<ポート>

例えば次のように使えます。

steam://connect/203.0.113.10:26900

便利なのですが、Steamの仕様では現在DNS名を指定できません。

Steam browser protocol

steam://connect/<IP>[:<port>][/<password>]

Note: DNS names no longer work here

自宅サーバーでは固定IPではなく、Dynamic DNSを使っていることがあります。

Dynamic DNSは、変化するグローバルIPアドレスに対して固定のDNS名を割り当てる仕組みです。

そこで、Dynamic DNSをIPアドレスへ変換してから steam://connect にリダイレクトするサービスを Cloudflare Workers で作りました。

作ったもの

サービスはこちらです。

https://connect.steamlink.workers.dev/

URLは次の形式です。

https://connect.steamlink.workers.dev/<DNS名>/<ポート>

例えば、

https://connect.steamlink.workers.dev/example.ddns.net/26900

へアクセスします。

Cloudflare Workersが example.ddns.net を名前解決します。

取得したIPアドレスが 203.0.113.10 なら、次のURLへリダイレクトします。

steam://connect/203.0.113.10:26900

全体の流れは次のとおりです。

これなら自宅のグローバルIPアドレスが変わっても、共有するURLは変更する必要がありません。

Workerのコード

DNSの名前解決には、Cloudflareの DNS over HTTPS を使っています。

DNS over HTTPSは、DNS問い合わせをHTTPSで行う仕組みです。

export default {
  async fetch(request) {
    const url = new URL(request.url);
    const parts = url.pathname.split("/").filter(Boolean);

    // /<hostname>/<port>
    if (parts.length !== 2) {
      return new Response(
        "Usage: /<hostname>/<port>\n",
        { status: 400 }
      );
    }

    const hostname = parts[0];
    const port = Number(parts[1]);

    // hostname validation
    if (
      hostname.length > 253 ||
      !/^[a-zA-Z0-9.-]+$/.test(hostname)
    ) {
      return new Response("Invalid hostname\n", {
        status: 400,
      });
    }

    // port validation
    if (
      !Number.isInteger(port) ||
      port < 1 ||
      port > 65535
    ) {
      return new Response("Invalid port\n", {
        status: 400,
      });
    }

    const dnsUrl =
      "https://cloudflare-dns.com/dns-query" +
      `?name=${encodeURIComponent(hostname)}&type=A`;

    const dnsResponse = await fetch(dnsUrl, {
      headers: {
        Accept: "application/dns-json",
      },
    });

    if (!dnsResponse.ok) {
      return new Response("DNS request failed\n", {
        status: 502,
      });
    }

    const dns = await dnsResponse.json();

    if (dns.Status !== 0) {
      return new Response("DNS lookup failed\n", {
        status: 404,
      });
    }

    const record = dns.Answer?.find(
      (answer) => answer.type === 1
    );

    if (!record) {
      return new Response("IPv4 address not found\n", {
        status: 404,
      });
    }

    const steamUrl =
      `steam://connect/${record.data}:${port}`;

    return new Response(null, {
      status: 302,
      headers: {
        Location: steamUrl,
        "Cache-Control": "no-store",
      },
    });
  },
};

コードは、Cloudflare Workersの管理画面でWorkerを作成して貼り付けるだけです。

サーバーやデータベースは必要ありません。

no-storeを指定する理由

リダイレクトには次のヘッダーを付けています。

Cache-Control: no-store

Dynamic DNSを使う場合、IPアドレスは後から変わる可能性があります。

ブラウザに古いリダイレクト結果を保存されると、変更前のIPアドレスへ接続してしまいます。

そのため、アクセスするたびにDNSを名前解決するようにしています。

7 Days to Dieで使う

例えばDedicated Serverが次の設定だとします。

DNS名: 7dtd.example.net
ポート: 26900

共有するURLはこれだけです。

https://connect.steamlink.workers.dev/7dtd.example.net/26900

DiscordやWebサイトなどにこのURLを貼っておけば、グローバルIPアドレスが変わってもリンクを変更する必要がありません。

ブラウザによっては steam:// を開くときにSteamを起動してよいか確認されます。

まとめ

steam://connect は便利ですが、DNS名を直接指定できません。

Cloudflare Workersを間に入れることで、

という単純な仕組みでDynamic DNSに対応できました。

自宅で 7 Days to Die などのDedicated Serverを動かしている場合には、IPアドレスを意識せず接続URLを共有できるので便利です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?