自宅サーバのWebサービスをVPSで中継するようにした

これまで自宅サーバへの外部からの接続には、 数年前から自宅のグローバルIPアドレスにフリーのドメインを紐づけて使っていたのですが、 3月末に更新を忘れてこのドメインを失効させてしまいました。

自宅サーバでは、主に個人用のWebサービスや身内用のゲームサーバが動いています。

同じドメインを再取得するには追加の料金がかかりますし、(若干用途が規約的に怪しいこともあり)新しくドメインを取り直す気にもなれなかったので、 以前から契約していたVPSをTCP/UDPプロキシとして使ってみることにしました。

この記事では、nginx.confのhttpディレクティブとstreamディレクティブそれぞれについて、拡張子でincludeを切り分けるようにする構成にしています。 基本的には、nginx.confに以下のように記述するイメージです。

http {
include /etc/nginx/conf.d/*.http;
}
stream {
include /etc/nginx/conf.d/*.stream;
}

また、この記事の内容には関係ありませんが、envsubstでconfigファイルに環境変数を注入する、nginxのDocker Hub公式Dockerイメージのtemplate機能を使用しているため、 nginx設定ファイルの拡張子がtemplateになっています。

上のツイートに関連して、certbot --nginxで自動生成される/etc/letsencrypt/options-ssl-nginx.confを手動でnginx.confに統合しているので、 以下の設定ではコメントアウトされているincludeがあります。

構成

  • 自宅サーバ側:systemd + autosshによる自動SSH接続&リモートポート転送
  • VPS側:nginxによるHTTPリバースプロキシ・UDPプロキシ

自宅サーバ側

~/.ssh/config

Host vps*
HostName VPS_IPADDR
Port VPS_SSH_PORT
ServerAliveInterval 10
ServerAliveCountMax 5
TCPKeepAlive yes
IdentitiesOnly yes
IdentityFile ~/.ssh/vps
Host vps-forwarding-homeserver
# SERVICE1
RemoteForward 127.0.0.1:VPS_SERVICE1_PORT 127.0.0.1:LOCAL_SERVICE1_PORT
# SERVICE2
RemoteForward 127.0.0.1:VPS_SERVICE2_PORT 127.0.0.1:LOCAL_SERVICE2_PORT

/etc/systemd/system/autossh-vps.service

[Unit]
Description=AutoSSH VPS
[Service]
Type=simple
Restart=always
User=user
Group=user
WorkingDirectory=/home/user
ExecStart=/usr/bin/autossh -N vps-forwarding-homeserver
[Install]
WantedBy=multi-user.target

VPS側

HTTPリバースプロキシ(SSHポート転送使用): myservice.http.template

server {
server_name myservice.example.com;
client_max_body_size 500M;
add_header Strict-Transport-Security 'max-age=15552000; includeSubDomains; preload';
location / {
#auth_basic "Auth required";
#auth_basic_user_file /secrets/myservice.htpasswd;
proxy_pass http://127.0.0.1:VPS_MYSERVICE_PORT;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
send_timeout 3600s;
proxy_connect_timeout 3600s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
#proxy_max_temp_file_size 2048m;
}
location /.well-known/acme-challenge/ {
root /letsencrypt-webroot;
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/myservice.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myservice.example.com/privkey.pem;
# include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = myservice.example.com) {
return 301 https://$host$request_uri;
}
server_name myservice.example.com;
listen 80;
return 404;
}

UDPポート転送(SSHポート転送不使用): myserviceudp.stream.template

server {
listen VPS_SERVICEUDP_PORT udp reuseport;
proxy_pass HOME_IPADDR:HOME_SERVICEUDP_PORT;
proxy_connect_timeout 3600s;
proxy_timeout 3600s;
#proxy_max_temp_file_size 2048m;
}