カテゴリー: サーバ管理

  • Debian 9 Stretch で unattended-upgrades による自動更新

    Debian 9 Stretch で unattended-upgrades による自動更新

    apt update & upgrade は日常的に実行するものですが、忙しかったりすると疎かになりがちです。そこで unattended-upgrades を有効にしておくことで、j自動で更新を行えます。

    インストール

    $ sudo apt install unattended-upgrades
    Reading package lists… Done
    Building dependency tree
    Reading state information… Done
    Suggested packages:
    bsd-mailx needrestart
    The following NEW packages will be installed:
    unattended-upgrades
    0 upgraded, 1 newly installed, 0 to remove and 1 not upgraded.
    Need to get 61.7 kB of archives.
    After this operation, 252 kB of additional disk space will be used.
    Get:1 http://http.us.debian.org/debian stretch/main amd64 unattended-upgrades all 0.93.1+nmu1 [61.7 kB]
    Fetched 61.7 kB in 0s (82.8 kB/s)
    Preconfiguring packages …
    Selecting previously unselected package unattended-upgrades.
    (Reading database … 38885 files and directories currently installed.)
    Preparing to unpack …/unattended-upgrades_0.93.1+nmu1_all.deb …
    Unpacking unattended-upgrades (0.93.1+nmu1) …
    Processing triggers for systemd (232-25+deb9u6) …
    Setting up unattended-upgrades (0.93.1+nmu1) …
    Processing triggers for man-db (2.7.6.1-2) …

    インストール後に dpkg-reconfigure で有効化します。

    有効化

    $ sudo dpkg-reconfigure unattended-upgrades
    dpkg-reconfigure unattended-upgrades 1/2
    dpkg-reconfigure unattended-upgrades 2/2

    自動更新の対象とするパッケージの指定です。

    autoremove の設定

    /etc/apt/apt.conf.d/50unattended-upgrades を編集し、不要になったパッケージの削除を有効にします。

    // ...略...

    Unattended-Upgrade::Remove-Unused-Dependencies "true";

    // ...略...

    /etc/apt/apt.conf.d/20auto-upgrades に以下を追記し、autoremove の実行間隔を設定します。

    APT::Periodic::AutocleanInterval "1";

    ここの単位は「日」ですので、”1″ であれば 1 日毎に実行、”0″ なら無効になります。

    // Do “apt-get autoclean” every n-days (0=disable)
    APT::Periodic::AutocleanInterval “21”;

    UnattendedUpgrades – Debian Wiki

    メール通知

    mailx コマンドでメールが送れることを確認しておきましょう。

    $ sudo apt install mailutils

    /etc/apt/apt.conf.d/50unattended-upgrades を編集し、 次の一行を編集して有効にします。

    Unattended-Upgrade::Mail "[email protected]";

    エラーの時のみメール通知する場合は、次の一行も編集します。

    Unattended-Upgrade::MailOnlyOnError "true";

    動作確認

    root で unattended-upgrades を実行すれば実際の動作を確認できます。-d(–debug) オプションを付けると処理内容を表示してくれます。

    $ sudo unattended-upgrade -d
    Initial blacklisted packages:
    Initial whitelisted packages:
    Starting unattended upgrades script
    Allowed origins are: ['origin=Debian,codename=stretch']
    pkgs that look like they should be upgraded:
    Fetched 0 B in 0s (0 B/s)
    fetch.run() result: 0
    blacklist: []
    whitelist: []
    No packages found that can be upgraded unattended and no pending auto-removals

    参考

  • OpenVPN でクライアント接続時にスクリプト実行

    OpenVPN でクライアント接続時にスクリプト実行

    /etc/openvpn/server.conf 内に以下の行を追加します。

    script-security 2
    client-connect /path/to/script-con.sh

    script-security 2 は外部スクリプトを実行するために必要です。デフォルトは 1 です。

    0 — Strictly no calling of external programs. 
    1 — (Default) Only call built-in executables such as ifconfig, ip, route, or netsh. 
    2 — Allow calling of built-in executables and user-defined scripts. 
    3 — Allow passwords to be passed to scripts via environmental variables (potentially unsafe).

    OpenVPN man page

    client-connect にはクライアントの接続時に実行するスクリプトを指定します。実行権限を与えるのを忘れないように。 client-disconnect で切断時に実行するスクリプトを指定できます。

    スクリプト内には定義された環境変数を使えます。全ての環境変数は man page の “Environmental Variables” 節に記載されています。

    今回はシェルスクリプト内から更に Python スクリプトを呼び出してメールを送るという二段ロケットな形を採りましたが、問題なく実行されました。簡単な例を記載しておきます。

    #!/bin/sh
    /usr/bin/env python3 /path/to/python-script.py $common_name $trusted_ip
    #!/usr/bin/env python3
    # coding: utf-8
    
    import sys
    
    args = sys.argv
    
    # Send messages to server admins
    ...

    参考

  • Vultr Cloud Compute(VC2) で swap を設定する

    Vultr Cloud Compute(VC2) で swap を設定する

    Vultr の VPS こと Vultr Cloud Compute(VC2) の標準提供イメージでは、swap の設定がされていません。CPU やディスクの性能的には最安の $3.5/month のプランでも十分事足りますが、メモリが 512MB しかないために簡易なサーバ用途でもギリギリになりがちです。

    top

    これは実際に運用しているサーバで top した様子です。メモリの free が 10MB 程度しかありません。250MB はキャッシュなので実際には不足しているわけではありませんが、余裕はない状態です。Vultr 公式に swap の設定ガイドがあるので、これを参考に swap の設定を行います。

    まずは既に swap が設定されていないかを確認します。”free -m” して swap が 0 であることを確認します。

    $ free -m
    total used free shared buff/cache available
    Mem: 492 228 8 26 255 224
    Swap: 0 0 0

    次に swap 先のファイルを準備します。今回はガイド通りの 2GB の領域を確保しました。

    $ sudo dd if=/dev/zero of=/swapfile count=2048 bs=1M
    2048+0 records in
    2048+0 records out
    2147483648 bytes (2.1 GB, 2.0 GiB) copied, 6.51387 s, 330 MB/s

    作成した /swapfile の権限を、root のみが読み書きできるように変更します。

    $ sudo chmod 600 /swapfile

    mkswap を実行して /swapfile のセットアップを行います。

    $ sudo mkswap /swapfile
    Setting up swapspace version 1, size = 2 GiB (2147479552 bytes)
    no label, UUID=0e842c1b-20d4-4da0-853d-78b708da7003

    swapon で swap を有効化します。

    $ sudo swapon /swapfile

    特に何も表示されなければ成功です。”free -m” してメモリ使用量を見てみましょう。

    $ free -m
    total used free shared buff/cache available
    Mem: 492 229 7 26 255 223
    Swap: 2047 0 2047

    すぐには使われないようですが、ちゃんと Swap の total が 0 ではなくなっていますね。

    永続化

    このままだと再起動するたびに swapon しないといけないので、/etc/fstab に書いて起動時に自動で swap を設定するようにします。次の 1 行を追記してください。

    /swapfile none swap sw 0 0

    参考

  • PostgreSQL 9.6 で “Peer authentication failed”

    PostgreSQL 9.6 で “Peer authentication failed”

    既に出尽くした感はありますが、昔からの PC ユーザほどハマりやすいのではないかと思うので記録します。

    データベースへ接続する際の認証手段は「ユーザ」と「パスワード」であると思い込みがちですが、最近の RDBMS では OS 側のユーザで認証するのがデフォルトになっています。

    例えば Linux で foo というユーザでログインしていたとします。ユーザを指定せずに mysql や psql を起動すると、同じ foo というユーザでデータベースに接続します。これはこれで簡潔でわかりやすい仕組みなのですが、落とし穴があって Linux 側と RDBMS が同じユーザでないといけない制限が掛かっていたりします。

    どういうことかというと、例えば PostgreSQL 9.6 を使っている環境で、ユーザ foo さんが psql をユーザ postgres で使いたいとき、次のようにユーザを指定して接続しても認証で弾かれます。パスワードが正しくても弾かれるので、ハマりやすいポイントです。

    foo@host:~$ psql -U postgres
    psql: FATAL: Peer authentication failed for user "postgres"

    postgres で psql に入るには sudo su – postgres などとして、Linux 側でもユーザ postgres である必要があります。

    foo@host:~$ sudo su - postgres
    postgres@host:~$ psql
    psql (11.1 (Debian 11.1-1.pgdg90+1), server 9.6.10)
    Type "help" for help.

    postgres=#

    この認証の設定は /etc/postgresql/9.6/main/pg_hba.conf にあります。hba は Host Based Authentication の略のようです。

    pg_hba.conf

    pg_hba.conf を開くと、説明のコメントがほとんどを占めていますが、必要なのは次の部分です。

    ...(略)...
    
    # Database administrative login by Unix domain socket
    local   all             postgres                                peer
    
    ...(略)...
    
    local   all             all                                     peer
    
    ...(略)...
    
    host    all             all             127.0.0.1/32            md5
    
    ...(略)...

    ここで “peer” となっているのが peer authentication です。これをパスワード認証にするには password または md5 とします。password は平文通信されるので、ハッシュ化される md5 を選びましょう。

    各設定はそれぞれ次のような意味です。

    local   all             postgres                                peer

    ローカルシステム上のユーザが、ユーザ名 postgres を使った peer 認証で全てのデータベース(all)に接続できます。peer 認証なので、実質的にローカルシステムの postgres というユーザが、全てのデータベースに接続できるのと同じです。

    local   all             all                                     peer

    ローカルシステム上のユーザは誰でも(2 つ目の all) peer 認証で全てのデータベース(1 つ目の all) に接続できます。

    host    all             all             127.0.0.1/32            md5

    127.0.0.1(localhost) からの接続はパスワード認証(md5)されて、全てのユーザ(2 つ目の all) が全てのデータベース(1 つ目の all) に接続できます。

    “peer” を “md5″ に書換えて、ロールにパスワードを設定すれば完了です。”sudo system reload postgresql” などとして、設定を反映させるのを忘れないように。

    ユーザ(ロール)のパスワード設定

    postgres 等の権限があるユーザで psql に入り、ALTER ROLE または ALTER USER を使います。

    postgres=# ALTER ROLE role_name ENCRYPTED PASSWORD 'your_password';

    そのパスワード認証、必要ですか?

    ここまで書いておいて今更ですが、peer 認証の仕組み自体は、分離している PostgreSQL と OS の認証をできるだけ簡素にする、とても良い仕組みです。MariaDB でも同じ手法を用いているため、これからは(あるいはもう既に)この手法が主流になっていくのでしょう。

    これが問題になるのは外部、あるいはプログラムからのアクセスでしょう。それについては、デフォルトで 127.0.0.1(localhost) からのアクセスはパスワード認証(md5)に設定されているため、ロールにパスワードを設定するだけで事足ります。

    今回は Python から psycopg2 で接続するのが最終目的だったため、ロールにパスワードを設定するだけで要件は満たしました。慣れた手法を使いたくなりますが、それによって時代の潮流から外れるのは、後々になって自分の首を絞めることになることはわかっているので、できる限り避けたいと思っています。

    参考

  • Debian 9 Stretch で Docker のインストール

    Debian 9 Stretch で Docker のインストール

    Debian 9 Stretch に Docker をインストールして動作確認を行うまで。

    $ sudo apt update
    $ sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
    $ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

    /etc/apt/sources.list に次の一行を追加する。

    deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable

    もう一度 apt update して更新を行ったあとにインストールを行います。

    $ sudo apt update
    $ sudo apt install docker-ce

    動作確認に hello-world の image を run してみます。

    $ sudo docker run hello-world
    Unable to find image 'hello-world:latest' locally
    latest: Pulling from library/hello-world
    d1725b59e92d: Pull complete
    Digest: sha256:0add3ace90ecb4adbf7777e9aacf18357296e799f81cabc9fde470971e499788
    Status: Downloaded newer image for hello-world:latest
    Hello from Docker!
    This message shows that your installation appears to be working correctly.
    To generate this message, Docker took the following steps:
    The Docker client contacted the Docker daemon.
    The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
    The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
    The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.
    To try something more ambitious, you can run an Ubuntu container with:
    $ docker run -it ubuntu bash
    Share images, automate workflows, and more with a free Docker ID:
    https://hub.docker.com/
    For more examples and ideas, visit:
    https://docs.docker.com/get-started/

    ローカルのイメージを表示

    $ sudo docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    hello-world latest 4ab4c602aa5e 2 months ago 1.84kB

    動作中のコンテナを表示

    $ sudo docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

    全てのコンテナを表示

    $ sudo docker ps -a
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    4d4807dccc3c hello-world "/hello" 8 minutes ago Exited (0) 8 minutes ago friendly_chandrasekhar

    コンテナの削除

    CONTAINER ID を指定します。

    $ sudo docker rm 4d4807dccc3c
    4d4807dccc3c

    ローカルのイメージを削除

    イメージの名前か IMAGE ID を指定します。

    $ sudo docker rmi hello-world
    $ sudo docker rmi 4ab4c602aa5e

    参考

  • cannot update mailbox /home/user/Maildir for user user. cannot open file: Is a directory

    Postfix でメールサーバを建てましたが、メールの受信をテストをするために Gmail から自ドメイン宛にメールを送ってみたところ、次のようなエラーメールが返ってきました。

    調べたら原因はすぐに判明して、Postfix の設定の問題でした。Maildir 形式なのに mbox 形式として扱おうとしていたのが問題でした。

    /etc/postfix/main.cf

    ...
    home_mailbox = Maildir/
    ...

    home_mailbox = Maildir とするとmbox として、Maildir/ とすると Maildir と扱われるようです。ファイルかディレクトリかで判別しているということですね。

    参考

  • プラグインに頼らない WordPress の移転

    プラグインに頼らない WordPress の移転

    経緯

    性能や管理の手間を考えてサーバの移転を行いました。その際に見事にハマった WordPress の移転について書きます。

    元々使っていたのは自宅サーバ上の WordPress 4.1 でした。バージョンが古いのは、楽にできるかと apt でインストールしてしまったこと、設置時にパーミッションや実行ユーザをぐちゃぐちゃにしていまい、更新できない状態であったことが理由です。

    セキュリティ上よろしくないのはもちろんのこと、そもそもプラグインやテーマを追加するのにサーバへファイルを直接転送しなければならないという、大変手間なことこの上ない状態になっていました。

    Vultr が日本で $3.5/月のインスタンスを用意してくれていたので、これを機に自宅サーバを廃止して VPS に全面移行することに決めました。

    自宅サーバでは自前のプログラム他、VPN や WordPress など様々なものを動かしていましたが、ハードの更新を何度か経験していたために自前のプログラムは特に問題にならないと思われ、VPN は不要になり、WordPress さえうまく移植できれば、ことはすぐに済むはずでした。

    WordPress にはインポートとエクスポート機能が標準で備わっているため、前回はこの機能を使ってすんなりと移植できたのをおぼえています。今回も、と思いきや、記事の文字部分はインポートされますが、何度やっても画像等のメディアファイルの取得に失敗してしまいます。

    次に WordPress では有名らしいプラグイン All-in-One WP Migration を使ってみましたが、約 700 MB 近い巨大なファイルを作り上げた上に記事の日本語が全て ? に化けてしまいました。

    その後も wp-content/uploads 内のファイルを自動登録してくれるプラグイン等、様々なものを試してみましたが、どれもどこかで不整合が起きて元通りには戻りません。そもそも標準のインポートがなぜだめなのか、原因は調べてもわからずじまいでした。

    そこで原点に戻って MySQL の DB を dump し、手作業で移植することにしたところ、ようやっとうまくいきました。その手順を以下に記します。

    環境

    移転元

    • MySQL 5.5.60
    • PHP 5.6.37
    • WordPress 4.1

    移転先

    • MariaDB 10.1.26
    • PHP 7.0.30
    • WordPress 4.9.8

    移転元での作業

    wp-content/uploads を固める

    $ tar cvzf /home/user/uploads.tar.gz /var/lib/wordpress/wp-content/uploads

    wp-content の場所は自分で探す必要があります。今回はなぜか Alias で通常とは違うところにあって、見つけるのに苦労しました。わからなかったら URL と Apache の conf をがんばって追って探すか、find 等で見つけましょう。

    $ find / -name wp-content -type d

    作成したアーカイブは scp 等で新しいサーバに転送しておきます。

    データベースの dump を作成する

    $ mysqldump --default-character-set=binary wordpress > wp.sql 

    WordPress のテーブルが独立したデータベース wordpress にある場合は上記で全てのテーブルが dump されます。別のテーブルが混ざっている場合は WordPress のテーブルだけを指定して dump してください。ユーザとパスワードは -u USERNAME -pPASSWORD を加えてください。

    作成した dump も新しいサーバに転送しておきます。

    “–default-character-set=binary” なしで dump すると、UTF-8 でも Shift-JIS でも EUC-JP でも日本語が読めないファイルが出来上がってしまいました。必ず指定しましょう。

    移転先での作業

    一度 WordPress 設置してインストールまで済ませ、WordPress が正常に動作することを確認しましょう。移転作業とインストールを同時に進めると、何かあったときに原因の切り分けが難しくなります。WordPress のバージョンは揃えた方が無難だと思いますが、今回は最新版の 4.9.8 を使ってそのままいけました。

    インストール時にデータベースやテーブルの接頭辞を指定しますが、必ず移転元と同じにしておきましょう。変更するなら WordPress の設定も変更しなければなりません。

    インストールが完了したら一点だけ確認しておきます。ログインしてダッシュボードを開き、「設定」 – 「メディア」の「ファイルアップロード」 – 「アップロードしたファイルを年月ベースのフォルダに整理」のチェックを移転元と同じ状態にしておきましょう。

    プラグインやテーマも揃えておく、あるいはコピーしてしまう方が安全だと思いますが、テーマに関してはサイトが表示されないだけで wp-login.php を開けばダッシュボードは開けるはずなので、今回は無視して進めました。

    dump から MariaDB へ

    WordPress のインストールまで済ませておくとテーブルのデータが競合してしまうので、全てのテーブルを空にしておきます。次の内容を clear_tables.sql などに保存しておきます。

    delete from wp_commentmeta;
    delete from wp_comments;
    delete from wp_links;
    delete from wp_options;
    delete from wp_postmeta;
    delete from wp_posts;
    delete from wp_term_relationships;
    delete from wp_term_taxonomy;
    delete from wp_terms;
    delete from wp_usermeta;
    delete from wp_users;
    $ mysql wordpress < clear_tables.sql
    $ mysql wordpress < wp.sql

    wp.sql は移転元で dump したデータベースの中身です。もし移転元と移転先のドメインが異なるなら、予めこのファイルをテキストエディタ等で開いてドメインを全て置換えしておきましょう。

    uploads の展開

    $ tar xvzf uploads.tar.gz
    $ cp -r uploads/* wp-content/uploads

    展開したファイルはパーミッションを適切に変更しておいてください。

    仕上げ

    uploads の移植とデータベースの復元が完了したら WordPress を開いてみましょう。データベース更新の案内が表示されるはずなので、あとは手順通り進めて完了です。お疲れさまでした。

    参考