2022-01-24
先日作成したブログをさくらVPSにホストしました。 OS入れてWebサーバ入れて、鍵を作って設定ファイル書いてと真心込めて作業したので、Netifyやfirebase、Vercelなどの進化しているホスティングサービスの凄さを肌身をもって実感することができました。
2022/01/11からCentOS Stream 9がさくらVPSで選択可能になっていたので、最新のOSがいいだろうということでこれを選択しました。
CentOS Stream9の公式ページによると、2027年ごろまでのサポートを想定しているということで、あと5年間は安心してそのまま使えそうです。 Open SSL ver3.00(最新)とTLS1.2より古いバージョンのサポートを終了して、TLS1.2 or 1.3のみサポートすることになっているということで、セキュリティ的にも安心そうです。 サーバーを弄るのは今回が初めてでしたが、CentOS Stream 9の記事はまだ少なく、他のバージョンと異なっているはまったポイントがいくつかあったのでその辺りも後ほど記載できたらと思います。
石狩を選択しました。一番安かったからというのが正直な理由です。石狩が一番寒いから環境的に優しそうな気もしています。(適当)
1Gを選択しました。 年間プランを使っていても差額を払えばアップグレード可能ということだったので、まずは1Gで十分と判断。最初の頃は1Gでも多い気がしたので、ケチるか迷いましたが512MBでもあまり金額が変わらなかったので1Gに落ち着いています。SSDはデフォルトの50GBのままです。
Nginxを採用。エンジンエックスと読むことを今回初めて知りました。 ApacheかNginxかどっちを入れるのが良いのか一切わからなかったので、軽く調べてみました。今も自分の用途に対して最適な選択になっているか?と言われると自信はないのですが、今回の用途では最低限問題はなさそうなのでよしとします。いつかしっかりと調査してみたいなーという気はしています。 色々と調べていく中で見えてきたポイントとしては、
参考
NginxとApacheの比較 〜 ウェブサーバー直接対決 〜
ローカルの操作とリモートの操作が混在していてややこしいので、基本的にコードブロックの上部に #local
#remote
などと記載するようにしています。
参考にしていただく際にはそれらの表記は無視してください。
【結論】
CentOS Strema 9ではデフォルトでrootでのパスワードログインができなくなっている。以前のバージョンだとデフォルトは可能な設定になっているので、ネット上の記事は最初にrootでSSH接続して。。。と書いてあるものが多いです。気をつけましょう。
鍵の設定をしていないからか?パケットフィルタリングの設定か?など疑い、鍵を設定してさくらVPSの管理画面からOSインストールの際にパケットフィルタリングの設定でTCP 80/443をあけたりして、それでも解決できなかったのでそもそもなぜパスワードでログインできない?と考えググったところ、 CentOS Stream 9 LAMPサーバインストールメモ【Apache2.4+MySQL8.0+PHP8.0】を見つけて気づきました。
【手順】 さくらがCentOS Stream 9の設定方法を出してくれていました。rootでのパスワード認証はデフォルトで不可になっているので、最初は標準ユーザとして設定されているcentosでログインします。
#local
ssh centos@port_number
あとはちょっと古いのですが、さくらのVPS講座を参考にしつつ、CentOS Stream 9固有の部分や不要な部分は飛ばしつつ作業をしていきます。 VNGコンソールから以下の容量でログインして
#remote
login: root
Password: password
centosユーザから任意のユーザー名にユーザーを作り替えて、最後にrootユーザーのパスワードを削除したら完了です。 ちなみに、rootユーザーでのパスワードログインがデフォルトで不可になっている理由としては、rootユーザーのパスワードログインが可能になっているとブルートフォース攻撃を受けてroot権限が乗っ取られてしまう可能性があるためです。 もちろん、自分で作成したユーザーでもパスワードログインを可能にしている場合その可能性は残るのですが、パスワードだけでなくユーザー名も当てる必要があるので攻撃の障壁は大きく上がるでしょう。
次に公開鍵認証の設定を行います。 パスワードログインだとまだパスワードを破られるリスクが残るので、念には念を入れておきます。
まずは、 ローカルで鍵を作成します。
#local
ssh-keygen -f "~/.ssh/your_key_name"
作成したら、リモートのホームディレクトリに 公開鍵であるyour_key_name.pub
を移動させたいので、 scp your_key_name.pub username@your_ip_address:~/
で移動させます。
そして、以下コマンドでリモートに公開鍵リストを作成し、権限を設定します。
#remote
pwd # ディレクトリを確認して、ホームディレクトリ以外にいる場合にはホームディレクトリに移動
mkdir .ssh # ディレクトリ作成
chmod 700 .ssh/ # 自分以外のアクセスを禁止
mv id_rsa.pub .ssh/authorized_keys # 公開鍵リスト作成
chmod 600 .ssh/authorized_keys # 自分以外の読み書きを禁止
デフォルトではSSH接続に22番ポートが活用されていますがwell known portということでユーザーネームを片っ端からアタックされて危険です。また、実際には鍵などでセキュリティを高めているのでリスクはそこまでない場合でも、アタックされているログがたくさん残るとログを見たときに邪魔です。 そこで、port番号を任意の番号に変更していきます。 この際に、すでに活用されている or これから活用しうるポートとぶつからないように設定します。
#remote
sudo vi /etc/ssh/sshd_config
すると、
#Port 22
とコメントアウトされている部分があるのでこの22を任意のポート番号に変えればOKです。 #はコメントアウトされている部分なので削除する必要があります。 私は普段IDEでシンタックスハイライトが効いた状態で開発しているので、一瞬#がコメントアウトということに気づかず設定失敗してしまいました。。
CentOS Stream 9の設定方法の中で firewalldの設定をしたかと思います。 しかし、設定しただけでは動いていないのでactivateしていきます。
#remote
systemctl status firewalld #firewalldの状態確認
○ firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:firewalld(1)
sudo systemctl start firewalld
systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
Active: active (running) since Sat 2022-01-22 14:53:52 JST; 2s ago
Docs: man:firewalld(1)
Main PID: 1985 (firewalld)
Tasks: 2 (limit: 5914)
Memory: 26.4M
CPU: 312ms
CGroup: /system.slice/firewalld.service
└─1985 /usr/bin/python3 -s /usr/sbin/firewalld --nofork --nopid
このような状態になったら起動成功です。 firewallについてはさくらのVPS講座第7回にて説明してくれていたので、初めて聞いたという方は読んでみるといいと思います。
CentOS Stream9はRPMパッケージを扱うコマンドは yum
ではなく dnf
です。
また、今回Nginxをインストールする際に、EPELリポジトリというものを作成する機会があったのですが、何のことかわからず調べたところ、CentOS標準のリポジトリでは提供されていないパッケージをインストールする際に活用するサードパーティー製リポジトリということでした。他にもサードパーティー製リポジトリは存在していますが、EPELはエンタープライズ向けで信頼性がある模様です。
ただ、デファクトぽくなっているが、RedHat社の公式サポートがあるわけではないので、その点は認識しておいた方が良さそうです。
参考
CentOSなどで使う、EPELってなんだ? - Qiita
まずはEPELを導入してNginxを入れる用意をします。
#remote
sudo dnf config-manager --set-enabled crb
sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-next-release-latest-9.noarch.rpm
念の為、sudo dnf update
で全部最新にしておきます。(意味ないかも)
nginx: Linux packagesを見てstableのインストールを進めていたのですが、なぜかインストールできません。サポートしているversionをよく見てみると、centos7 / 8ということで、stream9は入っていないです。
過去の先輩方の記事を見ていくと、dnfデフォルトのNginxはバージョンが古すぎる。という記載がよく見つかったので、dnfからではなく、直接インストールしようとしていたのですがならばと、公式は全部無視してdnfデフォルトのNginxをインストールすることにしました。
この際に、nginxの公式で展開されている /etc/yum.repos.d/nginx.repo
の設定は消す必要があるので注意です。
dnfからそのままインストールする際にはHow To Install Nginx on CentOS 9 Streamを参考にしました。
インストール後に念の為バージョンを確認してみると
#remote
nginx -v
nginx version: nginx/1.20.1
ということで、stableだから別に古いわけでもなかったです。めでたしめでたし。 インストールできたら、Nginxサーバを立ち上げていきます。
#remote
sudo systemctl start nginx #nginxサーバを立ち上げる
sudo systemctl enable nginx #nginxサーバが自動で起動するようにする
sudo systemctl status nginx #statusの確認
● nginx.service - The nginx HTTP and reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: di>
Active: active (running) since Wed 2022-01-19 15:47:12 JST; 10min ago
Main PID: 26081 (nginx)
Tasks: 3 (limit: 5914)
Memory: 2.8M
CPU: 15ms
CGroup: /system.slice/nginx.service
├─26081 "nginx: master process /usr/sbin/nginx"
├─26082 "nginx: worker process"
└─26083 "nginx: worker process"
この状態になったらOKです。
自分のIPアドレスをURLで叩いたら、nginxサーバーのデフォルト画面が見えるはずです。 http://your_ip_address
しかし、faviconがぐるぐるしていて進まないです。
ここでfirewallを設定していたことを思い出します。
http と https(後ほど使えるようにする)のポートを開ける必要があるので開けます。
#remote
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload
これで再度 http://your_ip_address
でトライするとnginxデフォルトの画面が開けました!https://your_ip_address
と、httpsで接続しようとするとまだ開けません。
後ほどSSL証明書を取得してhttps通信にも対応できるようにしていきます。
サーバーのipアドレスを直接URLバーに打ったら接続できるようになりました。今度は、ドメイン名とipアドレスをDNSの設定を行い紐づけていきます。 ネームサーバ利用申請 - さくらのサポート情報を参考に進めていきました。
設定が完了すると、これまではhttp://your_ip_address
としていたところから、 http://your_domain_name
でアクセスできるようになります。自分の場合は http://shgnkn.io
です。
次は、SSL証明書を入手して、httpsでの通信ができるように設定していきます。
Let’s Encryptを使いました。 ネコでもわかる!さくらのVPS講座 ~第六回「無料SSL証明書 Let’s Encryptを導入しよう」 | さくらのナレッジや Let’s EncryptのSSL証明書で、安全なウェブサイトを公開 | さくらのナレッジなどを読むと、古い記事なのでcertbot-autoを使うと記述がありますが、現在は非推奨となっているので使わないように注意です。 certbot-auto更新 などには書いてありましたね。
certbot-auto更新などに書いてあります。 しかし、CentOS Stream 9ではsnapdが使用できません。
そのため、今回はpip
でインストールする方法を取りました。(参照:Centos Stream9: Let’s Encrypt)。早速記事にしてくださっていた方がいて助かりました。
ブログ内のapacheはnginxに読み替えて実行していきます。
#remote
sudo certbot --nginx
諸々yesしたり、メアド、ドメインを登録したりしていきます。
Could not automatically find a matching server block for shgnkn.io. Set the `server_name` directive to use the Nginx installer.
エラー。nginx.confファイルにドメイン名を設定する必要があるとのことで設定していきます。
#remote
sudo vi /etc/nginx/nginx.conf
#/etc/nginx/nginx.conf
server {
listen 80;
listen [::]:80;
server_name shgnkn.io;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
設定ができたらリトライしていきます。
#remote
sudo certbot --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: your_domain
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1
Certificate not yet due for renewal
You have an existing certificate that has exactly the same domains or certificate name you requested and isn't close to expiry.
(ref: /etc/letsencrypt/renewal/your_domain.conf)
What would you like to do?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Attempt to reinstall this existing certificate
2: Renew & replace the certificate (may be subject to CA rate limits)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
Deploying certificate
Successfully deployed certificate for your_domain to /etc/nginx/nginx.conf
Congratulations! You have successfully enabled HTTPS on https://your_domain
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
以下コマンドで、証明書や秘密鍵などのファイルが確認できていたら成功です。
#remote
sudo ls -l /etc/letsencrypt/live/your_domain
https://your_domain
をブラウザのアドレスバーに入力するとhttps通信ができていることが確認できます。
F12でdevtoolsを立ち上げて、securityをみると証明書を確認することができます。
certbotは優秀で、httpで通信が来た際に、httpsに強制的にリダイレクトするようする設定を自動でしてくれます。あとは証明書の自動更新設定が必要になりそう。
証明書の期限が3ヶ月と短いので、証明書の自動更新も設定しておきたいところです。 cronを活用する方法、certbotにあるタイマーユニットを活用する方法など、複数方法はありそうなので、お好きなもので設定したらOKです。 自分はcronで設定してしまいましたが、うまく設定できているか確認ができていないので、期限が近づいたら見守りたいと思います。
参考
CentOS7にnginxとcertbotを導入してHTTPS環境をさくっと作るの巻
Ceontos Stream9: Let’s Encrypt
期限の30日以内であれば以下コマンドで手動更新も可能です。
#remote
sudo certbot renew
ここまで設定しておいてなんですが、自分はshgnkn.io
ではなくサブドメインを切ってblog.shgnkn.io
でホストしたかったのです。ということで、サブドメインを切っていきます。
まずは、さくらのドメインコントロールパネルでサブドメインを設定します。詳細は割愛しますが、この方のブログの前半が参考になります。管理画面が少し異なりますが、操作はほぼ一緒です。 設定から反映まで数分〜48時間程度かかるということなので気長に待ちます。
今回私は、大量のサブドメインを切る予定があるわけでもないので、変数を使って対応したりはしないでシンプルに設定していきます。
まずはconfファイルを設定します。このファイルを作成する前は、/etc/nginx/conf.d/
配下は空のはずです。
#remote
sudo vi /etc/nginx/conf.d/sub_domain.conf
#/etc/nginx/conf.d/sub_domain.conf
server{
server_name sub_domain.your_domain;
location / {
root /usr/share/nginx/html/sub_domain;
index index.html;
}
}
忘れずにNginxをリロードして設定を反映させます。
#remote
sudo nginx -s reload
これで、 /usr/share/nginx/html/sub_domain
配下の index.html
がhttp://sub_domain.your_domain
にアクセスした際に表示されるはずなので、適当なHTMLファイルを作成して確認します。
vi /usr/share/nginx/html/sub_domain/index.html
#/usr/share/nginx/html/sub_domain/index.html
Contents will be here
保存して、http://sub_domain.your_domain
にアクセスしてみると、Contents will be here
と表示できているはずです。
さて、次はサブドメインに対してもhttps通信ができるようにしていきます。 必要な作業はSSL証明書の再発行です。 サブドメインに対してhttp通信がなされた場合のリダイレクト設定も必要かと思っていたのですが、設定ファイルをみるとすでに設定できていたので不要でした。
「certbot サブドメイン」などで検索すると、いかなるサブドメインに対しても有効なワイルドカード証明書に関する記事が多数出てくるかと思います。しかし、ワイルドカード証明書だと更新作業を行う際に、DNSにTXTを登録する必要があったりして自動更新の設定が厳しそうです。(もしできる方法あったらぜひ教えてください!) 今回はサブドメインを1つしか切らない&今後も大量に切る予定はないということで、ワイルドカード証明書は使わずに、1つのサブドメインだけ追加していきます。
#remote
sudo certbot --nginx -m your_email_address -d sub_domain.your_domain -d your_domain
これでサブドメインもhttps対応させることができました。
https://sub_domain.your_domain
にアクセスできるようになっているはずです。
リダイレクトはすでに設定できているはずなので、サブドメインの http://sub_domain.your_domain
にアクセスしても自動でhttpsにリダイレクされることが確認できるかと思います。
最後にコンテンツをアップロードしたらいよいよ完了です!
今後はGitHub Actionsなどを活用して自動でデプロイできるようにしていきたいと思いますが、今回は初回なので手動rsyncで真心を込めてデプロイしていきたいと思います。 自動デプロイはまた後ほど、設定したら記事にしていきいたいと思います。
#local
rsync -auvz -e 'ssh -p your_port_number' public以下のフォルダ user_name@ip_address:/usr/share/nginx/html/sub_domain/
するとPermission denied (13)の大量のエラーが吐かれました。 rsyncの仕組みとして、ローカルでrsyncを呼ぶと、ファイルのシンク先リモートでもrsyncが起動して、お互いが通信してファイルが渡されるのですが、その際にリモートではsudoなどをしていないただのユーザーアカウントが動くので、書き込み権限がなくてエラーになっている模様です。 rootでログインはできない状態で保ちたいので、作成したuserでどうにかやりたい。
古いが、以下の記事などを読むと、 --rsync-path
オプションを指定して、sudo rsyncが呼び出されるようなスクリプトを作成しておいておけばいいとのこと。
ググると、「rootでログインするといいよ」「パスワードは不要にするといいよ」などの記事が見つかりますが、今後自動デプロイすること、rootログインを可能にして作業した後に不可に戻すのを忘れそうなことを考えると、なんとかもっとセキュアな方法を取りたいところでした。
そこで以下複数記事を参考にさせていただき、最終的にrsync + cron + ssh (rsyncd を立てない編)を参考に「鍵を作り特定の操作に対してだけrootで操作可能な権限を渡して操作」という方法を取ることにしました。
参考
セキュアな rsync - 理屈編 - JULY’s diary
セキュアな rsync - 実践編 - JULY’s diary
パスワードありsudoでrsyncするシェルスクリプト
rsync + cron + ssh (rsyncd を立てない編)
最終的に、最後の記事を参考に以下の作業は進めました。 鍵を作成。-Nオプションでパスフレーズは空にしておく
#local
sudo ssh-keygen -N "" -f ~/.ssh/rsync
すぐ消すが、念の為権限を絞ってtmpフォルダを作成
#remote
mkdir -m 700 tmp
sshd_configを書き換え
#remote
sudo vi /etc/ssh/sshd_config
.
.
.
#PermitRootLogin no
PermitRootLogin forced-commands-only
.
.
.
ローカルの公開鍵をリモートに転送
#local
sudo scp -P your_port_number ~/.ssh/rsync.pub user_name@your_iP_address:~/tmp
私の場合は、rootに.sshフォルダが存在していなかったので作成。もしすでに作成されている場合には、最初の2つのコマンドは飛ばしてOK。最後に忘れずにsshdの再起動とtmpフォルダの削除を行います。
#remote
sudo sh -c 'mkdir /root/.ssh'
sudo sh -c 'touch /root/.ssh/authorized_keys'
sudo sh -c 'cat ~nuts/tmp/rsync.pub >> /root/.ssh/authorized_keys'
systemctl restart sshd
sudo rm -rf ~/tmp
ここまでで、実行コマンドを限定した接続ができるはずなのでテストします。 まずは、鍵ファイルにlsコマンドを入れてみます。
#remote
sudo vi /root/.ssh/authorized_keys
・
・
・
command="ls" ssh-rsa ******
・
・
・
ローカルから接続してみます。
#local
sudo ssh -i ~/.ssh/rsync -p your_port_number root@your_ip_address
lsが実行されて、すぐに接続が切れたら成功です。
先ほどlsコマンドを入れた箇所には実際に走らせるコマンドを入れる必要があるので、そのコマンドを取得します。
#local
sudo rsync -vv -az -e "sudo ssh -i 絶対パス/.ssh/rsync -p your_port_number" 絶対パス/public/ root@your_port_number:/usr/share/nginx/html/sub_domain/
すると、実行結果としてrsync --server -vvulogDtprz . 絶対パス/public/
という記述が見えるかと思います。ここから-vvオプションを取り除いたコマンドを登録していきます。
#remote
sudo vi /root/.ssh/authorized_keys
・
・
・
command="rsync --server -ulogDtprz 絶対パス/public/" ssh-rsa ******
・
・
・
これで設定は完了したはずなので、ローカルからrsyncを呼び出してみます。
#local
sudo rsync -vv -az -e "sudo ssh -i 絶対パス/.ssh/rsync -p your_port_number" 絶対パス/public/ root@your_port_number:/usr/share/nginx/html/sub_domain/
実行結果を確認してみましょう。https://sub_domain.domain
にアクセスすると、Gatsbyでビルドしたページが表示されているはずです。
リモートの/usr/share/nginx/html/sub_domain/
配下も確認してみると、ビルドしたファイルが格納されているはずです。
#remote
sudo ls /usr/share/nginx/html/sub_domain/
サブドメインではなく、メインドメインで色々始めてしまったので、いらないファイルが /usr/share/nginx/html
に残ってしまっています。これらを気をつけながら rm -rf
コマンドで削除していきます。全部削除できたら、https://your_domain
をURLバーに打ち込んでも403 Forbiddenになるはずです。
これで自分も鯖管デビューです。独自ドメインがあるとテンションが上がりますね。 これを機に、アウトプットの習慣をつけていけたらと思います。