NginxでリクエストをLXCコンテナに振り分ける


やりたいこと

  • blog.abcang.netabcang.net宛のリクエストをwebコンテナに転送
  • blog.abcang.netabcang.netでそれぞれ別のページが表示される
  • app.abcang.net宛のリクエストをappコンテナに転送
  • 登録されていないサブドメインでのアクセスはabcang.netに転送
  • コンテナを増やすたびに設定ファイルを追加したくない

やったこと

以下のように設定ファイルを編集する。
各コンテナは普段通りの設定をすればいい。

/etc/nginx/conf.d/default.conf
map $http_host $cname {
    hostnames;
    abcang.net          web;
    blog.abcang.net     web;
    app.abcang.net      app;
    default             0;
}

server {
    listen       80 default_server;
    server_name  abcang.net;

    # 登録されていないホストはリダイレクト                            
    if ($cname = 0) {
        rewrite ^ http://abcang.net$request_uri? last;
    }

    # 内部DNSで名前解決して転送                                       
    location / {
        resolver dns.abcang.net valid=3600s;
        proxy_pass http://$cname;
        # 接続元情報を維持                                            
        proxy_set_header Host            $host;
        proxy_set_header X-Real-IP       $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_max_temp_file_size 0;

        # Websocket                                                   
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;
    }
}

説明

ドメインからコンテナを指定

map $http_host $cname {
    hostnames;
    abcang.net          web;
    blog.abcang.net     web;
    app.abcang.net      app;
    default             0;
}

左にアクセス元のドメインを、右にコンテナの名前を書いていく。
新しくコンテナを追加した場合はこの部分を増やせば良い。
defaultは一致しなかったものがマッチして、0が設定されるようにしている。

登録されていないホストはリダイレクト

    # 登録されていないホストはリダイレクト                            
    if ($cname = 0) {
        rewrite ^ http://abcang.net$request_uri? last;
    }

先のmapでの設定で、登録されていない場合は$cname0になることがわかる。
それを検知したらrewriteでリダイレクトするようにしている。
lastをつけるとそこで処理を停止してくれるらしい。

各コンテナに転送

    # 内部DNSで名前解決して転送                                       
    location / {
        resolver dns.abcang.net valid=3600s;
        proxy_pass http://$cname;
        # 接続元情報を維持                                            
        proxy_set_header Host            $host;
        proxy_set_header X-Real-IP       $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_max_temp_file_size 0;

        # Websocket                                                   
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;
    }

resolverの部分で内部DNS(LXCで使用されているもの)を指定する。
validをつけると再度DNSに問い合わせる時間を指定できるみたい。
proxy_passで転送先を指定しているが、ドメイン部分を変数にしておかないとnginx起動時以降名前解決してくれないらしい。
後は接続元の情報をヘッダに付けてあげたり、WebSocketも使えるようにしてあげたり。

参考