XServer VPSでホームページを公開する【AlmaLinux9/Nginx/PHP8/MySQL8】2025年版
予告
そのうち、手動ではなくAnsibleのYAMLコードで管理する記事を上梓いたします。
課題
単価が計算できるかたちで(つまり従量課金制度ではなく)、できるだけ自由な構成や設定でWebサーバーを建てたい。
概要(手続き)
細かいことはたくさんありますが、マクロでとらえるとけっこうシンプルです。
- リモートコンピューターリソースを購入する(XServerでVPSを購入する)
- OSと、Webサーバー用のソフトと、ウェブ向きのスクリプト言語と、データベースソフトを入れる
- それらの設定ファイルがつなぎあわさるようにディレクトリの配置やパスを調整する
- それぞれのファイルの権限を適切にコントロールする
- それらをOS(Linux)のやりかたでやる
- 必要があれば外部アプリからアクセスできるようにする
ローカル作業環境
- ローカルパソコンOS:macOS
$ sw_vers
# ProductName: macOS
# ProductVersion: 15.3.1
# BuildVersion: 24D70
$ system_profiler SPHardwareDataType
# Model Name: MacBook Air
# Chip: Apple M2
# Memory: 8 GB
購入したVPS環境
- プロバイダー:XServer VPS
- OS: AlmaLinux9.5
- CPU:3コア
- メモリ:2GB
- NVMe SSD:50GB
サーバー選定理由
2GBのメモリ単価が1000円前後で、AlmaLinuxの最新版が安定稼働してくれて、変な設定からスタートさせられないならどこでもよいのですが、XServerはDifyについていちはやくセット組んだり、ゲーミングのほうにちからをいれているので、プロジェクトと相性がよくて選びました。
プロジェクト自体をAWSの世界観に染めていく予定なら、Amazon Lightailにすると思います。
ほんとうは純ジャパのさくらを使いたいんですけど、選択肢の想起筆頭に来るか来ないかで言えば、来ない、という印象です。
とくに今回さくらのVPSを外したのは、SELinuxというセキュリティ設定が無効からスタートさせられるうえに、サポートやPAAセクション串刺し検索をしても情報が1件も出てこなかったのがすこし気になって積極的にはおすすめしない方針にしました。(とはいえ、じぶんもSELinuxうまく使えていないのでたいそうなことは言えませんが、、、)
ちなみに、さくらインターネットには「さくらのクラウド」というサービスがあり、最近(25年3月執筆時)は「AppRun」というサービスもベータ試験的にはじまっており、選択肢としてアリだと思います。
前提としている知識
- ターミナル操作
- LinuxやLinuxコマンド基本操作
- わざわざWebサーバーをたててだいたい何に使うか
- 変数の読み替え
※{email}や{password}とあったら、じぶんの入れたいメールアドレスやパスワードに置き換えて実行できる
前提知識について補足
ドルマーク表記について
下記の記事は、VPS初心者のかたの記録です。コマンドコピペは1行ずつ、『$』の次からと心得ましょう。
などの暗黙知的なことが書かれていました。
今回の記事は、コマンドの先頭にドルマーク$
をつけております。コマンドであることを強調するために添えてあるだけなので、実際にターミナルやコマンドラインで利用するさいは、ドルマークを無視して、一行ごとに実行していただければさいわいです。
差分表記について
また、コードを示しているパートで、緑系の色で「+」となっていたり、赤系の色で「-」と行頭に書いてあることがあります。これは差分表記で、プラスマークのほうが変更後、マイナスマークのほうが変更前です。
下記、デモです。
+ この記述を追記してください
- この記述は削除してください
+ あくまで差分なので、性質上逆転することもあります
- たとえば、この行はもともと表示されていた行なのに、
+ ## このように変更後は非表示にしたいのでコメントアウトすることもあります。
リモート/ローカルでの作業について
また、すべてはリモートサーバー、つまり購入したVPSのAlmaLinuxのなかにログインした状態での操作になります。あとで出てきますが、ssh -i ~/.ssh/xserver_{root_keyname} root@{ipaddress}
こういうコマンドで、Linuxにログインしたあとの状態ということです。
それ以外の、ログインしていない状態でやらなきゃいけない作業が1ミリほど出てきますが、それについては「ローカルで」という補足をつけております。ローカルというのは、手元のパソコンということです。リモートというのは、手元にはない、今回購入したはずのどこかにあるコンピューターのことです。
初心者のかたでわかりづらかったら積極的にDMください
初心者のかたで、わかりづらいことがあったら、TwitterでDMとかしていただけるとありがたいです。
今回の構成
- ドメインまわり:Cloudflare
- OS:AlmaLinux 9系
- Webサーバー:Nginx
- データベース:MySQL
ドメインまわりをCloudflareにすると世界観かわるのでおすすめです。以前はGMOのムームードメインをつかっていましたが、サービス維持費が高騰してきたので、原価で買えるCloudflareに移管しました。
使用するアプリ
- ブラウザ:Firefox
- エディター:Cursor
- テーミナル:Warp / Terminus
- FTP:Transmit5
- DB:Sequel Pro / DBeaver
DBをブラウザでさわりたい場合は、「phpMyAmin」や「Adminer」がおすすめです。
VPSとは
「Virtual Private Server」のことで、バーチャルのプライベートのサーバーのことです。IT業界におけるバーチャルというのは「事実上の」という意味で使われることがおおいので、事実上はプライベート(専用)なんだな、というニュアンスで考えてだいじょうぶです。
物理的なサーバーは1台ですが、そのコンピューターのなかに事実上の占有サーバーを何台もつくっていて、それをひとつ借りている、というところです。
非常に自由な設定が可能な分、セキュリティや安定性のチェック、運用、保守が大変です。整備された状態でコンピューターを借りたい場合は、いわゆる「レンタルサーバー」というサービスを購入するのがおすすめです。
あるいは、たとえばWordPressをコンテナとして、Google Cloud Runでサーバーレスにデプロイして動かすとかもありだと思います。
購入
- サイトにアクセス
下記記事「【簡単】エックスサーバーVPS(XServer VPS)の申し込み方法」がスクリーンショット豊富でわかりやすいと思います。
- 会員登録
- 申し込み(2GB以上がおすすめ)
- OS選択(AlmaLinux9)
- 公開鍵認証でログインを選択する(パスワードログインは拒否する)
ここでつくった鍵のことをxserver_{root_keyname}
とします。鍵のつくりかたは、下記の記事などを参考にしてください。ローカルの環境でつくれます。macOSの場合は~/.ssh
に鍵が生成されます。非表示ファイルを表示できる設定に変更して、中身を開けるようにしてください。
- サーバーの情報をどこかにメモする
- コントロールパネルからサーバーを起動する
- ターミナルからSSHできるように「パケットフィルター設定」を変更
「SSH」「Web」「MySQL」「メール」あたりのパケットフィルタリングを追加。使うものに合わせて最低限にしてください。着信したパケットを通過させるかどうかざっくり決めています。
必要な情報をメモっておく
「1Password」などのキーマネジメントアプリを使っているかたは、断然そちらにストックします。
[独自ドメイン]
DOKUJI_DOMAIN={dokuji_domain}
[XServerサービスアカウント]
XServerログインID:{email}
XServerログインパスワード:{password}
VPSコントロールパネル:https://secure.xserver.ne.jp/xapanel/xvps/index
[サーバー]
OS: AlmaLinux9.5
RAM: 2GB
SSD: 500GB
HOSTNAME: {hostname}
IPADDRESS: {ipaddress}
IPADDRESS_V8:
[サーバー root]
USERNAME: root
SSH_KEY: ~/.ssh/xserver_{root_keyname}.pem
[サーバー user]
USERNAME: {username}
SSH_KEY2: ~/.ssh/xserver_{username_keyname}.pem
[mysql root]
USERNAME: root
PASSWORD: {root_database_password}
[mysql user]
USERNAME: {database_username}
PASSWORD: {database_password}
ログインする
鍵をつくって、パケットフィルタリングにSSHをいれて、IPアドレスが確認できたら、さっそくログインします。ターミナルをひらいて、以下のssh
コマンドを打ちます。
# 念のためパスワードログインは拒否されることを確認
$ ssh root@{ipaddress}
root@{ipaddress}: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
# 認証鍵をつかってsshでログインする
$ ssh -i ~/.ssh/xserver_{root_keyname} root@{ipaddress}
# yesと答える(~/.ssh/known_hostsというファイルに保存されます。なりすましの防止です。)
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
# ログイン確認
$ sudo whoami
root
$ sudo who
root pts/0 2025-03-18 13:59 (118.1.228.231)
# OS確認
$ sudo cat /etc/redhat-release
AlmaLinux release 9.5 (Teal Serval)
# 時間
$ sudo date
Thu Mar 20 07:05:21 PM JST 2025
$ sudo timedatectl
Local time: Thu 2025-03-20 19:06:11 JST
Universal time: Thu 2025-03-20 10:06:11 UTC
nanoエディターをインストールする
基本はvi
エディター、Vim
エディターが梱包されていますが、入門時は少し抵抗があると思うので、nano
というエディターを取り入れます。
$ sudo dnf install nano -y
$ sudo nano --version
GNU nano, version 5.6.1
じぶんの使いやすいエディターがいちばんいいですね。
ついでに環境変数側もnano
にしてしまいます。ファイルの末尾にexport EDITOR=nano
と入れてください。
$ sudo nano ~/.bashrc
+ export EDITOR=nano
エディターの閉じ方は以下の手順です。
- control + X(エディターモードを終了するショートカットキー)
- Y(ファイル名を聞かれているのでそのまま保存)
- エンターキー(エディターから解放)
更新反映します。
$ source ~/.bashrc
$ sudo echo $EDITOR
nano
コマンド補完パッケージ
tabキーを押すと補完してくれるようになるツールです。タイプミスがなくなるのでおすすめです。
$ sudo dnf install -y bash-completion
$ source /etc/profile.d/bash_completion.sh
DNFの更新
DNFというのは、「Dandified Yum(ダンディファイド・ヤム)」と呼ばれているパッケージ管理ソフトです。Fedora系をふくむRHEL(Red Hat Enterprise Linux)系のディストリビューションで使うものです。
もともとYUM(Yellowdog Updater Modified)
というのがあったのですが、ベースのPythonのメジャーバージョンに対応するかたちで新生しました。
基本的にいつもパッケージを最新化しておくほうがよいです。セキュリティ、バグ、新機能などなどいろいろあるので、重要なコマンドです。
# (任意)アップグレードの確認
$ sudo dnf check-update
# アップグレード実行
$ sudo dnf upgrade -y
-y
オプションを入れることで、確認作業をスキップできます。-y
は、ほんとうは--assumeyes
(すべてをYesとみなして実行する)というオプションですが、その省略文字です。逆オプションは--assumeno
です。
似たようなコマンドにdnf update
というコマンドもありますが、dnf upgrade
側をやっておけ だいじょうぶです。
(開発環境のみ)DNF自動更新
自動更新もあるので、開発環境で必要があればインストールします。
$ sudo dnf install dnf-automatic -y
自動適用したいときはここの設定をyesにします。
$ sudo nano /etc/dnf/automatic.conf
- apply_updates = no
+ apply_updates = yes
常に有効にします。
$ sudo systemctl start dnf-automatic.timer
$ sudo systemctl enable dnf-automatic.timer
(さくらのVPSなどの場合)SELinuxの有効化
「Security-Enhanced Linux」の略で、強制アクセスコントロールのためのモジュールです。機能の詳細は、REDHの「SELinuxの使用」を御覧ください。
入門記事を書いてくださっているかたもいました。
SELinuxを導入するかどうか、かなり賛否両論あるテーマだと思います。ここでは争点をスキップして、導入をすすめることにします。
まず有効になっているかどうか、現状の確認をします。
$ sudo getenforce
Enforcing
XServer VPSではEnforcing
と表示されると思います。表示OKだったらこの章はここでスキップしてください。最近のLinuxでは最初から有効になっていると思います。
さくらのVPSはDisabled
になっているので、以下の作業をしていきます。
$ sudo nano /etc/sysconfig/selinux
- SELINUX=disabled
+ SELINUX=permissive
まずはpermissiveに更新できたら、selinux
系の引数を初期化するコマンドを叩きます。
$ sudo grubby --update-kernel ALL --remove-args selinux
$ sudo reboot
ログアウト
$ ssh -i ~/.ssh/xserver_{root_keyname} root@{ipaddress}
$ sudo su
$ sudo getenforce
Permissive
$ sudo aureport -a
<no events of interest were found>
$ sudo nano /etc/sysconfig/selinux
- SELINUX=permissive
+ SELINUX=enforcing
ふたたびnanoエディターで設定ファイルを開きます。さっきpermissive
モードにしたところを、enforcing
モードにします。これでようやく、SELinuxが有効になったことになります。
# 再起動
$ sudo reboot
// 再ログインする(ssh~)
# 確認
$ sudo getenforce
Enforcing
SELinuxの管理ツール
SELinuxのセキュリティ設定を確認・変更するためのパッケージをいれます。
$ sudo dnf install policycoreutils-python-utils -y
# ポリシーの確認
$ sudo semanage boolean -l
tftp_home_dir (off , off) Allow tftp to home dir
# セキュリティについて確認
$ sudo ls -Z /var/
policycoreutils-python-utils
は、SELinuxの管理ツールです。
semanage boolean -l
は、SELinuxでどのなにが有効になってるのか無効になっているのか確認できるコマンドです。
ls -Z {filepath}
は、そのファイルパスのセキュリティ事項について確認できます。あとでけっこう使います。設定できたはずなのになんかエラーが出るんだけど!というときに、だいたいSELinuxに捕まっているので、たとえばls -Z /var/www/html
のようなことをして、通っているのか阻止されているのか見たりします。
ユーザーの追加
ここまでroot
で作業してきましたが、原則的によくないことなのであたらしくユーザーを追加します。
OS(AlmaLinux9)をインストールするときに、パスワードログインを不能にしているので、公開鍵認証でログインできるようにディレクティブを変更します。
$ sudo nano /etc/ssh/sshd_config
- # PubkeyAuthentication yes
+ PubkeyAuthentication yes
sshdを再起動します。
# 構文テスト(エラーがなければなにも表示されません)
$ sudo sshd -t
# 再起動
$ sudo systemctl restart sshd
root権限が必要な作業を、rootアカウントではない作業用のアカウントで行えるようにします。
ここでは{username}
という名前にしますが、じぶんの名前に読み替えてください。たとえば、わたしの名前ならjun
にします。運用を考えている場合は、開発者用のアカウントとしてdeveloper
とかでもいいと思います。
# 一般ユーザーをつくる
$ sudo useradd {username}
# .sshディレクトリをつくて所有者を変更する
$ sudo mkdir /home/{username}/.ssh
$ sudo chmod 0700 /home/{username}/.ssh
$ sudo chown {username}:{username} /home/{username}/.ssh
# 一般ユーザーとしてログインする
$ sudo su - {username}
$ ssh-keygen -t Ed25519 -b 4096 -C "{email_address}"
# /home/{username}/.ssh/id_rsaにつくるか聞かれるのでyes
# パスコードを聞かれるので何も入力せずにエンターキー
# authorized_keysにコピーする
$ cat /home/{username}/.ssh/id_rsa.pub >> /home/{username}/.ssh/authorized_keys
$ chmod 0600 /home/{username}/.ssh/authorized_keys
# pem形式のキーにする
$ ssh-keygen -p -m PEM -f /home/{username}/.ssh/id_rsa
# 秘密鍵をクリップボードにコピーする
$ cat /home/{username}/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
が出てくるのですべてコピーしてください
別のタブでローカルのターミナルをひらいて、鍵の内容を反映する。
$ touch ~/.ssh/xserver_{username_keyname}.pem
# ~/.ssh/xserver_{username_keyname}.pemをお好きなエディターで開いて、先ほどコピーした鍵をペースト
wheelグループを有効にする
PAM(Pluggable Authentication Modules)と呼ばれる権限モジュールの更新作業です。シャープがついてコメントアウト状態になっているので、それを有効に戻します。
$ exit
$ sudo nano /etc/pam.d/su
- # auth sufficient pam_wheel.so trust use_uid
+ auth sufficient pam_wheel.so trust use_uid
- # auth required pam_wheel.so use_uid
+ auth required pam_wheel.so use_uid
wheelユーザーを確認
現在のwheelユーザーを確認。先ほどつくった{username}のアカウントがまだ登録されていないことを確認します。下記コマンドはwheel
グループだけ抜き出していますが、ほかのグループも見たいときは$ sudo cat /etc/group
の部分だけでもだいじょうぶです。
$ sudo cat /etc/group | grep wheel
wheel:
# rootに移動しようとすると権限の不一致で弾かれるのを確認
$ sudo su {username}
$ su root
$ su -
Permission denied
↑拒絶されるのが正常系です
# rootに戻る
$ exit
wheelアカウントでパスワードを聞かれないようにします(認証鍵のみを使います)。visudo
は構文チェックしながら編集できるコマンドで、vi
エディターが立ち上がります。
<viエディターの更新方法>
- なにかを入力すると
INSERT
という編集モード突入 - 上下左右キーで移動してコメントアウト部分を変更
-
esc
キーでINSERTモードから脱出 -
:qa
というショートカットキーで保存し、そのままvi
エディターから脱出
どうしてもviエディターがむずかしい場合は、$ sudo nano /etc/sudoers
としてもいいと思います。
# sudoersの更新
$ sudo visudo
- # %wheel ALL=(ALL) NOPASSWD: ALL
+ %wheel ALL=(ALL) NOPASSWD: ALL
+ # ログ
+ Defaults log_input, log_output
+ Defaults logfile=/var/log/sudo.log
+ Defaults maxseq = 1000
XServer VPSの初期設定だとログの設定が書いてなかったので、ついでに追記しておきました。ログというのは、sudo
を使ったときに使用履歴を/var/log/sudo.log
に残すということです。root
ユーザーを回避するのは、こういったログチェックの目的もあります。
nano
でやったかたは構文チェックが未チェックなので、下記のコマンドでチェックを入れてください。visudo
で編集したひとは不要です。
$ sudo visudo -c
/etc/sudoers: parsed OK
先ほどのアカウントをwheelアカウントとして追加して、あらためて確認します。
$ sudo usermod -aG wheel {username}
$ sudo cat /etc/group | grep wheel
wheel:x:10:{username}
$ sudo su {username}
$ sudo su
↑今回は成功します(先ほどはパスワードを聞かれてエラーになってたところ)
パスワードなしで、{username}とrootを行き来できるようになりました。
権限持ちのユーザーが完成したので、次は、rootでダイレクトにログインできないようにします。以下の設定に書き換えます。
$ sudo nano /etc/ssh/sshd_config
- PermitRootLogin prohibit-password
+ PermitRootLogin no
sshdの再起動。
$ sudo sshd -t
$ sudo systemctl restart sshd
試しにrootでログインを試みてみます。
$ sudo reboot
The system will reboot now!
$ ssh -i ~/.ssh/xserver_{root_keyname}.pem root@{ipaddress}
root@{ipaddress}: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
ちゃんと失敗しました。
$ ssh -i ~/.ssh/xserver_{username_keyname}.pem {username}@{ipaddress}
$ sudo su
上記のように、{username}で、そっちでつくった鍵でログインし、sudo su
でrootにいけるのでどうしてもrootじゃないといけない作業は、この移動方法でユーザー移動し、基本は{username}側で必要に応じてsudo
をつけて作業してください。
弊記事では念のためすべてsudo
をつけています。sudo
についての機能解説は割愛いたします。こちらの記事でおもしろい設定を教えてもらえて大変わらいました。
ファイアウォールを設定
防火壁、ということで、不正アクセスなどを制御する設定項目です。出入り口に置くイメージです。ゼロトラスト時代とはいえ重要な項目です。
# 入ってなかったのでインストールから
$ sudo dnf install firewalld -y
$ sudo systemctl status firewalld
Active: inactive (dead)
# 常に有効化してリロード
$ sudo systemctl start firewalld
$ sudo systemctl enable firewalld
$ sudo firewall-cmd --reload
# 詳細確認(サービスやポート、フォワード、ICMPなど)
$ sudo firewall-cmd --list-all
# ゾーンの確認
$ sudo firewall-cmd --get-active-zones
$ sudo firewall-cmd --get-default-zone
# 通信制御サービスの確認
$ sudo firewall-cmd --list-services
cockpit dhcpv6-client ssh
# http/https/ntpのトラフィックを追加する(永続的に有効化)
$ sudo firewall-cmd --permanent --add-service=http
$ sudo firewall-cmd --permanent --add-service=https
$ sudo firewall-cmd --permanent --add-service=ntp
# 使わないサービスを廃止
$ sudo firewall-cmd --permanent --remove-service=dhcpv6-client
$ sudo firewall-cmd --permanent --remove-service=cockpit
# 開放しているポートの確認
$ sudo firewall-cmd --list-ports
# ポートを開ける(あとで22から2222にするので先に2222にしておきます)
$ sudo firewall-cmd --zone=public --add-port=2222/tcp --permanent
$ sudo firewall-cmd --zone=public --add-port=3306/tcp --permanent
$ sudo firewall-cmd --reload
$ sudo firewall-cmd --list-ports
2222/tcp 3306/tcp
# (任意)IPアドレスを追加する
$ sudo firewall-cmd --add-source={ipadderss} --zone=public --permanent
# あらためて確認
$ sudo firewall-cmd --list-services
http https ntp ssh
# 通信状況を確認(netstatコマンドは非推奨なので注意)
$ sudo ss -a
設定変更を永続化する--permanent
オプションは、即時反映されてしまうため、理想的なことを言えば最初は永続化オプションを入れないで確認してから、問題なければ--permanent
オプションをつけて再更新するほうがよいです。
SSHポートの変更
初期名がバレているOSでは、SSHのウェルノウンポート(22)に無差別アタックがきます。hydraとかを利用した、SSHブルートフォースログイン攻撃と呼ばれるものです。
今回の案件の設定は、パスフレーズを利用していないのでSSHがブルートフォースでぶち抜かれることはないはずですが、ログが残ったり、「お、22番あいているじゃん!」で狙われるのは損だとみなして、変更することにします。ポートノッキングという、特定のポートを時間内に順番にノックしていくと空けられるテクニックや、外に露出せずにbastion(踏み台サーバー)を利用するなどの手もあります。
なにをどこで止めるか、というポリシーをもってやるのがいちばんよいと思います。
SELinux側のSSHのポートを調整します。
$ sudo semanage port --list | grep ssh
ssh_port_t tcp 22
$ sudo semanage port -a -t ssh_port_t -p tcp 2222
$ sudo semanage port --list | grep ssh
ssh_port_t tcp 2222, 22
$ sudo systemctl restart sshd
さらに「パケットフィルター設定」でパケットフィルタリングしている場合は、設定画面をブラウザで開いて、「パケットフィルター設定を追加する」から「その他」「TCP」「2222」を追加しないと外部からSSHログインできません。
ここでは仮に2222
にして話を進めています。ほかの番号にした場合は、適宜読み替えてください。
最後にsshdのディレクティブを変更します。
$ sudo nano /etc/ssh/sshd_config
- #Port 22
+ Port 2222
リスタートします。
$ sudo sshd -t
$ sudo systemctl restart sshd
ログインするときのオプションも変わります。
- ssh -i ~/.ssh/xserver_{username_keyname}.pem {username}@{ipaddress}
+ ssh -p 2222 -i ~/.ssh/xserver_{username_keyname}.pem {username}@{ipaddress}
Nginxを設定する
$ sudo dnf install nginx -y
$ sudo which nginx
/usr/sbin/nginx
$ sudo systemctl start nginx
$ sudo systemctl enable nginx
$ sudo systemctl status nginx
$ sudo curl {ipaddress}
SELinuxで外部サービスと接続できなくなっている可能性があるので、確認してから変更します。
# httpd_can_network_connectがoffになっている可能性があるので確認
$ sudo getsebool httpd_can_network_connect
httpd_can_network_connect --> off
# OFFだったらONにする
$ sudo setsebool -P httpd_can_network_connect on
# ほかも確認
$ sudo getsebool -a | grep httpd
# 今回はDBを使うのでhttpd_can_network_connect_dbがOFFの場合はONにする
$ sudo setsebool -P httpd_can_network_connect_db on
# 再起動
$ sudo systemctl restart nginx
このあたりは、SELinuxを導入しなくていいと言われている理由のひとつで、設定が複雑になったり、ウェブサーバーをつくるだけなのに、こういうサイドの設定で403になったりとか、たしかにむずかしいです。
実際の設定ファイルは、/etc/nginx/nginx.conf
にあります。
$ sudo cat /etc/nginx/nginx.conf
これはベースのファイルなので、変更せずにあたらしいファイルをつくります。/etc/nginx/conf.d/{dokuji_domain}.conf
という上書き用のファイルをつくります。
$ sudo nano /etc/nginx/conf.d/{dokuji_domain}.conf
+ # HTTPをHTTPSにリダイレクト
+ server {
+ listen 80;
+ server_name {dokuji_domain} www.{dokuji_domain};
+
+ # HTTPをHTTPSにリダイレクト
+ return 301 https://$host$request_uri;
+ }
+
+ # HTTPSサーバーブロック
+ server {
+ listen 443 ssl;
+
+ ssl_certificate /etc/ssl/{dokuji_domain}.pem;
+ ssl_certificate_key /etc/ssl/{dokuji_domain}.key;
+
+ server_name {dokuji_domain};
+
+ root /var/www/{dokuji_domain}/production/public;
+ index index.php index.html index.htm;
+
+ # BASIC認証
+ auth_basic "Input Your ID and Password";
+ auth_basic_user_file /var/www/{dokuji_domain}/production/.htpasswd;
+
+ # ブラウザでの閲覧拒否 (.htaccess, .htpasswd)
+ location ~ /\.(htaccess|htpasswd)$ {
+ deny all;
+ }
+
+ # 文字コードの設定
+ charset UTF-8;
+
+ # sitemap.xml, robots.txt, ads.txt をまとめて設定
+ location ~ ^/(sitemap\.xml|robots\.txt|ads\.txt)$ {
+ # キャッシュを制御しないようにする
+ add_header Cache-Control "no-store, no-cache, must-revalidate";
+ add_header Pragma "no-cache";
+ }
+
+ # ソフトエラー
+ error_page 403 /error/403.php;
+ error_page 404 /error/404.php;
+ error_page 500 /error/500.php;
+ error_page 503 /error/maintenance.php;
+
+ # indexなしでもファイル一覧を表示しない
+ autoindex off;
+
+ # PHP ファイルと HTML ファイルを PHP として処理
+ location ~ \.(php|html)$ {
+ include fastcgi_params;
+ fastcgi_pass unix:/run/php-fpm/www.sock; # PHP-FPMのソケット
+ fastcgi_index index.php;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ }
+
+ # XML ファイルは XML として処理
+ location ~ \.xml$ {
+ types {
+ text/xml xml;
+ }
+ default_type application/xml;
+ }
+
+ # キャッシュ設定
+ location ~* \.(css|js|jpg|jpeg|png|svg|webp|ico|gif|mp3|mp4|woff|woff2|ttf|pdf)$ {
+ expires 1M;
+ add_header Cache-Control "public, no-transform";
+ }
+
+ # セッションのSameSite設定
+ add_header Set-Cookie "Path=/; Secure; HttpOnly; SameSite=None";
+
+ # リライト設定
+ location / {
+ try_files $uri $uri/ /index.php?$query_string;
+ }
+
+ # エラーページの設定
+ location = /error/404.html {
+ root /var/www/{dokuji_domain}/production/public;
+ internal;
+ }
+
+ location = /error/50x.html {
+ root /var/www/{dokuji_domain}/production/public;
+ internal;
+ }
+
+ # access_log /var/log/nginx/{dokuji_domain}.access.log;
+ # error_log /var/log/nginx/{dokuji_domain}.error.log;
+ }
証明書がないとエラーになるので、openssl
をつかって入れておきます。
$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/{dokuji_domain}.key \
-out /etc/ssl/{dokuji_domain}.pem
次に、Nginxの構文があっているかどうかチェックします。ミスっている場合、ミスの内容が出てくるので生成AIとかに聞いてみるとすぐに解決します。だいたいは、インデントのミス、終端記号(;)が抜けてるとか、そういうところだと思います。
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
再起動。
$ sudo systemctl restart nginx
指定したフォルダをつくって、よくある権限を付与します。
$ sudo mkdir -p /var/www/{dokuji_domain}/production/public
$ sudo chown -R nginx:nginx /var/www/{dokuji_domain}
$ sudo chmod -R 755 /var/www/{dokuji_domain}
index.php
にテストをつくります。
$ sudo nano /var/www/{dokuji_domain}/production/public/index.php
+ <?php
+ echo "Hello, your world!";
+ phpinfo();
まだPHPの設定ができてないので、PHPをやっていきます。
PHP
スクリプト言語はPHPを入れます。
# バージョン確認
$ sudo dnf module list php
php 8.1 common [d], devel, minimal PHP scripting language
php 8.2 common [d], devel, minimal PHP scripting language
# Remiリポジトリを追加
$ sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-9.rpm -y
# PHP8.2を追加
$ sudo dnf module reset php -y
$ sudo dnf module enable php:remi-8.2 -y
$ sudo dnf install php php-fpm php-mysqlnd php-opcache php-gd php-xml php-mbstring -y
# php-fpm開始
$ sudo systemctl start php-fpm
$ sudo systemctl enable php-fpm
# バージョン確認
$ sudo php -v
PHP 8.2.28 (cli) (built: Mar 11 2025 17:58:12) (NTS gcc x86_64)
NginxはPHPを処理できないため、プロセスマネージャー(PHP-FPM)を入れる必要があります。
PHP-FPMの設定
PHP-FPMをNginxにあわせて設定していきます。per-requestベースのPHPがオーバーヘッドにならないように処理してくれます。
/etc/php-fpm.d/www.conf
がベースのファイルになります。
$ sudo nano /etc/php-fpm.d/www.conf
; RPM: apache user chosen to provide access to the same directories as httpd
- user = apache
+ user = nginx
; RPM: Keep a group allowed to write in log dir.
- group = apache
+ group = nginx
; Set permissions for unix socket, if one is used. In Linux, read/write
- ;listen.owner = nobody
- ;listen.group = nobody
- ;listen.mode = 0660
+ listen.owner = nginx
+ listen.group = nginx
+ listen.mode = 0660
- security.limit_extensions = .php .php3 .php4 .php5 .php7
+ security.limit_extensions = .php
- php_value[session.save_path] = /var/lib/php/session
+ ;php_value[session.save_path] = /var/lib/php/session
+ ;php_admin_value[config_file_path] = /etc/php.ini
session.save_path
はあとでphp.ini
側から調整するので、ここでは無効化しています。php_admin_value[config_file_path]
は、あとでphpの設定ファイルをつなげるので、コメントアウト状態で追記しておきます。
php-fpmの設定をプロジェクトごとにつくりたいので、プールをつくります。
# PHP-FPMプールをコピー
$ sudo cp /etc/php-fpm.d/www.conf /etc/php-fpm.d/{dokuji_domain}.conf
$ sudo nano /etc/php-fpm.d/{dokuji_domain}.conf
+ php_admin_value[config_file_path] = /etc/php.d/{dokuji_domain}.ini
$ sudo systemctl start php-fpm
$ sudo systemctl enable php-fpm
# ちゃんと反映されているか確認
$ sudo systemctl status php-fpm
php.ini
PHPの設定ファイルを設定していきます。まずはどこにあるか確認します。
$ sudo php --ini
Configuration File (php.ini) Path: /etc
Loaded Configuration File: /etc/php.ini
Scan for additional .ini files in: /etc/php.d
...
# ベースファイルを確認する
$ sudo cat /etc/php.ini
[PHP]
;;;;;;;;;;;;;;;;;;;
; About php.ini ;
;;;;;;;;;;;;;;;;;;;
; PHP's initialization file, generally called php.ini, is responsible for
; configuring many of the aspects of PHP's behavior.
PHPの設定ファイルになります。いろんなところに置いてある可能性があるため、どこにあるか確認しておきます。今回は/etc/php.ini
にあります。たまにetc/php/{php_version}/php.ini
みたいなところにも置いてあることがあります。
php.ini
のよく使う設定を見ておきます。更新もします。
$ sudo nano /etc/php.ini
;;;;;;;;;;;;;;;;;;;;
; Language Options ;
;;;;;;;;;;;;;;;;;;;;
- disable_functions =
+ disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
- ;realpath_cache_size = 4096K
+ realpath_cache_size = 4096K
- ;realpath_cache_ttl = 120
+ realpath_cache_ttl = 120
;;;;;;;;;;;;;;;;;
; Miscellaneous ;
;;;;;;;;;;;;;;;;;
- expose_php = On
+ expose_php = Off
;;;;;;;;;;;;;;;;;;;
; Resource Limits ;
;;;;;;;;;;;;;;;;;;;
- memory_limit = 128M
+ memory_limit = 256M
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Error handling and logging ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
;;;;;;;;;;;;;;;;;
; Data Handling ;
;;;;;;;;;;;;;;;;;
- post_max_size = 8M
+ post_max_size = 20M
;;;;;;;;;;;;;;;;
; File Uploads ;
;;;;;;;;;;;;;;;;
- upload_max_filesize = 2M
+ upload_max_filesize = 10M
;;;;;;;;;;;;;;;;;;
; Fopen wrappers ;
;;;;;;;;;;;;;;;;;;
- allow_url_fopen = On
+ allow_url_fopen = Off
allow_url_include = Off
;;;;;;;;;;;;;;;;;;;
; Module Settings ;
;;;;;;;;;;;;;;;;;;;
[Session]
;session.save_path = "/tmp"
- session.use_strict_mode = 0
+ session.use_strict_mode = 1
- ;session.cookie_secure =
+ session.cookie_secure = On
- session.cookie_lifetime = 0
+ session.cookie_lifetime = 86400
- session.cookie_httponly =
+ session.cookie_httponly = On
- session.cookie_samesite = ""
+ session.cookie_samesite = "Lax"
それぞれの項目の説明は割愛します。クッキー・セッション、あるいはキャッシュあたりはとくにプロジェクトによって大きく変わると思います。ご留意ください。
これをベースのファイルにします。次に、設定ファイルはプロジェクトごとにつくりたいので、コピーします。
$ sudo cp /etc/php.ini /etc/php.d/{dokuji_domain}.ini
$ sudo nano /etc/php.d/{dokuji_domain}.ini
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Error handling and logging ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;error_log syslog
+ error_log = "/var/log/{dokuji_domain}/production/log/"
[session]
- ;session.save_path = "/tmp"
+ session.save_path = "/var/log/{dokuji_domain}/production/session/"
ログとセッションの権限まわりの設定。
# パーミッション
$ sudo chmod 1733 /var/log/{dokuji_domain}/production/log/
$ sudo chmod 1733 /var/log/{dokuji_domain}/production/session/
$ sudo chown nginx:nginx /var/log/{dokuji_domain}/production/log/
$ sudo chown nginx:nginx /var/log/{dokuji_domain}/production/session/
# SELinuxの設定
$ sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/log/{dokuji_domain}/production/log(/.*)?"
$ sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/log/{dokuji_domain}/production/session(/.*)?"
$ sudo restorecon -Rv /var/log/{dokuji_domain}/production/log/
$ sudo restorecon -Rv /var/log/{dokuji_domain}/production/session/
$ sudo ls -Z /var/log/{dokuji_domain}/production/log/
$ sudo ls -Z /var/log/{dokuji_domain}/production/session/
再起動します。
$ sudo systemctl restart nginx
# 最後尾に追加されたか確認
$ sudo php --ini
BASIC認証
Nginxの設定ファイルのなかにBASIC認証をかけています。いちおう/procuction/.htpasswd
にBASIC認証の値を置くように記述しましたが、好きなところに置いてください。
以下のコマンドでつくります。{basicauth_username}には好きな名前をいれ、ランダムなパスワードは一度しか表示されないので、逃さぬようにコピーしてください。
$ RANDOM_PASSWORD=$(openssl rand -base64 12) && HASHED_PASSWORD=$(openssl passwd "$RANDOM_PASSWORD") && echo "{basicauth_username}:$HASHED_PASSWORD" >> /var/www/{dokuji_domain}/production/.htpasswd && echo "ランダムなパスワードはこちら(メモしてください): $RANDOM_PASSWORD"
GUIからつくれるウェブアプリもあります。お好みでやってください。
SELinux
いまのままだと403エラーになると思います。SELinuxの
$ sudo ls -Z /var/www/{dokuji_domain}/production/public/index.php
unconfined_u:object_r:var_t:s0 /var/www/{dokuji_domain}/production/public/index.php
もしvar_tというタイプになっていたら、ウェブサーバーがアクセスできなくなっているので、このディレクトリにアクセスできるようにします。
以下のchconコマンドは、SELinuxセキュリティコンテキストを変更するコマンドです。-Rオプションは、中身のサブディレクトリとかファイルに再帰的にかけていくオプションです。
$ sudo chcon -R -t httpd_sys_content_t /var/www/{dokuji_domain}/production/
$ sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/{dokuji_domain}/production(/.*)?"
$ sudo restorecon -R /var/www/{dokuji_domain}/production
$ sudo ls -Z /var/www/{dokuji_domain}/production
unconfined_u:object_r:httpd_sys_content_t:s0 index.php
これでも403になる場合は、ファイアウォールの設定(httpサービスあたり)、ファイルの権限が足りていない、Nginxの書きかたがミスっているなどが考えられます。ログを見たり、設定を確認してみたり、AIと一問一答してデバッグしてみてください。
(任意)オペコードキャッシュ
とりわけキャッシュに関しては、オペコードキャッシュを確認したいと思います。いま編集していたphp.ini
のなかに以下のような記述があります。
[opcache]
; see /etc/php.d/10-opcache.ini
オペコードキャッシュというのは、PHPはper-requestで毎回初期化して動くプログラミング言語ですが、スクリプトのコンパイル後のオペコードをキャッシュとしてメモリ上につくってくれる機能です。
$ sudo php -i
phpinfo()
PHP Version => 8.0.30
...
opcache.enable => On => On
デフォルトで有効になっていました。せっかくなので細かく設定していきます。不要なかたはスキップしてください。
$ sudo nano /etc/php.d/10-opcache.ini
opcache.enable=1
- ;opcache.memory_consumption=128
+ opcache.memory_consumption=128
- ;opcache.max_accelerated_files=10000
+ opcache.max_accelerated_files=10000
- ;opcache.validate_timestamps=1
+ opcache.validate_timestamps=0
- ;opcache.revalidate_freq=2
+ opcache.revalidate_freq=2
- ;opcache.save_comments=1
+ opcache.save_comments=1
- ;opcache.file_cache_consistency_checks=1
+ opcache.file_cache_consistency_checks=0
本番環境っぽくしています。それぞれの機能は割愛します。
.htaccessが存在しない世界
いわゆる「レンタルサーバー」を借りていると、Nginxで高速!
と謳われているのにもかかわらず、.htaccess
でサーバーの設定をオーバーライドできるものがあります。
これは、レンタルサーバー自体はNginxですが、実際にお借りしているアプリケーション側はApache HTTP Server(.htaccessがつかえる)上でワークしている、という仕組みになっています。
今回はNginxの性能を無駄にしたくないので、Apache HTTP Serverを入れません。なので、これまで.htaccess
に記述していた内容をさきほど編集していた/etc/nginx/conf.d/{dokuji_domain}.conf
や/etc/php.d/{dokuji_domain}.ini
に追記する必要があります。
どちらに書くかは案件によるかもしれませんが、基本はリクエストに関するもの(PHPファイルをPHP-FPMに接続・リクエストエラー処理・BASIC認証含め)や静的ファイルの払い出しなどをNginxのconfファイルに記述し、PHPに関すること(エラーログの出力・メモリ制限・セッションの設定など)をphp.ini
に記述すると、目的に沿って整理されてよいと思います。
あるいは、レンタルサーバーふうにしたい場合は共存方法を模索してみてください。
SFTP
sshの設定ファイルを少し変えます。
$ sudo nano /etc/ssh/sshd_config
# override default of no subsystem
- Subsystem sftp /usr/libexec/openssh/sftp-server
+ Subsystem sftp internal-sftp
外部プログラムを呼び出さないようにします。設定を変えたので再起動します。
$ sudo systemctl restart sshd
クライアントアプリからログインします。
sftp
接続で、host
的なところにじぶんのサーバーのIPアドレスを入力し、user
的なところに一般ユーザの名前を入れて、鍵は最初のほうにつくったPEM形式の鍵です。
正しく入力したらサーバー内に入れると思いますが、ホームページを更新する/var/www/
配下を更新できないので、{username}でも更新できるように権限変更します。
$ sudo chown -R {username}:nginx /var/www/
(便利機能)エディターから直接更新
Cursor(VS Code)から更新できるようにします。
VSCodeの拡張機能がつかえるので、今回は「SFTP」を導入してみます。
+ {
+ "name": "{好きな名前}",
+ "host": "{ipaddress}",
+ "protocol": "sftp",
+ "port": 2222,
+ "username": "{username}",
+ "privateKeyPath": "~/.ssh/xserver_{username_keyname}.pem",
+ "remotePath": "/var/www/{dokuji_domain}/production/",
+ "uploadOnSave": true,
+ "ignore": [".vscode/",".DS_Store"]
+ }
.vscode/sftp.json
に設定ファイルを書くと、SFTP接続できます。ファイルを更新すると、サーバーのファイルが更新されます。
更新されたら困るファイルはignore
にリストアップできます。
デプロイについては今回は割愛いたします。
MySQL
DBにはオープンソースソフトウェアの「MySQL」を利用します。インストールして常に有効にします。
$ sudo dnf install mysql-server -y
$ sudo mysql -v
$ sudo systemctl start mysqld
$ sudo systemctl enable mysqld
Created symlink /etc/systemd/system/multi-user.target.wants/mysqld.service → /usr/lib/systemd/system/mysqld.service.
次は、MySQLで最初にやるセキュリティ設定です。mysql_secure_installation
をはじめると、いろいろ問い合わせがくるので、答えていきます。途中で初回パスワードを聞かれるので、メモっておくのを失念しないようにきをつけてください。
まずはパスワードをつくっておきます。
$ for i in {1..2}; do
openssl rand -base64 24 | tr -dc 'a-zA-Z0-9!@#$%^&*()_+-=' | fold -w 24 | head -n 1
done
2個出てくるのは、最初にroot用のパスワードが必要で、そのあと一般用のユーザーのパスワードが必要だからです。両方メモっておいてください。
$ sudo mysql_secure_installation
# パスワード検証プラグインを使用するかどうか
VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?
Press y|Y for Yes, any other key for No: Y
# パスワード強度のレベル選択
There are three levels of password validation policy:
LOW Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary file
Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 2
# パスワード入力(STRONGは8文字以上、数字、小文字大文字混在、特殊文字、アタックされる辞書ファイルの回避)
Please set the password for root here.
New password: {mysql_strong_password}
Re-enter new password: {root_database_password}
# 匿名ユーザーの削除
Remove anonymous users? (Press y|Y for Yes, any other key for No) : Y
# rootログインのリモート実行の禁止
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : Y
# テストデータベースの削除
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : Y
次に、先ほどのパスワードでMySQLにログインして、一般ユーザーをつくるところまでいきます。
# ログイン
$ sudo mysql -u root -p
# バージョン確認
$ SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 8.0.41 |
+-----------+
# 文字コードの確認
$ show variables like "chara%";
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8mb3 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
# (任意)プラグインの確認
$ SHOW PLUGINS;
+---------------------------------+----------+--------------------+---------+---------+
| Name | Status | Type | Library | License |
+---------------------------------+----------+--------------------+---------+---------+
| binlog | ACTIVE | STORAGE ENGINE | NULL | GPL |
| mysql_native_password | ACTIVE | AUTHENTICATION | NULL | GPL |
| sha256_password | ACTIVE | AUTHENTICATION | NULL | GPL |
| caching_sha2_password | ACTIVE | AUTHENTICATION | NULL | GPL |
| sha2_cache_cleaner | ACTIVE | AUDIT | NULL | GPL |
| daemon_keyring_proxy_plugin | ACTIVE | DAEMON | NULL | GPL |
| CSV | ACTIVE | STORAGE ENGINE | NULL | GPL |
| MEMORY | ACTIVE | STORAGE ENGINE | NULL | GPL |
| InnoDB | ACTIVE | STORAGE ENGINE | NULL | GPL |
# MySQLデータベースの作成
$ CREATE DATABASE {database_name};
# MySQLユーザーの作成(usernameとpasswordを入れてください)
$ CREATE USER '{database_username}'@'%' IDENTIFIED BY '{database_password}';
# いまつくったユーザーに権限付与(外部アプリからもアクセスできるようにします)
$ GRANT ALL PRIVILEGES ON *.* TO '{database_username}'@'%' WITH GRANT OPTION;
# 更新
$ FLUSH PRIVILEGES;
# 権限確認
$ SELECT user, host FROM mysql.user;
+------------------+-----------+
| user | host |
+------------------+-----------+
| {database_username}| % |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+-----------+
# (おまけ)ユーザーの削除
$ DROP USER '{database_username}'@'%'
# mysqlからいったん出る
$ quit;
bye
次は、設定を変更します。
いまはメインの設定ファイル(/etc/my.conf
)の[mysqld]セクション
に直接書き込んでいきますが、案件によっては/etc/my.cnf.d/mysql-server.cnf
のような分割ファイルに書き込むことも検討できると思います。
$ sudo nano /etc/my.cnf
+ [mysqld]
+ bind-address = 0.0.0.0
+ default_authentication_plugin = caching_sha2_password
+ default_password_lifetime = 0
+ innodb_buffer_pool_size = 1024M
+ timezone = Asia/Tokyo
タイムゾーンを変えたので更新します。
$ sudo mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql -p
mysqlのrootユーザーのパスワードを入力
# 検証・再起動
$ sudo mysqld --validate-config
$ sudo systemctl restart mysqld
SELinuxのほうのポート制御もいちおう確認しておきます。
$ sudo semanage port -l | grep mysqld
mysqld_port_t tcp 1186, 3306, 63132-63164
(任意)DBバックアップ
DBを利用する場合は、自動でバックアップをとっておくにこしたことないです。
$ sudo nano /etc/cron.daily/mysql_backup.sh
+ #!/bin/bash
+
+ # バックアップディレクトリ
+ BACKUP_DIR="/var/backups/mysql"
+ # MySQLユーザー名
+ MYSQL_USER="{database_username}"
+ # MySQLパスワード
+ MYSQL_PASSWORD="{database_password}"
+ # MySQLデータベース名
+ DATABASE_NAME="{database_name}"
+ # バックアップファイル名
+ BACKUP_FILE="$BACKUP_DIR/backup_$(date +%Y%m%d_%H%M%S).sql"
+
+ # バックアップディレクトリが存在しない場合は作成
+ mkdir -p $BACKUP_DIR
+
+ # MySQLダンプの実行
+ mysqldump -u $MYSQL_USER -p$MYSQL_PASSWORD $DATABASE_NAME > $BACKUP_FILE
+
+ # 古いバックアップファイルを削除(例: 30日以上前のファイル)
+ find $BACKUP_DIR -type f -name "*.sql" -mtime +30 -exec rm {} \;
+
+ echo "Backup completed: $BACKUP_FILE"
権限付与します。
$ sudo chmod +x /etc/cron.daily/mysql_backup.sh
rootに移動して、スケジューラー(cron)を設定します。
$ su
$ crontab -e
+ 0 2 * * * /etc/cron.daily/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1
外部アプリからMySQLにログイン
外部アプリ(クライアントアプリ)から、ログインするときに、以下の情報が必要なので、入力してテスト接続してみてください。わたしは、冒頭で紹介した「DBeaver」がかわいいのでつかってます。
ホスト: {ipaddress}
ポート: 3306
データベース名:{database_name}
ユーザー名: {database_username}
パスワード: {database_password}
SSH側
ホスト:{ipaddress}
ポート:22
ユーザー:{username}
パスワード:ここは使いません
プライベートキー:~/.ssh/xserver_{key_name}.pem
接続できない場合は、ファイアウォールのポート、SELinuxのセキュリティコンテキストあたりで閉じられているかもしれません。それ以上に多いのは、入力ミスです。わたしもよくまちがって何時間か失っています。
接続できたら、users
テーブルとか、articles
テーブルとかいろいろつくれます。SQLやテーブル設計の話は割愛します。
完成(完成したとは言ってない)
OS(AlmaLinux)
のうえに、Nginx
が入り、PHP
ファイルについてはPHP-FPM
で処理され、同ホスト上でMySQL
と接続しました。
ドメインまわりが完了していたら、ひとまずかたちになった、というところです。ドメインまわりはがっつり割愛しましたが、あらためてCloudflare
がおすすめです。
ここからはプラスアルファ、大事なところを詰めていきます。
ログ監視
ログウォッチを入れてログを監視します。
$ sudo dnf install logwatch -y
設定はいろいろあると思いますが、ここでは一例を書いておきます。
$ sudo nano /etc/logwatch/conf/logwatch.conf
+ # ログの詳細レベル (Low, Med, High)
+ Detail = High
+
+ # レポートの出力形式 (text, html, mail)
+ Output = mail
+
+ # レポートの形式 (std, pretty)
+ Format = html
+
+ # レポートの送信先メールアドレス
+ MailTo = {email}
+
+ # レポートの送信元メールアドレス
+ MailFrom = logwatch@y{dokuji_domain}
+
+ # レポートの範囲 (All, Today, Yesterday)
+ Range = Yesterday
+
+ # 監視するサービス (すべてのサービスを監視する場合は 'All' を指定)
+ Service = All
+
+ # 特定のサービスを除外する場合
+ # Service = "-zz-network" # 例: ネットワーク関連のログを除外
+
+ # ログファイルの場所を指定 (デフォルトは /var/log)
+ LogDir = /var/log
+
+ # アーカイブされたログファイルも含める
+ Archives = Yes
+
+ # タイムゾーンを日本時間 (JST) に設定
+ Timezone = Asia/Tokyo
+
+ # レポートの言語を指定
+ Language = ja
logwatch@{dokuji_domain}
としましたが、メールアドレスのつくりかたは割愛します(Cloudflareだと「メールアドレス」から新規作成できます)。
メールアドレスが設定できたら、試しにやってみましょう。
# 試しに表示する
$ sudo logwatch --detail High --output stdout --range yesterday
# メール送信
$ sudo logwatch --output mail
# タイムゾーンの確認
$ timedatectl
次に、監視が自動実行であることを確認します。スケジューラー(cronジョブ)を見ます。
$ sudo ls -la /etc/cron.daily/0logwatch
-rwxr-xr-x. 1 root root 486 Sep 27 2023 /etc/cron.daily/0logwatch
ファイル同期
$ sudo dnf install rsync -y
$ sudo rsync --version
rsync version 3.2.3 protocol version 31
時間合わせ
まずは有効化する。
$ sudo chronyc sources -v
$ sudo systemctl enable chronyd
設定を変えます。
# 日本の国立研究開発法人情報通信研究機構(NICT)が提供するNTPサーバー
$ sudo nano /etc/chrony.conf
- pool 2.almalinux.pool.ntp.org iburst
+ pool ntp.nict.jp iburst
再起動します。
$ sudo systemctl restart chronyd
# 再同期
$ sudo chronyc makestep
# 表示
$ sudo chronyc tracking
Ref time (UTC) : Fri Mar 07 23:52:21 2025
System time : 0.000000036 seconds slow of NTP time
メールサーバー
Postfix
メールサーバーをインストールします。
# インストール
$ sudo dnf install postfix -y
# メール転送エージェント(MTA)の設定確認
$ sudo alternatives --display mta
# Postfixのバージョン情報
$ sudo postconf |grep mail_version
mail_version = 3.5.25
milter_macro_v = $mail_name $mail_version
多言語的にする予定がなく、RFC 6531標準にのっとらなくていい場合は、SMTPUTF8を無効にしたほうがいいと思うので、下記の設定ファイルを追記。案件によると思います。
$ sudo nano /etc/postfix/main.cf
+ smtputf8_enable = no
常に有効にして反映します。
$ sudo systemctl start postfix
$ sudo systemctl enable postfix
$ sudo systemctl restart postfix
アンチウイルスソフト
EPEL(Extra Packages for Enterprise Linux)リポジトリから取得します。
$ sudo dnf install epel-release -y
$ sudo dnf install clamav clamd clamav-update -y
# ClamAVのウイルス定義データベースを最新にします
$ sudo freshclam
Database test passed.
bytecode.cvd updated (version: 335, sigs: 86, f-level: 90, builder: raynman)
# 実行(ファイルでもディレクトリでもOK)
$ sudo clamscan -r --remove {test_filepath/dirpath}
----------- SCAN SUMMARY -----------
Known viruses: 8704988
Engine version: 1.0.8
Scanned directories: 130
Scanned files: 567
Infected files: 0
Data scanned: 494.99 MB
Data read: 235.77 MB (ratio 2.10:1)
Time: 47.687 sec (0 m 47 s)
--remove
オプションは感染ファイルやディレクトリを削除するオプションなので、つけないでもいいかもしれません。たとえば、sudo clamscan -r /var/www/{dokuji_domain}
とすれば、今回つくった独自ドメインのファイルをすべてチェックできます。
ブルートフォース攻撃を防ぐ
$ sudo dnf install fail2ban -y
ファイルは以下のところにあります。
$ sudo cat /etc/fail2ban/jail.conf
追加設定は別のファイルに置きます。
$ sudo nano /etc/fail2ban/jail.local
+ [sshd]
+ enabled = true
+ maxretry = 3
+ bantime = 3600
(任意)EXIFデータを削除する
画像ファイルにセンシティブなメタ情報が付与されていることがあるので、常に削除するほうがよいです。-overwrite_original
というオプションをいれるとバックアップをとらないです。
$ sudo dnf install perl-Image-ExifTool -y
$ sudo exiftool -all= -overwrite_original var/www/{dokuji_domain}/production/public/assets/images/{image_filepath}
(Cloudflareのみ)CloudflareのSSLの証明書設定
Cloudflareの指示にしたがって加工します。Cloudflareじゃないひとはスキップしてください。
ここからキーを作成します。.pem
と.key
です。
$ sudo nano /etc/ssl/{dokuji_domain}.pem
指定のキーを入れる
$ sudo chmod 600 /etc/ssl/{dokuji_domain}.pem
$ sudo nano /etc/ssl/{dokuji_domain}.key
指定のキーを入れる
$ sudo chmod 600 /etc/ssl/{dokuji_domain}.key
# ログファイルディレクトリの権限を755にする
$ sudo chown nginx:nginx /var/log/nginx
$ sudo chmod 755 /var/log/nginx
# ログファイル作成
$ sudo touch /var/log/nginx/nginx.vhost.error.log
$ sudo chown nginx:nginx /var/log/nginx/nginx.vhost.error.log
$ sudo chmod 644 /var/log/nginx/nginx.vhost.error.log
$ sudo touch /var/log/nginx/nginx.vhost.access.log
$ sudo chown nginx:nginx /var/log/nginx/nginx.vhost.access.log
$ sudo chmod 644 /var/log/nginx/nginx.vhost.access.log
# 再起動
$ sudo systemctl restart nginx
(困ったとき)ログを見る
$ sudo tail -f /var/log/nginx/error.log
$ sudo ls -Z /var/www
$ sudo ausearch -m avc -ts recent
$ sudo cat /var/log/audit/audit.log
$ sudo cat /var/log/secure
$ sudo tail -f /var/log/secure
SSHログインを楽にする
ローカルの~/.ssh/config
ファイルにVPSのデータを記載しておくと、ログインが少し楽になります。
+ ################################################################
+ # XSERVER VPS
+ ################################################################
+ Host {server_short_name}
+ Hostname {ipaddress}
+ User {username}
+ Port 2222
+ IdentityFile ~/.ssh/xserver_{username}.pem
下記コマンドでログインできるようになります。
$ ssh {server_short_name}
参考記事
まとめ
2025年にVPSというのはすこしヘンな感じもしますが、このあたりは一回おぼえると毎回あんまりやること変わらないのでスキル的にも消費期限が長くありがたいです。
初心者のかたでわかりづらいところがあれば、Twitterから教えていただけるとうれしいです。
Discussion