カテゴリー: サーバー管理

  • WordPress シングルインスタンス―マルチデータベース

     一つの物理OS上で複数の仮想ホストを作成しそれぞれでwordpressのサイトを稼働させている。

     wordpressフォルダーを複数用意していたが、領域が二重に必要になったり、それぞれで更新するなど管理が面倒になってくる。

     データベースエンジンは1インスタンスだが、それぞれのサイトに専用のデータベースを利用している。

     そこで、複数サイトでそれぞれのデータベースを利用する設定ができないか試してみた。

    ここでは以下の3つの形態を説明している。

    1. WordPress マルチサイト機能 (単一のデータベースを持つ単一のWordPress インスタンス)
    2. 単一のデータベースを持つ複数の WordPress インスタンス
    3. 複数のデータベースを持つ複数の WordPress インスタンス

    しかし、以下のような形態には触れられていない。

    • 複数のデータベースを持つ単一のWordPressインスタンス

     ちなみに、ここでいうデータベースとは、データベースエンジン(xamppではMySQL)のことではなく、MySQLが管理している複数のデータベースのうちの一つのことらしい。ソフトウェア開発ではどちらも意味することがあるから前後の文脈から判断しないといけない。

     インスタンスは二つある気がするけど、複雑になるからこのままの表記で行おう。

     ここには、単一のデータベースを持つ単一のWordPressインスタンスで複数ドメインの運用例が載っている。

     ここを参考にして、修正を行った。

     /wordpress/wp-config.phpを以下のように書き変える。

    // homeとsiteurlの指定
    // homeで/wordpressが省略されているときは、siteurlに追加する
    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
    define( 'WP_HOME', $protocol . $_SERVER['HTTP_HOST']  );
    if (strpos(WP_HOME, '/wordpress') !== false) {
        define( 'WP_SITEURL', WP_HOME );
    } else {
        define( 'WP_SITEURL', WP_HOME . '/wordpress' );
    }
    
    // アップロードフォルダーの指定
    if ( strpos(WP_HOME, 'www2.') !== false ) {
    	define( "UPLOADS", "wp-content/uploads/www2" );
    }
    
    // ** MySQL 設定 - この情報はホスティング先から入手してください。 ** //
    /** WordPress のためのデータベース名 */
    // www2.domain.comのときはデータベースwp-02を指定する
    if (strpos(WP_HOME, 'www2.') !== false) {
    	define( 'DB_NAME', 'wp-02' );
    } else {
    	define( 'DB_NAME', 'wp-01' );
    }

     アップロードフォルダーも別にしたいので、指定を追加した。

     /wordpressを省略しているので、サイトトップのindex.phpも同じwordpressフォルダーを指すように変更しておく。

    require __DIR__ . '/../../wordpress/wp-blog-header.php';

     ダッシュボードの設定-一般を開くと、WordPress アドレス (URL)とサイトアドレス (URL)は入力できなくなっている。たぶん事前に定義されていたのは変更不可となるのだろう。なかなかかしこい。

     行儀の悪いプラグインとか動かない可能性もあるらしいが、様子見しよう。

  • WordPress バックアップ

     サーバー自体のバックアップとは別にWordPressの設定、データベースのバックアップを定期的に行う。

     設定ファイル等はrobocopyで存在するファイルのみ新しいものをコピーする。

     データベースは、SQLファイルとして毎日1回出力する。

     サーバー上に保存するとインスタンスを削除したときに消えてしまうのでローカルPCに保存する。そのため、リモート接続を行ったときにのみ行うこととした。

     あらかじめローカルPCにはバックアップしたい設定ファイル等のファイルを同じ階層構造でコピーしておく。

     システム環境変数にローカルPCのフォルダーパスを定義しておく。

    WORDPRESS_BACKUP=\\tsclient\C\Backup

     ローカルPCにファイルを保存するため、タスクスケジューラーでリモートデスクトップ接続したときに実行するように設定しておく。その際、ローカルリソースのCドライブを利用することを指定している。

    Backup.bat

    @echo off
    echo %DATE%-%TIME: =0% : Excecuting ... %0 %*
    rem DATEの出力で、先頭に曜日が漢字一文字で表示されることがある。
    rem その場合は設定-時計と言語-日付と時刻-日付と時刻の形式を変更するで、
    rem 日付(短い形式)でyyyy/MM/ddを選ぶと曜日が出力されなくなるようだ。
    rem OSのバージョンによっては、設定-時刻と言語-日付と時刻-日付、時刻、地域の書式設定-データ形式を変更する
    if not "%1" == "" goto :BACKUP
    
    setlocal
    
    if not exist %~d0%~p0log mkdir %~d0%~p0log
    
    set LOG_FILE=%~d0%~p0log\%COMPUTERNAME%_Backup_%date:~-10,4%-%date:~-5,2%-%date:~-2,2%.log
    
    if "%WORDPRESS_BACKUP%" == "" (
        echo no backup placement >> %LOG_FILE% 2>&1
        echo set WORDPRESS_BACKUP=xxx >> %LOG_FILE% 2>&1
        endlocal
    
        EXIT /B
    )
    
    if not exist %LOG_FILE% (
        rem ログファイルへ出力するため、あえてファイルを通して呼び出す
        for %%f in (ProgramData Squid xampp) do call %0 %%f >> %LOG_FILE% 2>&1
    
        call BackupMySQL.bat >> %LOG_FILE% 2>&1
    )
    
    endlocal
    
    EXIT /B
    
    :BACKUP
    
    setlocal
    
    if exist \%1 (
      if not "%WORDPRESS_BACKUP%" == "" (
          echo robocopy  \%1 %WORDPRESS_BACKUP%\%1 /S /XJ /XO /XX /XL /NP
          robocopy  \%1 %WORDPRESS_BACKUP%\%1 /S /XJ /XO /XX /XL /NP
      )
    )
    
    endlocal
    
    EXIT /B

     時刻が%TIME: =0%となっているのは、10:00より前は10時台が0サプレスされるのでスペースを0に置き換えている。

    BackupMySQL.bat

    @echo off
    echo %DATE%-%TIME: =0% : Excecuting ... %0 %*
    rem MAX_FILES 残す個数
    
    setlocal
    
    set /a MAX_FILES=0
    if not "%1" == "" set /a MAX_FILES=%1
    
    for %%i in (wp-01 wp-02) do call :MYSQLDUMP %%i %MAX_FILES%
    endlocal
    
    EXIT /B
    
    
    :MYSQLDUMP
    
    setlocal
    
    if not exist %~d0%~p0MySQL mkdir %~d0%~p0MySQL
    set SQL_FILE=%~d0%~p0MySQL\%COMPUTERNAME%_%1_%date:~-10,4%-%date:~-5,2%-%date:~-2,2%.sql
    
    if not exist %SQL_FILE% (
        echo C:\xampp\mysql\bin\mysqldump -u -p %1
        C:\xampp\mysql\bin\mysqldump -u ユーザー名 -pパスワード %1 > %SQL_FILE%
    
        if not "%WORDPRESS_BACKUP%" == "" (
            if not exist %WORDPRESS_BACKUP%\xampp\Tools\MySQL mkdir %WORDPRESS_BACKUP%\xampp\Tools\MySQL
            echo copy /Y %SQL_FILE% %WORDPRESS_BACKUP%\xampp\Tools\MySQL\
            copy /Y %SQL_FILE% %WORDPRESS_BACKUP%\xampp\Tools\MySQL\
        )
    )
    
    endlocal
    
    EXIT /B

     mysqldumpのパスワード指定は、-pの後に空白を開けず続けて指定する。

  • サーバー証明書を取得

     Let’s Encryptでサーバー証明書を作成した。

     apacheのmod_mdモジュールでの作成、更新ができるらしいとどこかで見たので、試してみたがうまくいかない。
     どうもWindowsでは動かないらしい。

    http://apache-http-server.18135.x6.nabble.com/mod-md-1-1-0-repeating-on-error-td5040498.html

     とりあえず、IIS用 ツールをWindowsサーバにインストール。
     https://github.com/win-acme/win-acme/releases からwin-acme.v2.1.9.870.x64.trimmed.zipをダウンロードしてC:\Tooksに解凍。

    Apacheを立ち上げておく。
    C:/xampp/apache/conf/certsフォルダーを作成しておく。ACME.exeを管理者で起動する。

    C:\Tools\win-acmw> acme.exe –test

    Please choose from the menu: m
    How shall we determine the domain(s) to include in the certificate?: 2
    Enter comma-separated list of host names, starting with the common name: domain.com,www.domain.com
    Suggested friendly name ‘[Manual] domain.com’, press <Enter> to accept or type an alternative: <Enter>
    How would you like prove ownership for the domain(s)?: 1
    Path to the root of the site that will handle authentication: C:/xampp/htdocs
    Copy default web.config before validation? (y/n*) – no
    What kind of private key should be used for the certificate?: 2
    How would you like to store the certificate?: 2
    Path to folder where .pem files are stored: C:/xampp/apache/conf/certs
    Would you like to store it in another way too?: 5
    Which installation step should run first?: 4
    Enter email(s) for notifications about problems and abuse (comma seperated): postmaster@domain.com
    Terms of service: C:\ProgramData\win-acme\acme-v02.api.letsencrypt.org\LE-SA-v1.2-November-15-2017.pdf Open in default application? (y/n*) n
    Authorize identifier www.domain.com
    Authorizing www.domain.com using http-01 validation (FileSystem)
    Answer should now be browsable at http://www.domain.com/.well-known/acme-challenge/xxxxxxxxxxxxxxxx
    Preliminary validation looks good, but the ACME server will be more thorough
    Authorization result: valid
    Requesting certificate [Manual] domain.com
    Store with PemFiles…
    Exporting .pem files to C:/xampp/apache/conf/certs
    Installing with None…
    Adding Task Scheduler entry with the following settings
    – Name win-acme renew (acme-v02.api.letsencrypt.org)
    – Path C:\Tools\win-acme.v2.1.9.870.x64.trimmed
    – Command wacs.exe –renew –baseuri “https://acme-v02.api.letsencrypt.org/”
    – Start at 09:00:00
    – Time limit 02:00:00

    Do you want to specify the user the task will run as? (y/n*) – no
    How shall we determine the domain(s) to include in the certificate?: c
    Please choose from the menu:q

     正常に終了するとタスクスケジューラーにwin-acme renew (acme-v02.api.letsencrypt.org)タスクが追加される。

     ステージングサーバー用と両方のタスクが登録されていると、ほぼ同時にフォルダーへのアクセスが起きるため、正常に更新されないことがある。どちらかの開始時間をずらしておく。

     作成された証明書をapacheに以下で指定する

    SSLCertificateFile "conf/certs/chombo.work-crt.pem"
    SSLCertificateKeyFile "conf/certs/chombo.work-key.pem"
    SSLCertificateChainFile "conf/certs/chombo.work-chain.pem"

     apacheを再起動して以下のサイトなどで確認する
    https://www.digicert.com/help/

     最初は–testオプションを付けておき、成功したらオプションを外して実行する。正式版を発行するときは1日置かないと再度実行できないので一発勝負のつもりで。

     複数のホストの入った証明書も可能だけれど、同じローカルフォルダーを参照していないとwin-acmeで認証されないみたい。

     最初は実行途中で異常終了していたので、「Let’s Encrypt の証明書をブラウザ上で簡単取得」で試してみた。

    https://qiita.com/tappie/items/76881fdf7996c57a105a

     ここで作られた署名鍵、RSA秘密鍵をwin-acmeに読ませることでアカウントを設定でき、以後はwin-acmeだけで設定、更新できるようになる。

    自動更新結果のメール連絡

    settings_default.jsonファイルをsettings.jsonファイルにコピーし、メールアカウントを記入する。

      "Notification": {
        "SmtpServer": "mail.domain.com",
        "SmtpPort": 25,
        "SmtpUser": "postmaster",
        "SmtpPassword": "xxxxx",
        "SmtpSecure": true,
        "SmtpSecureMode": 1,
        "SenderName": "win-acme",
        "SenderAddress": "postmaster@domain.com",
        "ReceiverAddresses": ["postmaster@domain.com"],
        "EmailOnSuccess": true,
        "ComputerName": "domain.com"
      },