2023/08/20

httpd (Apache2)が起動しなくなった為、オボエガキ

今日、急に社内のローカルサーバのhttpdが停止していた為、 状況を確認したところ、ゾンビ状態だったので、
一度停止し、再起動を図る。

# systemctl start httpd
   Job for httpd.service failed because the control process exited with error code. See "systemctl status httpd.service" and "journalctl -xe" for details.

起動失敗となったので、表記のコマンドにて調査
# systemctl status httpd.service
# journalctl -xe

しかしながら、エラーはないため、

# apachectl configtest でsyntaxErrorがないか確認するもエラーなし。

そこで、
/var/log/httpd/error_logを覗くと、起動時にサーバ証明書のことを云っている。

そこで、取り敢えず、
# nano /etc/httpd/conf.d/ssl.conf

#   SSL Engine Switch:
#   Enable/Disable SSL for this virtual host.
SSLEngine off
として再起動するも、同じエラーが消えない。

/etc/httpd/conf.d/配下に nss.confがあり、これがエラーを誘発しているようなので、

# nano /etc/httpd/conf.d/nss.conf

#   SSL Engine Switch:
#   Enable/Disable SSL for this virtual host.
NSSEngine off

として再起動すると、httpsが立ち上がった。

念のため、証明書を確認してみる。
# certutil -L -d /etc/httpd/alias -n Server-Cert
見てみると、
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4 (0x4)
        Signature Algorithm: PKCS #1 SHA-256 With RSA Encryption
        Issuer: "CN=Certificate Shack,O=example.com,C=US"
        Validity:
            Not Before: Fri Aug 16 03:19:38 2019
            Not After : Wed Aug 16 03:19:38 2023
 

何かのモジュールを入れる際に、mod_nssが一緒に実装されており、
その際に実装された証明書の期限が 昨日だったため、今日から停止した様子。
上記の証明書はデフォルトで

phpinfoを見ると、SSLはOpenSSLを利用しており、そもそも、内部の閉鎖LAN下のサーバのため、mod_sslを積極的に使っていないと思われる。
とりあえず、この状況で稼働させて様子をみる。
支障が出た際は、nss.confかssl.confを有効にして、自前のサーバ証明書の作成を行うこととする。


これ、通常稼働させていて署名切れた後に、何かの拍子にサーバを再起動させた際は
動かなくなるから焦る可能性が非常に高い。

2022/05/11

gmailにspamの烙印を押されたので、SPFレコード、DKIMを設定する。

 SPFレコードの設定

# nano /var/named/hoge-co.jp.db

末尾に

hoge-co.jp.              IN      TXT    "v=spf1 +ip4:xxx.xxx.xxx.xxx +mx ~all"
  ※xxx.xxx.xxx.xxxはメールサーバのIPv4アドレス
を追加

BINDを再起動
# service named restart

 

OpenDKIM のインストール
# yum install -y –-enablerepo=epel opendkim

ディレクトリ作成
# mkdir /etc/opendkim/keys/hoge-co.jp
# opendkim-genkey -D /etc/opendkim/keys/hoge-co.jp -b 2048 -d hoge-co.jp -s 20220505

-b 1024以上でないとgoogleは認めてくれないが大きければ良い訳ではないようなので、2048とした。
-d 一般的にはメールアドレスの@より後ろのドメイン名を指定
-s 管理しやすい任意の文字列を指定 とりあえず日付

念のためパーミッションを変更

# chmod 700 /etc/opendkim/keys/*/
# chmod 600 /etc/opendkim/keys/*/
*

設定ファイル修正
# nano
/etc/opendkim.conf

Mode sv   s→svに変更
Syslog  yes
SyslogSuccess   yes
LogWhy  yes
UserID  opendkim
Socket  inet:8891@localhost
Umask   007
# Statistics    /var/spool/opendkim/stats.dat
SendReports     yes
SoftwareHeader  yes
Canonicalization        relaxed/relaxed
# Domain        example.com
#Selector      default  コメントアウト
MinimumKeyBits  1024
KeyFile /etc/opendkim/keys/default.private
KeyTable        /etc/opendkim/KeyTable の#を外し有効化
SigningTable    refile:/etc/opendkim/SigningTable の#を外し有効化
AlwaysAddARHeader true 追加

保存して閉じる

#nano /etc/opendkim/KeyTable
20220505._domainkey.hoge-co.jp hoge-co.jp:20220505:/etc/opendkim/keys/hoge-co.jp/20220510.private

保存して閉じる

#nano
/etc/opendkim/SigningTable
*@hoge-c.jp 20220505._domainkey.hoge-co.jp

保存して閉じる

起動と自動起動化
# systemctl start opendkim
#
systemctl enable opendkim

postfixに関連付け

#nano
/etc/postfix/main.cf
 
smtpd_recipient_restrictions = permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination,reject_unauth_pipelining,reject_invalid_hostname,check_sender_access hash:/etc/postfix/check_backscatterer,check_policy_service unix:private/policyd-spf
 
 
末尾に
milter_protocol = 2
# OpenDKIM smtpdが利用するmilter定義
smtpd_milters = inet:localhost:8891
# smtpd以外が利用するmilter定義
non_smtpd_milters = $smtpd_milters
# milterがメールを受信時のデフォルト動作
milter_default_action = accept

を追加し、保存して閉じる

再起動
# postfix reload

DKIM 公開鍵レコード設定

自動的に255文字以下に分割してくれているので、加工してDNSに記載する。

ADSPをDNSに設定
#nano
/var/named/hoge-co.jp.db に
20220505._domainkey.hoge-co.jp.  IN      TXT     ( "v=DKIM1; k=rsa; "

          "pごにょごにょ~"

          "ごにょごにょ~");
_adsp
._domainkey.hoge-co.jp.  IN TXT "dkim=unknown" を追加。

 

BINDを再起動
# service named restart

上手くいかねぇ・・・。
https://de-vraag.com/ja/71638753
同じような症状があったので、参考にさせてもらいようやく何とか上手くいった・・・。

postfixユーザーをopendkimのグループに所属させないと、ソケットが通らない。
こんなの分からねーですよ・・・。6時間位かかった・・・。

# usermod -aG opendkim postfix

# cat /etc/group
 opendkim:x:989:postfix 所属した。

先人によると、このデーモンに不具合があるらしく、
# nano /lib/systemd/system/opendkim.service
 ExecStart=/usr/sbin/opendkim $OPTIONS 
この$OPTIONSの宛先がおかしいことがあるらしい。
$OPTIONS の先を探しに行っ足りしたが、上手くいかず、それに嵌った。

/var/run/opendkim/opendkim.pid
/var/run/opendkim/opendkim.sock この定義ファイルを読み込ませたいのだが、

warning: connect to Milter service inet:localhost:8891: Connection refused
上記エラーがかえって来る。


最終的に、先人の方々の知恵を借り、力技でゴリ押した。

ExecStart=/usr/sbin/opendkim -P /var/run/opendkim/opendkim.pid -p local:/var/run/opendkim/opendkim.sock -p inet:8891@localhost

User=opendkim
Group=opendkim

とした。

暫くして、SPFレコード、DKIMレコード共に支障なく浸透したことを確認後、
セカンダリDNSと同期をとるために、ゾーン定義(
/var/named/hoge-co.jp.db)のシリアル値を更新して

@       IN      SOA     ns.hoge-co.jp. root.hoge-co.jp. (
                                2022050500 ; serial値
                                1H      ; refresh (3 hours)
                                900     ; retry (1 hour)
                                5D      ; expire (2 weeks 6 days)
                                1D      ; minimum (1 day)
                                )
保存して
BINDを再起動。

※googleさんは、セカンダリDNSの設定も併せて見に行くようで、
 プライマリDNSとセカンダリDNSがきっちり同期とれていないとメールを弾く仕様にレベルアップしているようだ。


DNSが浸透したらgoogleさんがメールを許容してくれるようになった。


とりあえず、OpenDMARCのインストールまでは行った。

# yum install opendmarc
# nano /etc/opendmarc.conf
が、今のところgoogleさんはDMARCは必須としていないので、設定は今後様子を見て行う。


2022/04/15

CentOS7(RHEL 7)のemergency mode

WEBサーバの稼働日が399日目だったが、
javaのアプリケーションの安定動作の為、定期的に再起動を掛けている。
利用者のセッション情報を上手く離さないままで正常に終了しない状態が続くと
応答を繰り返す可能性があるが、利用者への配慮でタイムアウト時間をかなり長めに取っていることにも起因している可能性がある。
正常時は、正しく返す応答が、中途半端にセッションを有したまま、再起動が掛かってしまい、当然セッションがないので、応答が次々と繰り返られれば、
短い時間でスレッドの上限に達し、ヒープ領域の食事を延々を行い、
ヒープ領域を食い尽くし、FULLGCが起こる原因になりかねない。
タイムアウト時間の見直しは課題として、検討を行うとして、

前段が長くなったが、上記の状態に陥り、load averageが7近くまで上昇してしまい、
各アプリケーションが自然に停止してしまった為、止むを得ずWEBサーバ
の再起動を行ったのだが、およそ一年前にコンソールから追加できないディスク領域の拡張依頼をしたのだが、その際、fstabが修正されておらず、今回の症状となったようだ。

Welcome to emergency mode! After logging in, type "journalctl -xb" to view
system logs, "systemctl reboot" to reboot, "systemctl default" to try again to
boot into default mode.
Give root password for maintenance (or type Control-D to continue):

と表示された・・・。

rootでログインし、
# mount -a でどのマウントが引っかかっているか原因を探る。

mount: special device /dev/sd?/  does not exist となったので、

/etc/fstab の構成と比較し、 /dev/sd?のドライブレターと齟齬が生じている箇所を
修正する事となる。

複数のドライブに不具合が生じている際は、正しいマウント先を確認しながら
fstabの修正が必要となるので、注意のこと。

尚、不可解な点が一点あり、fstabの先頭に\が記載されていた。
コンソールからの追加では、自動的にfstabが書き換わる仕様だが、
エンジニアが介入する特殊なディスク領域拡張にはおそらく対応していない為、
作業マニュアル等の中に、作業開始時にシステムの破損を防ぐため、
fstabの先頭に\を記載し、上書き保存 のようなルールがあるのではないか?
事実、ドライブの構成を確認しながらfstabを修正する破目に陥ったので、
最も効率的にリスクを回避できるので、上記のルールを策定した人は、
とても頭の良い方だと素直に尊敬できる。



https://www.symmetric.co.jp/blog/archives/65
https://atmarkit.itmedia.co.jp/ait/articles/0711/27/news122_3.html
の記事が大変参考となった。感謝いたします。


2021/11/28

NTT フレッツ光ネクスト 契約回線確認等のサイト接続

 NTT東日本のフレッツ光ネクストを利用しているが、
手続中に契約回線確認等でサービス情報サイトにアクセスする必要がある。

サービス情報サイト (https://flets-east.jp/)

その際、Windowsのネットワークのプロパティにて、ipv6を許容していないと、
サイトにアクセスできなかったので、 オボエガキ。

以前はIPv4のみ(ネットワークプロパティ上でIPv6を利用しない状態)で接続できていたが、
ONUがIPv6対応の場合、IPoEのみ情報サイトへの接続を許容している模様。
PPPoEにてIPv4方式のWebサイトへ強制的に向けるよう、PPPoE接続設定を行い、
NTTルータのPPP接続ランプも2か所に接続された状態になったのだが、内部処理は、
IPv6を優先に接続させようとするようで、機械的にルータ側はIPv6側に接続されている場合は、
IPv4へ切り替える作業は行わない仕様のようだ。
そのため、WindowsのネットワークのプロパティでIPv6をOFFにする効果がないということが分かった。
Microsoftはレジストリレベルで、IPv4の優先度を上げる設定を推奨している記事があった)
レジストリでIPv6を非対応にすればよいが、あまり意味を感じず、そこまでのテストは行っていない。


 左図の赤で囲んだ(TPC/IPv6)にチェックが入っていないと、
 上記のサイトにアクセスできない状態となる。


 今まで、IPv4の速度向上に効果があるということで、
 IPv6の設定を無効にしていたが、
 ここの設定をoffにしてもOSの内部的な優先度は
 あくまでIPv6が高い状態で処理が行われているそうだ。
 









参考URL https://turningp.jp/server-client/windows/windows-ipv6-ipv4

2021/10/20

postfix メールの受信を拒否する_spam等対策

spamメールの対策のオボエガキ

http://www.postfix-jp.info/trans-2.2/jhtml/header_checks.5.html

上記を参考にすると、
/etc/postfix/main.cf の
header_checks = regexp:/etc/postfix/header_checks
を有効にする。

/etc/postfix/header_checks の末尾等に排除条件を追記する。

cf)
件名に「残念ながらあなたの」~が含まれる場合
/^Subject:.*=?ISO-2022-JP?B?GyRCO0RHMCRKJCwkaSQiJEokPyROGyhC?=.*/ REJECT

※日本語は、エンコードしないと駄目。

ユーザhogeへのメール(hoge@xxx.comが受信)を拒否する場合
/^To:.*hoge@xxx.com/ REJECT


あくまで非mimeのヘッダーチェックなので、以下の内容に限る。
受信サーバ側から見るので、
Cc:           同時送信されたユーザ
From:       送信元ユーザ 
Subject: 件名
To:           受信者 

この辺りは、使える。


最後に設定を反映

# systemctl restart postfix

2021/08/23

NAS(TeraStation)が起動しなくなった際のサルベージ方法

会社の定期電気点検に伴って、物凄い台数の機器の電源の入り切りが発生したのだが、

十数台あるNASのうち1台の基盤が壊れたらしく、起動しなくなってしまった。

HDDは3年毎くらいで交換したが、本体は7年以上頑張ってくれたみたい。ありがとう・・・。

 

とはいえ、データは救出して使えるようにしないと問題なので、

同世代のNASを覗いてみると、XFSフォーマットだった。

CentOSでそのままいけるじゃないか!と気楽に外付けでHDDを接続し、

マウントしようとしたが、

mount: unknown filesystem type 'linux_raid_member'

レイド組んでると、普通にマウントできないそうだ・・・。

少し調べると、mdadm(Multiple Devices maapper administrator の略と思われる)という

ユーティリティがあるので、それを使ってレイド構成として認識させるとあった。

 

物理又は、ソフトウェア的にレイドを組んでいるマシンで作業すると

ぶっ壊れる恐れがあるので、『レイドが組んでいないマシンで作業』すること!

 

# yum install mdadm でユーティリティをインストールする。

 

RAID状態だったHDDをUSB等で接続すると、md124とかmd125とかの
mdマップが自動作成させてしまっているので、一旦それらを停止させる必要があった。

# cat /proc/mdstat で調べると、inactiveとして認識されているが、これが原因の様子。

そこで、
# mdadm --stop --scan でraidアレイをすべて停止させてから、

mdadmのコマンドでマウントさせるためのデバイスを認識させる。
# mdadm --assemble --run --force /dev/md7 /dev/sdd7
接続したHDDはsdd7 認識させるmdもわかりやすくmd7とした。

mdadm: /dev/md7 has been started with 1 drive (out of 2).
と出れば、dev配下にmd7として認識されたことになる。

# mkdir /mnt/nas_hdd
わかりやすくnas_hddというディレクトリを作成し、マウント

# mount /dev/md7 /mnt/nas_hdd

アンマウントは、通常通り、
# umount /mnt/nas_hdd で良い。


転ばぬ先の杖はちゃんと用意しないといけないですね。
こんな作業知らないで済むならその方が良いし、消えて欲しくないデータなので、
精神衛生上あまり宜しくない作業だった。

RAIDは便利だけど、起動しなくなった時はつらいなぁ。

2021/05/31

定点カメラ motionを使って定点カメラ

motionをraspberry pi4に入れて定点カメラとして動かしたい
インストール
$ sudo apt install motion
設定
$ sudo nano /etc/motion/motion.conf 

設定はごにょごにょする。
自動起動については、
daemon on
とすれば、自動起動になる。

 

USB接続のカメラを使うとき
$ lsusb で接続を確認
$ ls /dev/video*
等でカメラのIDを確認して、設定してあげればよい。

 尚、複数台のカメラを動かす場合は、

thread /usr/local/etc/thread1.conf
thread /usr/local/etc/thread2.conf
のようにmotionが読込めるディレクトリを作成し、motion.conf に作成したスレッドファイルに絶対パスで指定する必要がある。
制御するWebカメラが1台の場合は、motion.conf に全てを記述し、threadファイルは必要なし。

usr/local/etc/thread1.conf
共通する設定は motion.conf に、カメラ固有に設定が必要と思われる項目を
thread1.conf、thread2.confに記載する。
motion.conf と thread.conf でパラメーターが重複しても優先されるのは threadファイルとなる。

 ポートは8081等で開放しておくこと。
複数台の場合は、当たり前だが各々開放が必要なので、定義のこと。

/etc/motion/thread1.conf
# カメラデバイスの指定(ここをvideo0等の割当先に指定する。)
videodevice /dev/video0
# Webブラウザから画角調整やキャプチャ動作を確認のためポート設定
stream_port 8081

 

 
 

 




2021/05/07

PHP7以前 クエリ結果のカラム文字列を取得できない場合(2GB文字列問題)

データベースのカラムからデータを取得し、phpで扱う作業を行った際、
文字列を取得してこなくて、酷く嵌ったので、オボエガキ。

PHP7とPHP5で平行稼働させている類似のプログラムがあり、
先にPHP7を修正し、追加のカラムの文字列を取得させると、意図する通りに動作した。

続いてPHP5を動かすが、 取得してこない。

 

色々調べたところ、PHP(7以前)の文字列型は2GB以上の文字列を処理できない
正確には、nverchar等でカラムサイズが2147483647(int4の最大値)
で定義されている場合、PHP内でうまく扱えず、空白として処理されてしまうようだ。

PHPのzvalue_value共用体で文字列長をint型で管理しているため、
文字列の長さが2147483647を超えるとマイナスになってしまうことが原因らしい

PHP5のまま稼働させる必要があったので、クエリにてレコードを取得する際に、

select CONVERT(VARCHAR(512), <カラム名>) as hoge from <table名> where ~;

 

のように、varcharのサイズを指定してカラムを取得すれば,以降PHP内でカラムの文字列を扱えた。

3時間くらい同僚と嵌ってしまい、困ったので、忘れないように残しておく。



2021/03/02

rapidSSL サーバ証明書更新のオボエガキ

前提
opensslコマンドがつかる環境である事

申込後
WEBサイトから更新の申し込みを行い、その際取得した、CSRとKEYをテキストファイルに
貼り付け、 key.txt と csr.txt 等の名前で作業ディレクトリに保存 
key.txtをサーバにアップするため、RSA形式に変換


# openssl rsa -in key.txt -out <サーバにアップする際の名前>.key
# openssl rsa -in key.txt -out hoge_2021rsa.key
(今回は仮として、hoge_2021rsa.key とする)
-----BEGIN RSA PRIVATE KEY----- から
-----END RSA PRIVATE KEY-----  のRSA形式の秘密鍵に変換できる。

中間証明書をrapidSSLのサイトから取得
https://www.geotrust.co.jp/resources/rapidssl/repository/intermediate_sha2.html
ここが正規の所みたいだが、RapidSSLの人は、デジサートのアカウントじゃないから、
2021年の3月以降は、このページではサポートしないようである。
3月以降下のURLにリダイレクトさせると記載されている。
https://knowledge.digicert.com/ja/jp/solution/SOT0018.html?_ga=2.199517224.764125246.1614230988-505583794.1614230987
リンク先にある、テキストフィールドの
「—–BEGIN CERTIFICATE —–」から
「—–END CERTIFICATE—–」をテキストに貼り付けて、
中間証明書のcrtファイルとして保存する。(仮にintermediate_2021.crt とする)

 2021-03現在、crtファイルの生成に、DNS テキストフィールドを利用して
認証させる方法をrapidSSLが採用しているので、
サーバのnamed.serviceの設定ファイルにTXTレコードを追記し、
named.serviceを再起動させる。

DNSサーバツールであるbindがインストールされているはずだが、
無い場合は、インストールしておく。弊社はbindで動いている。
# yum install bind
# yum install bind-utils

設定ファイルは以下に保存されているはずなので、

/etc/named.conf の中に記載の ディレクトリにあるdbに追記TXTレコードを追記

・・・
options {
//listen-on port 53 { 127.0.0.1; };
listen-on port 53 { 192.168.142.31; };
listen-on-v6 port 53 { ::1; };
directory  "/var/named";
dump-file  "/var/named/data/cache_dump.db";
・・・


上記の場合、cache_dump.db に記載すれば良い

TXTレコードは

ドメイン名   :hoge.jp
ホスト名    : 
レコードタイプ : TXT
指定内容(Value):
1234567890abcdef(rapidsslから指示がある文字列)

例: hoge.jp.   IN TXT "
1234567890abcdef"

複数行ある場合は、カンマ区切りで一行に書くこと
(複数行で記載すると、最初の一行だけ反映される仕様のようだ)

DNSサーバ再起動後、30分くらいでTXTレコードが拾えるようになるはず。

googleさんにお願いしてhoge.jpのTXTレコードを照会する場合
$ dig @8.8.8.8 hoge.jp TXT 
;; ANSWER SECTION:
hoge.jp.         2xxxx   IN      TXT     "
1234567890abcdef"

こう帰ってくれば、反映されている。

この状態で、
Digicert社(rapidsslの親会社)が定期的にDNSをチェックしている際に、
上手く
TXTレコードに指定の文字列が確認が取れると、承認作業が完了し、Digicert社の審査を経て証明書発行される仕組み。

証明書がメールで送られてくるので、
「—–BEGIN CERTIFICATE —–」から
「—–END CERTIFICATE—–」をテキストに貼り付けて、crtファイルとして保存する。
(今回は、仮に
hoge_2021.crt とする。)

続いて、ssl証明書の配置をする。

設定ファイルは
/etc/httpd/conf.d/ssl.conf
に配置されているので、中身を確認し必要であれば、修正後のファイル名に置き換え等の
作業を行い、指定のディレクトリにRSA形式の秘密鍵と中間証明書.crt、証明書.crt
ファイルを配置した状態(ssl.confの中以下の記載のアドレスにファイルを配置)
#   Server Certificate:
SSLCertificateFile /usr/local/ssl/crt/hoge_2021.crt
#   Server Private Key:
SSLCertificateKeyFile /usr/local/ssl/private/hoge_2021rsa.key
#   Server Certificate Chain:
SSLCertificateChainFile /usr/local/ssl/crt/intermediate_2021.crt

上記のような状態でhttpdを再起動すれば、反映される(はず)
再起動
# systemctl restart httpd



2021/01/26

PHP XMLファイルからデータ取得

PHPにてXML形式のファイルから必要なデータを取得する。

予めssh2が使えるように、
libssh2とssh2のextensionを PHP7にインストールしておく。

#yum install gcc glibc-devel zlib-devel openssl-devel
#yum install --enablerepo=epel,remi,remi-php73 php-devel

本家LIBSSH2サイトへアクセスしwgetで取得
# wget https://www.libssh2.org/download/libssh2-1.9.0.tar.gz
# tar vxzf libssh2-1.9.0.tar.gz
# cd libssh2-1.9.0
# ./configure
# make
# make install

ライブラリ PCELから ssh2のモジュールを取得
# wget https://pecl.php.net/get/ssh2-1.2.tgz
# tar vxzf ssh2-1.2.tgz
# cd ssh2-1.2
# phpize
# ./configure --with-ssh2
# make
# make install

extensionに認識
php.iniに
extension=ssh2.so を記述し、apacheを再起動。

<?php
$filepath="<取得先のxmlファイルのアドレスを指定>";
//SCPでファイル要求
$connection = ssh2_connect('192.168.0.xxx', 22);//22ポートは開放しておく
ssh2_auth_password($connection, '<ユーザ名>', '<パスワード>');
$get_add = "/var/www/html/xml/get.xml";//一旦ローカルに取得
ssh2_scp_recv($connection, $filepath, $get_add);
//file_existsを使い、xmlがあればデータを取得させる
if(file_exists("/var/www/html/xml/get.xml")){
$xml=simplexml_load_file("/var/www/html/xml/get.xml");

//xmlの中身を取得 階層が深い時は、->で階層を深く指定すれば取得できる。
//xmlの構成を以下とした場合
//<address>
//  <zip>100-0001</zip>
//  <add>東京都何某</add>
//</address>

$column_xml = ($xml->address->zip);//zipの中身を取得
echo "取得したxmlのデータ⇒".$column_xml;
}else{
echo "xml取得失敗";
}
//ディレクトリに残存する当該xmlファイルを削除する
array_map('unlink', glob("/var/www/html/xml/get.xml"));
?>

 

2021/01/21

シェル(bash) データベースへのレコードを自動挿入

指定の時間に成ったら、レコードを挿入するためのシェル(bash)

#!/bin/bash
#postgresqlへアクセスし、データを書き込む
psql "postgresql://<ユーザ>:<パスワード>@192.168.0.xxx/<データベース名>" << _EOF
insert into table1 (create_date)
select to_number(to_char(now(), 'YYYYMMDD'),'99999999')
where NOT EXISTS (select 1 from table1 where create_date=to_number(to_char(now(), 'YYYYMMDD'),'99999999'))
_EOF

exit $?


データベースへの格納条件
create_dateは20210121のnumeric型

create_dateに今日の日付が入っているものが存在しなければ、
create_dateに今日の日付「YYYYMMDD」のnumeric型のデータでそのほかはデフォルト値
のレコードを挿入する。
存在すれば、レコードを挿入しない。

これをcronやRUNDECK等を使って指定の時間にシェルを走らせればいい。

Postgresql データ型変換 char numeric date関連

日付の取り扱いでよく使うもののオボエガキ

【1】今日の日付をnumericに20210121に形で格納したい場合
  now()をcharでYYYYMMDD型に加工した後に、numberで8桁の数値に変えればよい
結果  to_number(to_char(now(), 'YYYYMMDD'),'99999999')

 

【2】8桁の数字20210121をタイムスタンプ型にしたい場合
結果 to_timestamp(to_char(’20210121’,'0000-00-00'),'YYYY-MM-DD'))

 

【3】2021-01-21 12:00:00.0 を 2021-01-21のタイムスタンプ型で扱いたい場合
結果 to_timestamp(to_char(’2021-01-21 12:00:00.0’,'YYYY-MM-DD'),'YYYY-MM-DD')

 

※【2】と【3】は同じタイムスタンプ型になっているので、
where等で 【2】-【3】> INTERVAL '3 days' 等で経過日数を条件としたり出来る。

 

to_charの扱いとして
to_char(1111,'99999') ⇒ ' 1111' 先頭に空白を含み、指定桁数無視
to_char(1111,'FM99999') ⇒ '1111' 空白なし指定桁数無視
to_char(1111,'00000') ⇒ ' 01111' 先頭に空白と含み指定桁数のゼロを付加
to_char(1111,'FM00000') ⇒ '01111'  空白なし指定桁数のゼロ付加

となる FMをつけないと格納できないようなDBもあり得る。

2020/08/19

centos7 sambaサーバにcifsでマウントする

windowsユーザの為に、samba

接続したい名前を検索する。

 # smbclient -L 192.168.0.xxx -U%


        Sharename       Type      Comment
        ---------       ----      -------
        info            Disk      hogehoge Utilities
        share           Disk      hogehoge
        share2          Disk
        share3          Disk
        IPC$            IPC       IPC Service (hogehoge)
Reconnecting with SMB1 for workgroup listing.

        Server               Comment
        ---------            -------

        Workgroup            Master
        ---------            -------
        WORKGROUP            hogeFile


マウントしたい先は、//192.168.0.xxx/share2 と分かった。

# mount //192.168.0.2/share2 /home/hoge/mnt/ -o username=<sambaの登録ユーザ名>,password=<その人のパスワード>

 マウント先でシンボリックリンクを有効にしたい際は、

 # mount //192.168.0.2/share2 /home/hoge/mnt/ -o username=<sambaの登録ユーザ名>,password=<その人のパスワード>,mfsymlinks

と末尾に ,mfsymlinksのオプションを付加すること。

 接続先のcifsのヴァージョン古い場合は、ver2.0等の追記が必要とのことだが、

デフォルト値で接続できたので、このまま運用する。

 接続解除

# umount /home/hoge/mnt

 

 

ディレクトリのパーミッション一括変更処理

新たなユーザと新たなグループを作成し、既存のディレクトリのパーミッションを
数百個一括で変換したい事案が出たので、オボエガキ

findを使ってディレクトリを絞ってパイプでxargsに投げる方法

 

# find /home/hogehoge/test -type d -user nobody -perm 0755 -print | xargs chmod 644


『/home/hogehoge/test』配下にある『nobodyユーザ』の
パーミッション『0755』のディレクトリを『フルパス形式の標準出力』にして
『パイプ』以降の 『xargs』コマンドを使って『フルパス形式の標準出力』に対して、
パーミッション『644』を定義する。

findコマンド
find <処理したいディレクトリの先頭> <オプション>
オプション
-type d ディレクトリファイルを検索
-user nobody ユーザnobodyのファイルのみ検索
-perm 0755 パーミッションが755のものを検索
-print 見つけたファイルをフルパスで出力

| xargs chmod 644
パイプ『|』の右側へ左側のコマンドを投げる
xargs 標準入力やファイルからリストを読み込み、コマンドラインを作成して実行
chmod 644 パーミッションを644に変更

同じような操作方法として、パイプを使わずに パイプ以降を
-exec chmod 644 {} + と記述する方法もあるが、

xargsよりもexecのほうが処理の手順が多く、ファイル数が多くなるほど負荷がかかるため、
基本はxargsを推奨とのこと。
コマンドの分かりやすさからも、xargsのほうがよさそう。

2020/07/28

phpmailer のSMTP送信で嵌った際の対処

表題に行きつくまで2時間ほど嵌ったのでオボエガキ

以前のphp5.4.16では何の問題もなく動いていたのだが
新しいサーバがPHP 7.2.21で稼働している。

PHP5.6から、verify_peerのデフォルトがtrueになったそうで、
SMTP認証をする際に、証明書を求められてエラーが返ってくる。
自己署名証明書も駄目っぽいので、証明書の設定をしないでSMTPを使いたいとき

verify_peerを使いませんと宣言すればよい
と先人は簡単に仰っていたが、ここに行きつくまで2時間かかった・・・。

$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);



以下、phpのサンプル

<?php

//----------
//メール作成
//----------

//PHPMailer ライブラリ読み込み
use PHPMailer\PHPMailer\PHPMailer;//PHPMailerの呼び出し
require_once("./vendor/autoload.php" );//位置は適宜設定のこと

mb_language("japanese");//言語設定、内部エンコーディングを指定mb_internal_encoding("UTF-8");

$files = "generate.csv";//アドレスは適宜設定のこと
//日本語添付メールを送るための設定
$to = "hoge@hoge.jp"; //宛先 必須
//$cc = "";
//$Bcc = "";
$subject = "メールのタイトル名";
$body ="本文\n";
$body.="添付のcsvファイルをご確認のこと。\n";
$body.="\n";
$from = "hoge2@hoge.com"; //送り主
$fromname = "送信者名";

//PHPMailerのインスタンス生成
$mail = new PHPMailer(true);//Exceptionを使う場合はtrueにする事使わないときは()でも動く
$mail->CharSet = "iso-2022-jp";
$mail->Encoding = "7bit";

//SMTPサーバ設定
$mail->IsSMTP();
//$mail->SMTPDebug = 0; // 0:デバッグOFF 1:デバッグON
$mail->SMTPAuth = TRUE;
$mail->Host = 'mail.hoge.jp:587';
$mail->Username = 'hoge';
$mail->Password = 'hogehoge';
$mail->SMTPSecure = 'tls'; //TLS
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
$mail->AddAddress($to);
//$mail->AddCC($cc);
//$mail->AddBcc($Bcc);
$mail->From = $from;
$mail->FromName = mb_encode_mimeheader(mb_convert_encoding($fromname,"JIS","UTF-8"));
$mail->Subject = mb_encode_mimeheader(mb_convert_encoding($subject,"JIS","UTF-8"));
$mail->Body = mb_convert_encoding($body,"JIS","UTF-8");

//添付ファイル
$mail->AddAttachment($files);

//メールを送信
if (!$mail->Send()){
echo("Failed to send mail. Error:".$mail->ErrorInfo);
}else{
echo("Send mail OK.");
}


?>


このような記述で動作した。


後日追記
証明書を取得してpostfixのsmtpd_tls_cert_file などにPKCS12形式のcrtファイル
を配置し、テストしたところ、
verify_peerについての記述をしなくとも、正しく動いた。





twilio Enable Two-Factor Authentication (2段階認証)設定

Twilioから
[Action Required] You must enable Two-factor authentication on your Twilio accounts by October 12, 2020

というメールが来た。
中を見ると、2020年の10月12日からセキュリティ上2段階認証を要求します。
2段階認証を許容していないとロックアウトされてしまうので、設定変更してね
という内容だった。


    1.Login to Twilio Console
    2.Go to “User Settings” page (below your name on the top right corner) in Console
    3.In the "Enable Two-Factor Authentication (2FA)" section, select desired 2FA level
     and click “Update 2FA Settings” to save your selection.
    4.In the "Two-Factor Authentication (2FA) Methods" section, select the desired 2FA method
     and click “Update 2FA Method” to save your selection.
    5.Users enabling 2FA for the first time will be required to go through a one-time login
     and verification process with your new 2FA method of choice.

      手順に従って設定してみた。

      1.今までのようにログインする。
      2.右上のユーザー名をクリックして、User Settings画面に移動
      3.Enable Two-Factor Authentication (2FA) の
        30日毎に認証を選択し(毎回は流石に面倒と判断)
        Update 2FA Settings をクリック
      4.認証画面に飛ばされるので、 日本(+81)を選んで、ユーザ登録した際の
        sms番号(090-xxxx-yyyyなら90xxxxyyyy)を入力して送信
      5.携帯にsmsが飛んでくるので、認証コードを入力する。
      6.トラブル用の回復コードが飛んでくるので、携帯のsimが使えなくなった場合など
        の為に、メモっておいたほうがいいかも。
      7.無事ログインできた。

       メールにある、 In the "Two-Factor Authentication (2FA) Methods については、
      再度ログイン後に選択可能だったので、最初の一回目は テキストメッセージが
      飛んでくるようだ。
      認証コードを送信するための画面の説明は図入りの解説ページを設けても
      良いと思ったけど、twilioを使っている人は、全くの素人ではないだろうから
      自力で何とかするんだろう・・・。

      認証方法については、
      Authy app とあるので、アプリからの認証も出来る模様。
      https://apps.apple.com/jp/app/twilio-authy/id494168017 
      https://play.google.com/store/apps/details?id=com.authy.authy&hl=ja
      面白そうだけど、そもそもそんなにログインしないからテキストでいいや。

      2020/07/07

      inotifywait ディレクトリ監視から自動動作のサンプル

      ディレクトリ監視をして、業務効率化を図るべく、
      今更感満載ながらinotifywaitに手を出してみた。
      
      
      yumでインストールをする
      
      
      epelレポジトリにあるので、未導入時はepel-releaseをインストール
      # yum install epel-release 
       
      inotify-toolsをインストールする。
      # yum install inotify-tools 
      ヴァージョン確認 
      # inotifywait --help
      inotifywait 3.14
       
       
      動作は、ワンライナーでもOKだが、
      シェルスクリプトにて動作させたほうが、汎用性が高い。
       
      シェルスクリプトの例
      先駆者の方々の歴史を参考に
      今回は、pdftkと連携させ、監視ディレクトリにpdfファイルが新規作成されたら
      作業用ディレクトリに移動しPDFに作業済みスタンプを押して、
      作業済ディレクトリに保存という作業を想定。
       
      
      
      doSetStamp.sh
      
      
      ここから
      
      
      #!/bin/sh
      export PATH="/usr/local/bin:$PATH"#pdftkのパスを通す
      MONITORDIR="/home/hoge/work" #監視ディレクトリ指定
      ##スタンプは /home/hoge/stamp/back.pdfを想定
       
      inotifywait -m -r -e create --format '%w%f' "${MONITORDIR}" | while read NEWFILE
      do
        cd /home/hoge/work
        file=$(basename "${NEWFILE}" .pdf)
        mv "$file".pdf /home/hoge/work/"$file".pdf;
        cd /home/hoge/work/
        pdftk /home/hoge/work/"$file".pdf stamp ./stamp/back.pdf output /home/hoge/work/done/"$file"`date "+%Y%m%d"`.pdf;
        rm "$file".pdf
      done
      
      
      ここまで
      
      
      
      
      inotifywaitでなく、シェルのルールの問題だが、
      ダブルクオーテーションで括らないと、半角スペースでコマンドが止まってしまう。
      Windowsユーザが使うので、どうしても半角スペース問題は、加味しておかないと
      想定通りに動かない。
       
      バックエンドで動かす場合は、 
      $nohup doSetStamp.sh &
      のようにする。
      
      
      pdf以外のファイルをディレクトリに配置しない方法として、
      
      
      do~doneの制御にifで判別させて仕分ける方法が最も簡単だと思う。
      if [[ "$file" =~ .*pdf$ ]]; then  
       ここに動作させたい処理を書く; 
      else
       pdfファイル以外の処理を書く;  
      fi
       
       
      
      

      2020/05/14

      SPAM対策

      不覚にも、メールサーバのユーザパスワードが突破され、

      50件程度の踏み台にされてしまったので、対策を行った。

      先ずは、ユーザのパスワードを即座に変更

      # passwd <ユーザ名>
      Changing password for user <ユーザ名>.
      New password:
      Retype new password:
      passwd: all authentication tokens updated successfully.

      メーラー等の設定を修正する。

      スパム送信元のIPアドレスを探る。
        # tail -10000 /var/log/maillog | grep "LOGIN"
      May 14 05:29:03 www postfix/smtpd[xxxx]: xxxxxxxxxxxx: client=unknown[141.XXX.XXX.XXX], sasl_method=LOGIN, sasl_username=ごめんなさい・・・確かに、ヨーロッパのサーバ(ここも踏み台?)に突破されています。

      postfixに拒絶するIPアドレスを指定する。
      # vi /etc/postfix/main.cf

      末尾に
      smtpd_client_restrictions=
      permit_mynetworks,
      check_client_access hash:/etc/postfix/reject_ip,
      permit

      smtpd_client_restrictions で接続の許可、拒否の定義をする。

      permit_mynetworks, $mynetworksに書いたアドレスは許可する。

      check_client_access hash:/etc/postfix/reject_ip, 指定するipを拒否

      permit 上記以外を許可

      拒否するIPアドレス一覧を作成

      記載方法は、拒否したいIPアドレス、ドメイン + REJECTと記載。


      # nano /etc/postfix/reject_ip

      send.hogehoge.com REJECT
      141.XXX.XXX.XXX REJECT
      141.XXX.XXX REJECT

      reject_ipをDB形式に変換
      # postmap /etc/postfix/reject_ip

      Postfixをリロード
      # systemctl restart postfix

      設定が反映される。

      パスワードは、乱数生成が必須とまではいかないまでも、
      ある程度読まれないものにしないとだめだなぁ・・・
      突破されるとは思わなんだ・・・。

      2020/04/05

      slackの登録とbot起動 終了

      今更ながら、slackbotに手を出してみる

      参考にさせて頂いたところ
      https://se.miyabikno-jobs.com/entrance-labotlatori/

      Hubotを使う方法が簡単なようなので、上記を参考に導入

      01.slackのアカウント取得
      02.Hubotのアプリを追加
      03.HubotのAPIトークンを取得
      04.pythonのライブラリ slackbotをインストール
         $ sudo apt-get install python-3-pip
         $ sudo pip3 install slackbot
         $ mkdir slackbot
         $ cd slackbot
      05. $ touch slackbot_settings.py bot.py botmodule.py
         ・slackbot_settings.py:Botの設定を書くためのファイル(名称変更不可)
         ・bot.py:Botを起動するための実行ファイル(名前は任意)
         ・botmodule.py:Botの応答を記述するためのモジュール(名前は任意)
      06.$ nano slackbot_settings.py

      # 「API_TOKEN」にはSlackから取得したAPIトークンを記述
      API_TOKEN = "XXXXXXXXXXXXXXXXXXX"
      # 知らない言葉を聞いた時のデフォルトの応答
      DEFAULT_REPLY = "その言葉の意味は学習していません"
      # 外部ファイルを読み込む。botmodule.pyを読込
      PLUGINS = [
      'slackbot.plugins',
      'botmodule',
      ]

      07.$ nano bot.py

      from slackbot.bot import Bot
      # Botを起動する
      def main():
      bot = Bot()
      bot.run()
      if __name__ == "__main__":
      main()

      08.$ nano botmodule.py

      from slackbot.bot import respond_to
      from slackbot.bot import listen_to
      # 「respond_to」はメンションする(@でターゲットを指定すること)と応答する
      @respond_to('よろしく')
      def greeting_1(message):
      # Slackに応答を返す
      message.reply('よろしくお願いします!')
      # 「listen_to」はメンションがなくても応答する
      @listen_to('コニチハ')
      def greeting_2(message):
      message.reply('コニチハ')

      09.$ nohup python3 bot.py &
        ssh接続を切っても稼働するようにnohup ~ &で起動
            再度sshで接続し、プロセスを停止さえたい場合は、
            $ ps x
            にて pyhon3 bot.py のプロセスidを調べて、
        $ kill -9 
           として停止させる。

      ログインシェルがsshを閉じる際にSIGHUPを投げるため、プロセスが終了してしまうと思っていた。
      nohupはSIGHUPのシグナルハンドラをSIG_IGNに設定、つまり「受信しても無視」する設定にして、コマンドラインで指定されたジョブを実行している。 
      nohupで起動した時点ではRUNNNINGだが、端末が閉じられた後、標準入力に対してread()するようなプログラムでは、(5分ごとに読みなおしなどの動作が入るもの)はcloseしてしまっていて、
      EOFを返してきてしまう。


      nohupを使わなくても停止しないケースもあるようだが、説明が難しい。
      非常に詳しくテストされた解説が掲載されている
      https://www.glamenv-septzen.net/view/854
      実際は、SIGHUPのデフォルト処理はプロセス終了となっており、SIGHUPの受信にかかわらず、プロセスが終了するとき、そのプロセスがセッションリーダーだった場合、カーネルからそのセッションのフォアグラウンドプロセスグループに対してSIGHUPが送信されるらしい。
      また、カーネル側で放置しているバックグラウンドジョブに対しても、シェル(bash)側で終了時にSIGTERM/SIGCONTを送信する事があるためというのが実態のようだ。

      2019/12/12

      土日・祝祭日をカウントしないクエリ

      土日、祝祭日をカウントしないで、経過日数から処理を行いたい。

      休日テーブルのようなものを作って、LEFTJOINして加工
      のようなことをやっていたが、
      DBなくても動くものが欲しかったので、調べてみたオボエガキ。

      範囲を絞る方法として、
      次のように使う

      select 【id】 from 【table名】
      where (to_timestamp(to_char(now(),'YYYY-MM-DD'),'YYYY-MM-DD') -
      (to_timestamp(to_char(【table名】.【受付日】,'9999-99-99'),'YYYY-MM-DD'))) > interval '5 days'
      and
       (SELECT count(*) FROM generate_series(to_timestamp(to_char(【table名】.【受付日】,'9999-99-99'),'YYYY-MM-DD'),
      to_timestamp(to_char(now(),'YYYY-MM-DD'),'YYYY-MM-DD')-interval  '1 day',
      interval  '1 day') the_day
      WHERE (extract('ISODOW' FROM the_day) < 6
      and not(EXTRACT(MONTH FROM the_day) * 100
      + EXTRACT(DAY FROM the_day)
      IN (101, 113, 211, 223, 224, 320, 429, 503, 504, 505, 506, 723, 724, 810, 921, 922, 1103, 1123) ) ) ) >4

      idが 【table名】.【受付日】から5日以上経過(当日含まないので中4日)
      なお、条件として、【table名】.【受付日】がint2(8)の為、DATE型に変換している。

      解説
      副問い合わせをしているのだが、

      (SELECT count(*) FROM generate_series(to_timestamp(to_char(【table名】.【受付日】,'9999-99-99'),'YYYY-MM-DD'),
      to_timestamp(to_char(now(),'YYYY-MM-DD'),'YYYY-MM-DD')-interval  '1 day',
      interval  '1 day') the_day
      WHERE (extract('ISODOW' FROM the_day) < 6
      and not(EXTRACT(MONTH FROM the_day) * 100
      + EXTRACT(DAY FROM the_day)
      IN (101, 113, 211, 223, 224, 320, 429, 503, 504, 505, 506, 723, 724, 810, 921, 922, 1103, 1123) ) ) ) >4

       generate_series という集合を返す関数を使って、カウントが中4日となる様に制御している。

       generate_series
      (
      to_timestamp(to_char(【table名】.【受付日】,'9999-99-99'),'YYYY-MM-DD'),
      to_timestamp(to_char(now(),'YYYY-MM-DD'),'YYYY-MM-DD')-interval  '1 day',
      interval  '1 day'
      ) the_day

      始まり,終わり,間隔 と記載している。 
      終わりの中で -interval  '1 day' としているのは、当日を入れたくないため。

      WHERE
      (
      extract('ISODOW' FROM the_day) < 6
      and not
      (
      EXTRACT(MONTH FROM the_day) * 100
      +
      EXTRACT(DAY FROM the_day)
      IN
       (101, 113, 211, 223, 224, 320, 429, 503, 504, 505, 506, 723, 724, 810, 921, 922, 1103, 1123)
      )

      extract('ISODOW' FROM the_day) < 6 ISODOWは6が土曜、7が日曜となる。
      (DOWだと0が日曜、6が土曜)

      and not 以下の括りで、国民の休日をカウント対象から除外させている。

      EXTRACT(MONTH FROM the_day) * 100
      +
      EXTRACT(DAY FROM the_day)
      で月を100倍し、日と足す。
      これを 副問い合わせのIN関数
      (左側の式の結果が右側の式のどれかと等しい場合、結果は「真」を返す)
      を用いて、その日付だった場合は、2重否定となり、カウントされない。


      固定日以外の春分の日なんかは、国立天文台の算定式で括ってあげればいいんだが、
      このところ、天皇即位やオリンピックで変則が多いので、調べて直接日付を書いたほうが
      よさそう。

      春分の計算
      (EXTRACT(MONTH FROM date) = 3
      AND EXTRACT(DAY FROM date) = FLOOR(20.8431
      + 0.242194 * (EXTRACT(YEAR FROM date) - 1980))
      - FLOOR((EXTRACT(YEAR FROM date) - 1980) / 4))



      and not でそれぞれ括れば、除外できるが

      and not が直ぐに思いつかなかった・・・。