メインコンテンツにスキップ ナビゲーションにスキップ フッターにスキップ

ネットワーキング

リバースプロキシ、Dockerラベル、TLS証明書、DNS、TCP/UDPポートフォワーディングによるサービスの公開。

ネットワーキング

このページでは、隔離されたDockerデーモン内で実行されているサービスをインターネットからアクセス可能にする方法を説明します。リバースプロキシシステム、ルーティング用Dockerラベル、TLS証明書、DNS、TCP/UDPポートフォワーディングについて説明します。 | Route server running old version | Binary was updated but service not restarted | Happens automatically on provisioning; manual: sudo systemctl restart rediacc-router | | STUN/TURN relay not reachable | Relay addresses cached at startup | Recreate the service after DNS or IP changes so it picks up the new network config |

サービスがループバックIPを取得する仕組みと.rediacc.jsonスロットシステムについては、サービスを参照してください。

仕組み

Rediaccは、外部トラフィックをコンテナにルーティングするために2コンポーネントのプロキシシステムを使用します:

  1. ルートサーバー — すべてのリポジトリDockerデーモンにわたって実行中のコンテナを検出するsystemdサービス。コンテナラベルを検査し、YAMLエンドポイントとして提供されるルーティング設定を生成します。
  2. Traefik — 5秒ごとにルートサーバーをポーリングし、検出されたルートを適用するリバースプロキシ。HTTP/HTTPSルーティング、TLS終端、TCP/UDPフォワーディングを処理します。

フローは以下の通りです:

インターネット → Traefik (ポート 80/443/TCP/UDP)
                   ↓ 5秒ごとにポーリング
               ルートサーバー (コンテナを検出)
                   ↓ ラベルを検査
               Dockerデーモン (/var/run/rediacc/docker-*.sock)

               コンテナ (127.x.x.x ループバックIPにバインド)

適切なラベルをコンテナに追加してrenet composeで起動すると、自動的にルーティング可能になります。手動のプロキシ設定は不要です。

The route server binary is kept in sync with your CLI version. When the CLI updates the renet binary on a machine, the route server is automatically restarted (~1–2 seconds). This causes no downtime, Traefik continues serving traffic with its last known configuration during the restart and picks up the new config on the next poll. Existing client connections are not affected. Your application containers are not touched.

Dockerラベル

ルーティングはDockerコンテナラベルで制御されます。2つのティアがあります:

ティア1:rediacc.*ラベル(自動)

これらのラベルは、サービス起動時にrenet composeによって自動的に注入されます。手動で追加する必要はありません。

ラベル説明
rediacc.service_nameサービスIDmyapp
rediacc.service_ip割り当てられたループバックIP127.0.11.2
rediacc.network_idリポジトリのデーモンID2816
rediacc.repo_nameRepository namemarketing
rediacc.tcp_portsTCP ports the service listens on8080,8443
rediacc.udp_portsUDP ports the service listens on53

コンテナがrediacc.*ラベルのみを持つ場合(traefik.enable=trueなし)、ルートサーバーはリポジトリ名とマシンのサブドメインを使用して自動ルートを生成します:

{service}.{repoName}.{machineName}.{baseDomain}

例えば、マシンserver-1上のmarketingというリポジトリ内でベースドメインexample.commyappというサービスは以下を取得します:

myapp.marketing.server-1.example.com

各リポジトリは独自のサブドメインレベルを持つため、フォークや異なるリポジトリが衝突することはありません。リポジトリをフォークする場合(例:marketing-staging)、フォークは自動的に異なるルートを取得します。カスタムドメインを使用するサービスには、ティア2ラベルまたはrediacc.domainラベルを使用してください。

rediacc.domainによるカスタムドメイン

docker-compose.ymlrediacc.domainラベルを使用して、サービスにカスタムドメインを設定できます。短縮名と完全なドメインの両方がサポートされています:

labels:
  # 短縮名, マシンのbaseDomainを使用してcloud.example.comに解決
  - "rediacc.domain=cloud"

  # 完全なドメイン, そのまま使用
  - "rediacc.domain=cloud.example.com"

ドットを含まない値は短縮名として扱われ、マシンのbaseDomainが自動的に追加されます。ドットを含む値は完全なドメインとして使用されます。

machineNameが設定されている場合、カスタムドメインサービスは2つのルートを取得します:ベースドメイン上のルート(cloud.example.com)とマシンサブドメイン上のルート(cloud.server-1.example.com)。

ティア2:traefik.*ラベル(ユーザー定義)

カスタムドメインルーティング、TLS、特定のエントリポイントが必要な場合は、docker-compose.ymlにこれらのラベルを追加します。traefik.enable=trueを設定すると、ルートサーバーに自動ルートの代わりにカスタムルールを使用するよう指示します。

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
  - "traefik.http.routers.myapp.entrypoints=websecure,websecure-v6"
  - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
  - "traefik.http.services.myapp.loadbalancer.server.port=8080"

これらは標準のTraefik v3ラベル構文を使用します。

ヒント: 内部専用サービス(データベース、キャッシュ、メッセージキュー)にはtraefik.enable=trueを設定しないでください。自動的に注入されるrediacc.*ラベルのみが必要です。

HTTP/HTTPSサービスの公開

前提条件

  1. マシンにインフラストラクチャが設定されていること(マシンセットアップ, インフラストラクチャ設定):

    # 共有資格情報(configごとに一度、すべてのマシンに適用)
    rdc config infra set -m server-1 \
      --cert-email admin@example.com \
      --cf-dns-token your-cloudflare-api-token
    
    # マシン固有の設定
    rdc config infra set -m server-1 \
      --public-ipv4 203.0.113.50 \
      --base-domain example.com
    
    rdc config infra push -m server-1
  2. ドメインのDNSレコードがサーバーのパブリックIPを指していること(下記のDNS設定を参照)。

ラベルの追加

公開したいサービスのdocker-compose.ymltraefik.*ラベルを追加します:

services:
  myapp:
    image: myapp:latest
    environment:
      - LISTEN_ADDR=${MYAPP_IP}:8080
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
      - "traefik.http.routers.myapp.entrypoints=websecure,websecure-v6"
      - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
      - "traefik.http.services.myapp.loadbalancer.server.port=8080"

  database:
    image: postgres:17
    command: ["-c", "listen_addresses=${DATABASE_IP}"]
    # traefikラベルなし, データベースは内部専用
ラベル目的
traefik.enable=trueこのコンテナのカスタムTraefikルーティングを有効化
traefik.http.routers.{name}.ruleルーティングルール, 通常はHost(\domain`)`
traefik.http.routers.{name}.entrypointsリッスンするポート:websecure(HTTPS IPv4)、websecure-v6(HTTPS IPv6)
traefik.http.routers.{name}.tls.certresolver証明書リゾルバ, 自動Let’s Encryptにはletsencryptを使用
traefik.http.services.{name}.loadbalancer.server.portコンテナ内でアプリケーションがリッスンするポート

ラベル内の{name}は任意の識別子です。関連するルーター/サービス/ミドルウェアラベル間で一貫している必要があります。

注意: rediacc.*ラベル(rediacc.service_namerediacc.service_iprediacc.network_id)はrenet composeによって自動的に注入されます。composeファイルに追加する必要はありません。

TLS証明書

TLS証明書はCloudflare DNS-01チャレンジを使用してLet’s Encrypt経由で自動的に取得されます。資格情報はconfigごとに一度設定します(すべてのマシンで共有):

rdc config infra set -m server-1 \
  --cert-email admin@example.com \
  --cf-dns-token your-cloudflare-api-token

自動ルートはサービスごとの証明書の代わりにリポジトリサブドメインレベルのワイルドカード証明書*.marketing.server-1.example.com)を使用します。これによりLet’s Encryptのレート制限を回避し、起動を高速化します。カスタムドメインルートはマシンレベルのワイルドカード(*.server-1.example.com)を使用します。

traefik.http.routers.{name}.tls.certresolver=letsencryptを持つティア2ルートでは、ルートのホスト名に基づいてワイルドカードドメインSANが自動的に注入されます。

Cloudflare DNS APIトークンには、保護したいドメインに対するZone:DNS:Edit権限が必要です。

TCP/UDPポートフォワーディング

非HTTPプロトコル(メールサーバー、DNS、外部公開するデータベース)には、TCP/UDPポートフォワーディングを使用します。

ステップ1:ポートの登録

インフラストラクチャ設定時に必要なポートを追加します:

rdc config infra set -m server-1 \
  --tcp-ports 25,143,465,587,993 \
  --udp-ports 53

rdc config infra push -m server-1

これによりtcp-{port}udp-{port}という名前のTraefikエントリポイントが作成されます。

Plain TCP Example (Database)

To expose a database externally without TLS passthrough (Traefik forwards raw TCP):

services:
  postgres:
    image: postgres:17
    command: -c listen_addresses=${POSTGRES_IP} -c port=5432
    labels:
      - "traefik.enable=true"
      - "traefik.tcp.routers.mydb.entrypoints=tcp-5432"
      - "traefik.tcp.routers.mydb.rule=HostSNI(`*`)"
      - "traefik.tcp.services.mydb.loadbalancer.server.port=5432"

Port 5432 is pre-configured (see below), so no --tcp-ports setup is needed.

Security note: Exposing a database to the internet is a risk. Use this only when remote clients need direct access. For most setups, keep the database internal and connect through your application.

ポートの追加または削除後は、プロキシ設定を更新するために常にrdc config infra pushを再実行してください。

ステップ2:TCP/UDPラベルの追加

composeファイルでtraefik.tcp.*またはtraefik.udp.*ラベルを使用します:

services:
  mail-server:
    image: ghcr.io/docker-mailserver/docker-mailserver:latest
    labels:
      - "traefik.enable=true"

      # SMTP (ポート 25)
      - "traefik.tcp.routers.mail-smtp.entrypoints=tcp-25"
      - "traefik.tcp.routers.mail-smtp.rule=HostSNI(`*`)"
      - "traefik.tcp.routers.mail-smtp.service=mail-smtp"
      - "traefik.tcp.services.mail-smtp.loadbalancer.server.port=25"

      # IMAPS (ポート 993), TLSパススルー
      - "traefik.tcp.routers.mail-imaps.entrypoints=tcp-993"
      - "traefik.tcp.routers.mail-imaps.rule=HostSNI(`mail.example.com`)"
      - "traefik.tcp.routers.mail-imaps.tls.passthrough=true"
      - "traefik.tcp.routers.mail-imaps.service=mail-imaps"
      - "traefik.tcp.services.mail-imaps.loadbalancer.server.port=993"

主要な概念:

  • HostSNI(\*`)` は任意のホスト名にマッチ(プレーンSMTPなどSNIを送信しないプロトコル用)
  • tls.passthrough=true はTraefikが復号化せずに生のTLS接続を転送することを意味し、アプリケーション自体がTLSを処理
  • エントリポイント名はtcp-{port}またはudp-{port}の規則に従う

事前設定済みポート

以下のTCP/UDPポートにはデフォルトでエントリポイントがあります(--tcp-portsで追加する必要なし)。エントリポイントは設定されたアドレスファミリーに対してのみ生成されます, IPv4エントリポイントには--public-ipv4が、IPv6エントリポイントには--public-ipv6が必要です:

ポートプロトコル一般的な用途
80HTTPWeb(HTTPSへ自動リダイレクト)
443HTTPSWeb(TLS)
3306TCPMySQL/MariaDB
5432TCPPostgreSQL
6379TCPRedis
27017TCPMongoDB
11211TCPMemcached
5672TCPRabbitMQ
9092TCPKafka
53UDPDNS
10000-10010TCP動的範囲(自動割り当て)

DNS設定

自動DNS(Cloudflare)

--cf-dns-tokenが設定されている場合、rdc config infra pushはCloudflareに必要なDNSレコードを自動的に作成します:

レコードタイプ内容作成元
server-1.example.comA / AAAAマシンのパブリックIPpush-infra
*.server-1.example.comA / AAAAマシンのパブリックIPpush-infra
*.marketing.server-1.example.comA / AAAAマシンのパブリックIPrepo up

マシンレベルのレコードはpush-infraによって作成され、カスタムドメインルート(rediacc.domain)をカバーします。リポジトリごとのワイルドカードレコードはrepo upによって自動的に作成され、そのリポジトリの自動ルートをカバーします。

これは冪等です, IPが変更された場合は既存のレコードが更新され、既に正しい場合はそのまま維持されます。

ベースドメインのワイルドカード(*.example.com)は、rediacc.domain=erpのようなカスタムドメインラベルを使用する場合、手動で作成する必要があります。

手動DNS

Cloudflareを使用しない場合やDNSを手動で管理する場合は、A(IPv4)および/またはAAAA(IPv6)レコードを作成します:

# マシンサブドメイン(rediacc.domain=erpのようなカスタムドメインルート用)
server-1.example.com           A     203.0.113.50
*.server-1.example.com         A     203.0.113.50
*.server-1.example.com         AAAA  2001:db8::1

# リポジトリごとのワイルドカード(myapp.marketing.server-1.example.comのような自動ルート用)
*.marketing.server-1.example.com    A     203.0.113.50
*.marketing.server-1.example.com    AAAA  2001:db8::1

# ベースドメインワイルドカード(rediacc.domain=erpのようなカスタムドメインサービス用)
*.example.com                  A     203.0.113.50

Cloudflare DNSが設定されている場合、リポジトリごとのワイルドカードレコードはrepo upによって自動的に作成されます。複数のマシンがある場合、各マシンはそれぞれのIPを指す独自のDNSレコードを取得します。

ミドルウェア

Traefikミドルウェアはリクエストとレスポンスを変更します。ラベル経由で適用します。

HSTS(HTTP Strict Transport Security)

labels:
  - "traefik.http.middlewares.myapp-hsts.headers.stsSeconds=15768000"
  - "traefik.http.middlewares.myapp-hsts.headers.stsIncludeSubdomains=true"
  - "traefik.http.middlewares.myapp-hsts.headers.stsPreload=true"
  - "traefik.http.routers.myapp.middlewares=myapp-hsts"

大容量ファイルアップロードバッファリング

labels:
  - "traefik.http.middlewares.myapp-buffering.buffering.maxRequestBodyBytes=536870912"
  - "traefik.http.routers.myapp.middlewares=myapp-buffering"

複数のミドルウェア

カンマ区切りでミドルウェアをチェーンします:

labels:
  - "traefik.http.routers.myapp.middlewares=myapp-hsts,myapp-buffering"

利用可能なミドルウェアの完全なリストについては、Traefikミドルウェアドキュメントを参照してください。

診断

サービスにアクセスできない場合、サーバーにSSHしてルートサーバーのエンドポイントを確認します:

ヘルスチェック

curl -s http://127.0.0.1:7111/health | python3 -m json.tool

全体的なステータス、検出されたルーターとサービスの数、自動ルートが有効かどうかを表示します。

検出されたルート

curl -s http://127.0.0.1:7111/routes.json | python3 -m json.tool

すべてのHTTP、TCP、UDPルーターとそのルール、エントリポイント、バックエンドサービスを一覧表示します。

ポート割り当て

curl -s http://127.0.0.1:7111/ports | python3 -m json.tool

動的に割り当てられたポートのTCPおよびUDPポートマッピングを表示します。

よくある問題

問題原因解決方法
サービスがルートに表示されないコンテナが実行されていない、またはラベルが不足リポジトリのデーモンでdocker psを確認、ラベルを確認
証明書が発行されないDNSがサーバーを指していない、または無効なCloudflareトークンDNS解決を確認、Cloudflare APIトークンの権限を確認
502 Bad Gatewayアプリケーションが宣言されたポートでリッスンしていないアプリが{SERVICE}_IPにバインドし、ポートがloadbalancer.server.portと一致していることを確認
TCPポートに到達できないインフラストラクチャにポートが登録されていないrdc config infra set --tcp-ports ...push-infraを実行

完全な例

この例では、PostgreSQLデータベースを持つWebアプリケーションをデプロイします。アプリはapp.example.comでTLS付きで公開されます。データベースは内部専用です。

docker-compose.yml

services:
  webapp:
    image: myregistry/webapp:latest
    environment:
      DATABASE_URL: postgresql://app:changeme@${POSTGRES_IP}:5432/webapp
      LISTEN_ADDR: ${WEBAPP_IP}:3000
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
      - "traefik.http.routers.webapp.entrypoints=websecure,websecure-v6"
      - "traefik.http.routers.webapp.tls.certresolver=letsencrypt"
      - "traefik.http.services.webapp.loadbalancer.server.port=3000"
      # HSTS
      - "traefik.http.middlewares.webapp-hsts.headers.stsSeconds=15768000"
      - "traefik.http.middlewares.webapp-hsts.headers.stsIncludeSubdomains=true"
      - "traefik.http.routers.webapp.middlewares=webapp-hsts"

  postgres:
    image: postgres:17
    environment:
      POSTGRES_DB: webapp
      POSTGRES_USER: app
      POSTGRES_PASSWORD: changeme
    command: -c listen_addresses=${POSTGRES_IP} -c port=5432
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    # traefikラベルなし, 内部専用

Rediaccfile

#!/bin/bash

up() {
    mkdir -p data/postgres
    renet compose -- up -d
}

down() {
    renet compose -- down
}

DNS

app.example.comをサーバーのパブリックIPに向けるAレコードを作成します:

app.example.com   A   203.0.113.50

デプロイ

rdc repo up --name my-app -m server-1 --mount

数秒以内にルートサーバーがコンテナを検出し、Traefikがルートを取得してTLS証明書をリクエストし、https://app.example.comが公開されます。