2017年10月23日月曜日

Chinachuの録画ファイルを自動削除

Chinachu自体にも自動的にファイルを削除する機能はありますが、
あくまでも容量が足りなくなったときのみの機能なので、
1週間以前の録画ファイルを削除するスクリプトを作成してみました。

#!/bin/bash

day_count=7
tsdir="/mnt/storage/share/tv/"
logdir="/opt/chinachu/log/tsdel/"

nowstr=`date +%y%m%d%H%M%S`
logfile=${logdir}${nowstr}.log
datestr=`date --date "${day_count} days ago" +%y%m%d`

echo "------- TS File Delete Start -------" >> ${logfile}
count=0
for filepath in ${tsdir}*; do
  filename=`basename ${filepath}`
  filename=${filename:1:6}
  if [ ${filename} -lt ${datestr} ] ; then
    rm -fv "${filepath}" >> ${logfile} 2>&1
    let count++
  fi
done

echo "------- ${count} Files Deleted. -------" >> ${logfile}

if [ $count -gt 0 ] ; then
  echo "------- Chinachu Cleanup Start -------" >> ${logfile}
  expect -c "
    set timeout 5
    spawn /opt/chinachu/chinachu cleanup
    expect \"\[Y/n\]?\ \"
    send \"Y\n\"
    expect \"$\"
    exit 0
  " >> ${logfile} 2>&1
  echo "------- Chinachu Cleanup End. -------" >> ${logfile}
fi

echo "------- TS File Delete End. -------" >> ${logfile}
以上、コイツをcronにぶち込んで運用しています。

2017年5月5日金曜日

Mastodonのアップデート

マストドンは頻繁に更新されています。
せっかく自分専用インスタンスを立てたのだから、最新版を
追いかけたくなるのが人情ってもんですw
ということで、アップデートの手順です。
su - mastodon

cd live

git fetch

git checkout $(git tag | sed -e "/rc/d" | tail -n 1)

bundle install

yarn install

RAILS_ENV=production bundle exec rails db:migrate

RAILS_ENV=production bundle exec rails assets:precompile

sudo pm2 restart mastodon-*.service
あとは正常に動作しているか確認すれば終了です!

Mastodonに管理アカウントを設定する。

マストドンのインスタンスを立ち上げてみてはものの、
このままの状態では誰も管理アカウントが居ない状態になっています。
なので自分のアカウントを追加した状態で、
su - mastodon

cd live

RAILS_ENV=production bundle exec rails mastodon:make_admin USERNAME=#自分#
を実行。
めでたく管理者アカウントに昇格できました!

Mastodonのサーバ通信切れを予防する

無事に自分用マストドンインスタンスを開設できたわけですが、
一つ重要な設定を忘れていることに気がつきました。
つーかちゃんと公式マニュアル見ろって話ですw

で、参考にしたサイトはこちら。
Qiita:Mastodonのサーバ間通信が切れた場合のリカバリ

crontab -eで編集します。
crontab -e
通常であれば、
cd /home/mastodon/live && RAILS_ENV=production bundle exec rake mastodon:daily
をcronに追加すればいいようなのですが、
実はこれ、リソースの少ないサーバでは落ちるという事例があるようで、
今の契約はVPSの最安プラン(512MBプラン)という貧弱なものなので、
安全策でこのような設定にしてみました。
MAILTO=root
10 4,16 * * * /bin/bash -l -c 'cd /home/mastodon/live && RAILS_ENV=production bundle exec rake mastodon:feeds:clear'
15 4,16 * * * /bin/bash -l -c 'cd /home/mastodon/live && RAILS_ENV=production bundle exec rake mastodon:media:clear'
20 4,16 * * * /bin/bash -l -c 'cd /home/mastodon/live && RAILS_ENV=production bundle exec rake mastodon:users:clear'
25 4,16 * * * /bin/bash -l -c 'cd /home/mastodon/live && RAILS_ENV=production bundle exec rake mastodon:push:refresh'
とりあえずコレで一安心ですw

Mastodonインスタンスを立ててみる

今流行のマストドンインスタンスを立ててみました。
Dockerを使えば簡単に導入できるようですが、今回はあえて手動でやってみました。

下記手順の前提条件:
・さくらのVPS(標準OS:Ubuntu16.04)
・ドメイン取得済み[mstdn.imoimo.xyz](今回はお名前.comを利用させて頂きました。)
・諦めない心


参考サイト:
公式マニュアル
Qiita:さくらのVPSで自分の Mastodon サーバを最速でつくる方法
稲葉サーバーデザイン:Let’s EncryptによるSSLサーバー証明書の自動更新設定

443ポート、動作確認用ポートを開放するために、iptablesの設定を編集
sudo vi /etc/iptables/iptables.rules
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT

#さくらのVPS標準OSはデフォルトで22番ポート(ssh)だけが開放されている。
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT

#httpsポートを追加。
-A INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT

#Mastodon動作確認用でこちらも。後で削除する。
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3000 -j ACCEPT

-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

iptablesの設定内容を反映
sudo iptables-restore < /etc/iptables/iptables.rules

mastodonユーザを作成し、mastodonユーザでログイン
sudo adduser -ingroup sudo mastodon

su - mastodon

依存関係のあるパッケージなどをインストール
sudo apt-get install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev nodejs file git curl

curl -sL https://deb.nodesource.com/setup_4.x | sudo bash -

sudo apt-get install nodejs

sudo npm install -g yarn

Redisのインストール
sudo apt-get install redis-server redis-tools

Postgresのインストール
sudo apt-get install postgresql postgresql-contrib

sudo postgresql-setup initdb

sudo systemctl start postgresql

sudo systemctl enable postgresql

Postgresにmastodonユーザを作成
sudo su - postgres

psql

CREATE USER mastodon CREATEDB;

\q

Postgresのおまじない(ローカルユーザからはパスワード要求しない設定っぽい)
sudo sed -i '/^local.*postgres.*peer$/a host    all     all     127.0.0.1/32    ident' /etc/postgresql/9.?/main/pg_hba.conf

identのインストール
sudo apt-get install pidentd

sudo systemctl enable pidentd

sudo systemctl start pidentd

sudo systemctl restart postgresql

Rbenvのインストール
git clone https://github.com/rbenv/rbenv.git ~/.rbenv

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile

echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

~/.rbenv/bin/rbenv init

source ~/.bash_profile

rbenvが無事インストールされているか確認
exit

su - mastodon

type rbenv

rbenv-build のインストール
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

rubyのインストール
rbenv install 2.4.1

rbenv rehash

rbenv global 2.4.1

rubyが正常にインストールされたか確認
ruby -v

Mastodon本体を取得
mastodonユーザのHomeにliveディレクトリを作成し、そこに格納。
cd ~

git clone https://github.com/tootsuite/mastodon.git live

cd live

git checkout $(git tag | tail -n 1)

依存パッケージ(RubyGems)のインストール
gem install bundler

bundle install --deployment --without development test

yarn install

rakeのシークレットキーを生成(3回実行し、3個生成しておく)
rake secret

.env.productionの編集
cp .env.production.sample .env.production

vi .env.production
#RdisとPostgresは同一サーバに構築したので、そのように設定。
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
DB_HOST=127.0.0.1
DB_USER=mastodon
DB_NAME=mastodon
DB_PASS=
DB_PORT=5432

#Mastodonで使うドメイン名を設定
LOCAL_DOMAIN=mstdn.imoimo.xyz
#動作確認のため、falseに設定しておく(あとでtrueに戻す)
LOCAL_HTTPS=false

#それぞれrake secretで作成したシークレットキーを設定する。
PAPERCLIP_SECRET=#シークレットキー#
SECRET_KEY_BASE=#シークレットキー#
OTP_SECRET=#シークレットキー#

#とりあえずGmailアカウントを作ってそれを使うことにした。
SMTP_SERVER=smtp.gmail.com
SMTP_PORT=587
SMTP_LOGIN=mstdn.imoimo@gmail.com
SMTP_PASSWORD=#GMailのログインパスワード#
SMTP_FROM_ADDRESS=mstdn.imoimo@gmail.com
SMTP_OPENSSL_VERIFY_MODE=none
SMTP_DOMAIN=gmail.com

Mastodonのビルド
RAILS_ENV=production bundle exec rails db:setup

RAILS_ENV=production bundle exec rails assets:precompile

systemdの設定(自動起動)
sudo vi /etc/systemd/system/mastodon-web.service
[Unit]
Description=mastodon-web
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=3000"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
sudo vi /etc/systemd/system/mastodon-sidekiq.service
[Unit]
Description=mastodon-sidekiq
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=5"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
sudo vi /etc/systemd/system/mastodon-streaming.service
[Unit]
Description=mastodon-streaming
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="NODE_ENV=production"
Environment="PORT=4000"
ExecStart=/usr/bin/npm run start
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target

Mastodonサービスを起動
sudo systemctl enable /etc/systemd/system/mastodon-*.service

sudo systemctl start mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service

とりあえず動作確認
これでマストドンのAboutページが出れば成功!
http://<サーバのIPアドレス>:3000

Let's Encrypt(certbot)のインストール
cd /usr/local

sudo git clone https://github.com/certbot/certbot

certbotが正常にインストールされたことを確認
certbotのヘルプが表示されればOK。
cd /user/local/certbot

sudo ./certbot-auto --help

証明書を取得する
certbot-auto certonly --standalone -d mstdn.imoimo.xyz -m mstdn.imoimo@gmail.com --agree-tos -n

証明書を自動更新するためのスクリプトを作成する
sudo vi /usr/local/certbot/certbot.sh
#!/bin/sh
#
LOGFILE=/var/log/update_sslcert.log
COMMAND=/usr/local/certbot/certbot-auto
WEBSERVER_STOP_COMMAND="systemctl stop nginx"
WEBSERVER_START_COMMAND="systemctl start nginx"

MAILTO=root

echo "===== Update SSL Cert =====" >> ${LOGFILE}
echo "`date` Update SSL Cert start" >> ${LOGFILE}

${COMMAND} renew \
  --pre-hook "$WEBSERVER_STOP_COMMAND" \
  --post-hook "$WEBSERVER_START_COMMAND" \
  --non-interactive >> ${LOGFILE}
STATUS=$?

if [ "$STATUS" != 0 ]; then
    echo "Update SSL Cert failed" >> ${LOGFILE}
    echo "Update SSL Cert failed" |\
    mail -s "Update SSL Cert in `hostname`" ${MAILTO}
fi

echo "`date` Update SSL Cert end" >> ${LOGFILE}

# EOF

先ほど作成したスクリプトをcronに追加する
sudo crontab -e
50 4 * * 4 /usr/local/certbot/certbot.sh > /dev/null

Nginx(httpsプロキシとして使用)のインストール
sudo apt-get install nginx

Nginxの設定
公式ドキュメントのサンプルをそのまま流用。
sudo vi /etc/nginx/conf.d/mastodon_proxy.conf
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

server {
  listen 80;
  listen [::]:80;
  server_name mstdn.imoimo.xyz;
  # Useful for Let's Encrypt
  location /.well-known/acme-challenge/ { allow all; }
  location / { return 301 https://$host$request_uri; }
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name mstdn.imoimo.xyz;

  ssl_protocols TLSv1.2;
  ssl_ciphers EECDH+AESGCM:EECDH+AES;
  ssl_ecdh_curve prime256v1;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;

  ssl_certificate     /etc/letsencrypt/live/mstdn.imoimo.xyz/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/mstdn.imoimo.xyz/privkey.pem;
  ssl_dhparam         /etc/ssl/certs/dhparam.pem;

  keepalive_timeout    70;
  sendfile             on;
  client_max_body_size 0;

  root /home/mastodon/live/public;

  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

  add_header Strict-Transport-Security "max-age=31536000";

  location / {
    try_files $uri @proxy;
  }

  location /assets {
    add_header Cache-Control "public, max-age=31536000, immutable";
  }

  location @proxy {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";
    proxy_pass_header Server;

    proxy_pass http://127.0.0.1:3000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  location /api/v1/streaming {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";

    proxy_pass http://localhost:4000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  error_page 500 501 502 503 504 /500.html;
}

.env.productionのLOCAL_HTTPSをtrueに変更する
vi ~/live/.env.production

iptablesで開けていた3000番ポートを閉じて、設定を反映
sudo vi /etc/iptables/iptables.rules

sudo iptables-restore < /etc/iptables/iptables.rules

MastodonとNginxの再起動
sudo systemctl restart mastodon-sidekiq.service

sudo systemctl restart mastodon-web

sudo systemctl restart nginx

最終動作確認
https://mstdn.imoimo.xyz
コレで無事マストドンが表示されれば成功!
ハマり所はLet's Encryptとポート開放の辺りでしょうか・・・
ぶっちゃけ結構大変でした・・・w

2017年2月20日月曜日

Twitterの自動返信BOTをPHPで実装

// TwitterOAuthライブラリを使用
require 'twitteroauth/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;

// ログファイル
define("LOG_FILE","koimoimo.log");
// 最新ツイートIDを保存するファイル
define("LATEST_FILE","latest.txt");

//TwitterのOAuth用パラメータ
define("C_KEY","--Consumer Key--");
define("C_SEC","--Consumer Secret--");
define("A_TOK","--Access Token--");
define("A_SEC","--Access Token Secret--");

// 自分自身のTwitter ID(@なしで指定)
define("MYNAME","--My Twitter ID--");
// 非公式RT用返信ヘッダ
define("MENTION_HEAD","ホアーッ RT @");
// マッチング文字列を配列に格納
$key_arr = [
"ブチッ",
"ブチッ",
"ぶちっ",
"シャコン",
"ブチっ",
"ぶちぶち",
"ブチブチ",
"ブチブチ"
];

// OAuthでTwitterに接続
$connection = new TwitterOAuth(C_KEY,C_SEC,A_TOK,A_SEC);
// 前回の最新ツイートIDを取得
$latest = load_file(dirname(__FILE__)."/".LATEST_FILE);
// ホームタイムラインからツイートを取得
$tl = $connection->get("statuses/home_timeline", ["count" => 200]);
// 今回の最新ツイートIDを保存しておく
save_file(dirname(__FILE__)."/".LATEST_FILE,$tl[0]->id_str);
// ツイートをスキャンし、マッチング文字列にヒットしたら非公式RTする
foreach($tl as $t){
    // 送信者が自分自身以外のツイートと、前回の最新より新しいツイートに絞る
    if($t->user->screen_name != MYNAME && $t->id_str > $latest){
        // ツイートをマッチング文字列配列でスキャンし、ヒット数を返す。
        $sc = get_key_score($t->text,$key_arr);
        // ヒット数が1以上で、かつツイート中に自身のIDが含まれるものに絞る
        if($sc > 0 && mb_strstr($t->text,"@".MYNAME) != NULL){
            // 多重メンション防止
            if(mb_strstr($t->text,MENTION_HEAD) == NULL){
                // 返信を投稿する
                send_mention($connection,$t->user->screen_name,$t->text);
            }
        }
    }
}

// ファイルを開き、内容を文字列変数に格納する
function load_file($filename)
{
    $fp = fopen($filename,"r");
    $buf = fgets($fp);
    fclose($fp);
    return $buf;
}

// 文字列変数の内容をファイルに書き込む
function save_file($filename,$buf)
{
    $fp = fopen($filename,"w");
    fwrite($fp,$buf);
    fclose($fp);
}

// 文字列変数の内容をファイルに追記する
function append_log_file($filename,$buf)
{
    $fp = fopen($filename,"a");
    fwrite($fp,$buf."\n");
    fclose($fp);
}

// 文字列からマッチング文字列配列のヒット数を返す
function get_key_score($txt,$key)
{
    $s = 0;
    foreach($key as $k){
        if(mb_strstr($txt,$k) != NULL) $s++;
    }
    return $s;
}

// 非公式RT形式でツイートし、内容をログに残す
function send_mention($con,$usr,$txt)
{
    $m = MENTION_HEAD.$usr.": ".$txt;
    if(mb_strlen($m) > 140) $m = mb_strimwidth($m,0,140,"...");
    $r = $con->post("statuses/update", ["status" => $m]);
    append_log_file(dirname(__FILE__)."/".LOG_FILE,date("Ymd_His").":".$m);
    return $r;
}

2017年2月7日火曜日

内向きDNSサーバ構築

何年も前からやろうやろう思っていて、
でもめんどくさそうで二の足を踏んでいた内向きDNSなのですが。
ここにきてえいやっとやってしまいました。

DNSサーバのIPアドレス:192.168.1.250
ドメイン名:mydomain.com
として、設定を進めます。
なお動的グローバルIP環境なので、内向きのみの名前解決とし、
外への名前解決はルータに丸投げするようにします。

手順は以下の通り。

BIND9とdnstoolsのインストール
debian-sv# apt-get -y install bind9 dnstools

named.confを編集する。
debian-sv# vi /etc/bind/named.conf
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
#include "/etc/bind/named.conf.default-zones"; # コメントアウト
include "/etc/bind/named.conf.internal-zones"; # 追加:内向き用定義ファイル

named.conf.optionを編集する。
debian-sv# vi /etc/bind/named.conf.options
options {
    directory "/var/cache/bind";
    # 問い合わせを許可する範囲
    allow-query { localhost; 192.168.1/24; };
    # ゾーン転送を許可する範囲
    allow-transfer { localhost; 192.168.1/24; };
    # 内向き以外の問い合わせは他のDNSに丸投げする
    forwarders { 192.168.1.1; };
    dnssec-validation auto;
    # conform to RFC1035
    auth-nxdomain no;
    # ipv6は使用しないのでnoneにする
    listen-on-v6 { none; };
};

内向き用ゾーン定義(named.conf.internal-zones)
debian-sv# vi /etc/bind/named.conf.internal-zones
view "internal" {
    match-clients {
        localhost;
        192.168.1/24;
    };
    zone "mydomain.com" {
        type master;
        file "/etc/bind/mydomain.com.lan";
        allow-update { none; };
    };
    zone "1.168.192.in-addr.arpa" {
        type master;
        file "/etc/bind/1.168.192.db";
        allow-update { none; };
    };
    include "/etc/bind/named.conf.default-zones";
};

内向きの正引き用設定ファイル
debian-sv# vi /etc/bind/mydomain.com.lan
$TTL 86400
@ IN SOA    ns.mydomain.com. root.mydomain.com. (
    2017020101  ;Serial
    28800       ;Refresh
    14400       ;Retry
    3600000     ;Expire
    86400       ;Minimum TTL
)
    IN  NS      ns.mydomain.com.
    IN  MX 10   mydomain.com.

    IN  A       192.168.1.250
ns  IN  A       192.168.1.250
*   IN  CNAME   192.168.1.250

内向きの逆引き用設定ファイル
debian-sv# vi /etc/bind/1.168.192.db
$TTL 86400
@ IN SOA    ns.mydomain.com.  root.mydomain.com.(
    2017020101  ;Serial
    28800       ;Refresh
    14400       ;Retry
    3600000     ;Expire
    86400       ;Minimum
)
    IN NS       ns.mydomain.com.
    IN MX 10    mydomain.com.
250 IN PTR      mydomain.com.

以上で設定完了。
BIND9を再起動させる。
debian-sv# systemctl restart bind9

動作確認してみる。
debian-sv# dig mydomain.com

; <<>> DiG 9.9.5-9+deb8u9-Debian <<>> mydomain.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15622
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;mydomain.com.                 IN      A

;; ANSWER SECTION:
mydomain.com.          86400   IN      A       192.168.1.250

;; AUTHORITY SECTION:
mydomain.com.          86400   IN      NS      ns.mydomain.com.

;; ADDITIONAL SECTION:
ns.mydomain.com.       86400   IN      A       192.168.1.250

;; Query time: 41 msec
;; SERVER: 192.168.1.250#53(192.168.1.250)
;; WHEN: Tue Feb 07 21:10:59 JST 2017
;; MSG SIZE  rcvd: 91

上手く引けてるっぽい。作業完了!

参考サイト:
mk-mode BLOG「Debian 8 (Jessie) - DNS サーバ構築!」
ペイパー・プログラマーズ・ダイアリー「BIND9で内向きDNS構築 on Ubuntu」
VineLinuxで自宅サーバー「内向きDNSサーバー構築」