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

  • サーバー証明書を取得

     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"
      },
    
  • 一つのApache設定ファイルを複数のPCで使う

     自宅とAWS上でほぼ同じ内容のWebサーバーを稼働させている。

    • OS: Windows Server 2016
    • Server version: Apache/2.4.43 (Win64)

     コンテンツはほぼ同じなのだが、ドメイン名とか違っているのでhttpd.confなどがそれぞれ別の内容になっている。

     似たような内容が2か所にコピーされているのは間違いの元なので、一つのconfファイルが使えないかといろいろ試していてやっと実現できた。

     confファイルの中で分岐させるのは<If>とか<SetEnvIf>とか<IfDefine>とかあるけど、<If>とかは実行時にページを要求されるごとに評価されるためか、うまく動かなかった。

     <IfDefine>は起動時に評価されるため、なんとか実現できた模様。

     以下はPC1という名前とPC2という名前の二つのPCが、それぞれdomain1.com,domaein2.comとうドメインを運用している前提で説明する。

    httpd.confでApacheの環境変数を定義する。

    Define COMPUTER_${COMPUTERNAME}
    <IfDefine COMPUTER_PC1>
        Define DOMAIN "domain1.com"
    </ifDefine>
    <IfDefine COMPUTER_PC2>
        Define DOMAIN "domain2.com"
    </ifDefine>

     PCのシステム環境変数COMPUTERNAMEを使ってそれぞれ別のApache環境変数を定義している。

     httpd-vhosts.confなどでは<IfDefine>を使ってそれぞれ固有の設定を記述する。

    <IfDefine COMPUTER_PC1>
    <Directory "C:/xampp/htdocs">
        Options FollowSymLinks
        AllowOverride All
        Require all denied
        Require ip ${IPADDR_LOCAL}
    </Directory>
    </IfDefine>
    
    <IfDefine COMPUTER_PC2>
    <Directory "C:/xampp/htdocs">
        Options FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    </IfDefine>
    
    <VirtualHost *:80>
        ServerAdmin postmaster@${DOMAIN}
        DocumentRoot "C:/xampp/htdocs"
        ServerName www.${DOMAIN}
        ServerAlias ${DOMAIN}
        ErrorLog  "| bin/rotatelogs.exe logs/${DOMAIN}-error_%Y-%m.log  86400"
        CustomLog "| bin/rotatelogs.exe logs/${DOMAIN}-access_%Y-%m.log 86400"
    </VirtualHost>

     上記はPC1だけIPアドレスによるアクセス制限をかけている。

     VirtualHostは、それぞれのドメインを同じ記述で別の定義を行っている。

     それぞれのPC上で、以下のコマンドを使って実行時に設定されている内容を確認する。

    httpd.exe -S                  VirtualHostの確認
    httpd.exe -t -DDUMP_CONFIG    設定の確認
  • WordPress 参加申込フォーム作成

     参加している趣味の団体で、年一回開催しているイベントの参加申込をWordPressでできるようにしたい。

     フォームのプラグインは有名どころだとContact Form 7とWM WP Formがあるみたいなので、とりあえず両方作ってみた。

     プラグインはContact Form 7とその履歴を保存できるFlamingo、WM WP Formを追加する。

     ついでに、郵便番号から住所を自動入力できるyubinbangoも入れておく。

     フォームには定番の氏名、生年月日、住所、メールアドレスなどを入力できるようにしておいた。

    MW WP Form版

    <script src="https://yubinbango.github.io/yubinbango/yubinbango.js" charset="UTF-8"></script>
    <script> document.querySelector('.mw_wp_form_input form').classList.add('h-adr'); </script>
    <span class="p-country-name" style="display:none;">Japan</span>
    
    xxxに参加申し込みします
    <table class="table-res-form">
    <tbody>
    <tr>
    <th>氏名<span class="requied">必須</span></th>
    <td>[mwform_text name="lastname" size="12" placeholder="姓"]</td>
    <td>[mwform_text name="firstname" size="12" placeholder="名"]</td>
    </tr>
    <tr>
    <th>ふりがな<span class="requied">必須</span></th>
    <td>[mwform_text name="lastkana" size="12" placeholder="せい"]</td>
    <td>[mwform_text name="firstkana" size="12" placeholder="めい"]</td>
    </tr>
    <tr>
    <th>生年月日<span class="requied">必須</span></th>
    <td colspan="2">[mwform_select name="birth-year" children="1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038" value="1980"]年 [mwform_select name="birth-month" children="-,1,2,3,4,5,6,7,8,9,10,11,12"]月 [mwform_select name="birth-day" children="-,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31"]日</td>
    </tr>
    <tr>
    <th>性別<span class="requied">必須</span></th>
    <td colspan="2">[mwform_radio name="gender" children="男,女"]</td>
    </tr>
    <tr>
    <th>郵便番号<span class="requied">必須</span></th>
    <td colspan="2">[mwform_text name="zipcode" class="p-postal-code" conv_half_alphanumeric="true" size="10" maxlength="7" placeholder="0000000"]</td>
    </tr>
    <tr>
    <th>都道府県<span class="requied">必須</span></th>
    <td colspan="2">[mwform_select name="pref" class="p-region" children="-,北海道,青森県,岩手県,宮城県,秋田県,山形県,福島県,茨城県,栃木県,群馬県,埼玉県,千葉県,東京都,神奈川県,新潟県,富山県,石川県,福井県,山梨県,長野県,岐阜県,静岡県,愛知県,三重県,滋賀県,京都府,大阪府,兵庫県,奈良県,和歌山県,鳥取県,島根県,岡山県,広島県,山口県,徳島県,香川県,愛媛県,高知県,福岡県,佐賀県,長崎県,熊本県,大分県,宮崎県,鹿児島県,沖縄県" value"長野県"]</td>
    </tr>
    <tr>
    <th>市町村区<span class="requied">必須</span></th>
    <td colspan="2">[mwform_text name="city" class="p-locality" size="20" placeholder="市町村"]</td>
    </tr>
    <tr>
    <th>番地等<span class="requied">必須</span></th>
    <td colspan="2">[mwform_text name="addr1" class="p-street-address p-extended-address" size="40" placeholder="番地等"]</td>
    </tr>
    <tr>
    <th>建物名等</th>
    <td colspan="2">[mwform_text name="addr2" size="40" placeholder="建物名等"]</td>
    </tr>
    <tr>
    <th>電話番号<span class="requied">必須</span></th>
    <td colspan="2">[mwform_text name="phone" size="20" maxlength="15"]</td>
    </tr>
    <tr>
    <th>メールアドレス<span class="requied">必須</span></th>
    <td colspan="2">[mwform_email name="email" size="40"]</td>
    </tr>
    <tr>
    <th>その他</th>
    <td colspan="2">[mwform_textarea name="etc" cols="40" rows="5" ]</td>
    </tr>
    </tbody>
    </table>
    <p style="text-align: center;">[mwform_bconfirm class="確認" value="confirm"]確認画面へ[/mwform_bconfirm]
    [mwform_bback value="back"]戻る[/mwform_bback][mwform_bsubmit name="送信" value="send"]送信する[/mwform_bsubmit]</p>

    Contact Form 7版

    固定ページなどに張り込むショートコードにhtml_classを追加する。

    [contact-form-7 id="nnn" title="xxx" html_class="h-adr"]
    <script src="https://yubinbango.github.io/yubinbango/yubinbango.js" charset="UTF-8"></script>
    <span class="p-country-name" style="display:none;">Japan</span>
    
    xxxに参加申し込みします
    <table class="table-res-form">
    <tbody>
    <tr>
    <th>氏名<span class="requied">必須</span></th>
    <td>[text* lastname size:12 placeholder"姓"]</td>
    <td>[text* firstname size:12 placeholder"名"]</td>
    </tr>
    <tr>
    <th>ふりがな<span class="requied">必須</span></th>
    <td>[text* lastkana size:12 placeholder"せい"]</td>
    <td>[text* firstkana size:12 placeholder"めい"]</td>
    </tr>
    <tr>
    <th>生年月日<span class="requied">必須</span></th>
    <td colspan=2>[select* birth-year default:61 "1920" "1921" "1922" "1923" "1924" "1925" "1926" "1927" "1928" "1929" "1930" "1931" "1932" "1933" "1934" "1935" "1936" "1937" "1938" "1939" "1940" "1941" "1942" "1943" "1944" "1945" "1946" "1947" "1948" "1949" "1950" "1951" "1952" "1953" "1954" "1955" "1956" "1957" "1958" "1959" "1960" "1961" "1962" "1963" "1964" "1965" "1966" "1967" "1968" "1969" "1970" "1971" "1972" "1973" "1974" "1975" "1976" "1977" "1978" "1979" "1980" "1981" "1982" "1983" "1984" "1985" "1986" "1987" "1988" "1989" "1990" "1991" "1992" "1993" "1994" "1995" "1996" "1997" "1998" "1999" "2000" "2001" "2002" "2003" "2004" "2005" "2006" "2007" "2008" "2009" "2010" "2011" "2012" "2013" "2014" "2015" "2016" "2017" "2018" "2019" "2020" "2021" "2022" "2023" "2024" "2025" "2026" "2027" "2028" "2029" "2030" "2031" "2032" "2033" "2034" "2035" "2036" "2037" "2038"] [select* birth-month include_blank "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12"]月 [select* birth-day include_blank "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "30" "31"]日</td>
    </tr>
    <tr>
    <th>性別<span class="requied">必須</span></th>
    <td colspan=2>[radio gender default:0 "男" "女"]</td>
    </tr>
    <tr>
    <th>郵便番号<span class="requied">必須</span></th>
    <td colspan=2>[text* zipcode class:p-postal-code size:10 minlength:7 maxlength:7 placeholder"0000000"]</td>
    </tr>
    <tr>
    <th>都道府県<span class="requied">必須</span></th>
    <td colspan=2>[select* pref class:p-region default:20 "北海道" "青森県" "岩手県" "宮城県" "秋田県" "山形県" "福島県" "茨城県" "栃木県" "群馬県" "埼玉県" "千葉県" "東京都" "神奈川県" "新潟県" "富山県" "石川県" "福井県" "山梨県" "長野県" "岐阜県" "静岡県" "愛知県" "三重県" "滋賀県" "京都府" "大阪府" "兵庫県" "奈良県" "和歌山県" "鳥取県" "島根県" "岡山県" "広島県" "山口県" "徳島県" "香川県" "愛媛県" "高知県" "福岡県" "佐賀県" "長崎県" "熊本県" "大分県" "宮崎県" "鹿児島県" "沖縄県"]</td>
    </tr>
    <tr>
    <th>市町村区<span class="requied">必須</span></th>
    <td colspan=2>[text* city class:p-locality size:10 placeholder"市町村"]</td>
    </tr>
    <tr>
    <th>番地等<span class="requied">必須</span></th>
    <td colspan=2>[text* addr1 class:p-street-address class:p-extended-address placeholder"番地等"]</td>
    </tr>
    <tr>
    <th>建物名等</th>
    <td colspan=2>[text addr2 placeholder"建物名等"]</td>
    </tr>
    <tr>
    <th>電話番号<span class="requied">必須</span></th>
    <td colspan=2>[tel* phone]</td>
    </tr>
    <tr>
    <th>メールアドレス<span class="requied">必須</span></th>
    <td colspan=2>[email* email ]</td>
    </tr>
    <tr>
    <th>その他</th>
    <td colspan=2>[textarea etc ]</td>
    </tr>
    <tr>
    <td colspan=3><div align="center">[submit "送信"]</div></td>
    </tr>
    </tbody>
    </table>

    外観-カスタマイズで追加CSSに追加して、表示を整形する。

    以下の頁を一部参考にさせてもらっています。

    https://tonari-it.com/contactform7-form-design/

    /* ContactForm7のテーブル化レスポンシブ調整 */
    .entry-content > *:not(.alignwide):not(.alignfull):not(.alignleft):not(.alignright):not(.is-style-wide) {
    	max-width: 70rem;
    	width: calc(100% - 4rem);
    }
    /*テーブルを親要素の幅いっぱいに伸ばす*/
    .table-res-form {
        width: 100%;
    }
    /*一行ごとに上ボーダー*/
    .table-res-form tr {
        border-top: 1px #DDD solid;
    }
    /*一番上の行だけボーダーなし*/
    .table-res-form tr:first-child {
        border-top: none;
    }
    /*奇数行だけ背景色つける*/
    .table-res-form tr:nth-child(2n+1) {
        background: #eee;
    }
    /*thとtd内の余白指定*/
    .table-res-form th, .table-res-form td {
        padding: 1.0em;
    }
    /*th(項目欄)は30%幅、テキストを右寄せ*/
    .table-res-form th {
        width: 30%;
        text-align: right;
    }
    /*「必須」「任意」部分のスタイリング*/
    .table-res-form .requied, .optional{
        font-size: 50%;
        color: #FFF;
        height: 0;
        line-height: 1;
        vertical-align: baseline;
         position: relative;
        bottom: 1ex;
    }
    .table-res-form .requied {
        background: red;
    }
    .table-res-form .optional {
        background: blue;
    }
    
    /*ここから768px以下の指定*/
    
    @media only screen and (max-width: 768px) {
    /*thとtdをブロック化して幅100%にして、縦積み*/
        .table-res-form th, .table-res-form td {
            width: 100%;
            display: block;
        }
    /*th(項目名)欄の不要な余白削除・テキスト左寄せ*/
        .table-res-form th {
            padding-bottom: 0;
            text-align: left;
        }
    /*不要な最終行の左のthを非表示にする*/
        .table-res-form .empty {
            display: none;
        }
    }
    
    /*ここまで768px以下の指定---終わり*/
    
    /*ここから入力欄のスタイル指定*/
    
    /*各入力フォームスタイリング*/
    .table-res-form input[type="text"], input[type="email"], input[type="tel"], textarea {
        border: 1px #89BDDE solid;
        padding: 0.5em;
        border-radius: 5px;
        margin-bottom: 0.5em;
        width: auto;
    }
    /*入力欄にフォーカスしたら変化*/
    .table-res-form input[type="text"]:focus, textarea:focus {
        background: #EEFFFF;
        box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.5);
    }
    /*送信ボタンスタイリング*/
    .table-res-form input[type="submit"] {
        border: 1px #89BDDE solid;
        padding: 0.5em 4em;
        border-radius: 5px;
        background: #4C9ED9;
        color: #fff;
        box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.5);
        font-weight: bold;
    }
    /*送信ボタン・マウスオーバー時スタイリング*/
    .table-res-form input[type="submit"]:hover {
        background: #006599;
        box-shadow: none;
    }
    
    /* MW WP Formのラジオボタンを横並びにする */
    .mwform-radio-field {
    	display: inline-flex;
    }