最近のコメント

    ラズパイが起動しない(SDカードが壊れた)

    娘ちゃんの自由研究でつくったルールベースの対話ロボ、久しぶりに初代ラズパイを起動しようとしたら、Kernelパニックで起動しない状態となった。娘ちゃん😭

    Rootパーティションが認識出来ない旨のメッセージが表示されていて、おそらくSDカードが壊れたようだが何とか復旧できないか試みたところ、意外とあっさり動作したのでメモ。

    以下、手順(と言っても大したことないが)

    • SDをUSBカードリーダーにセット
    • 生きの良いラズパイに接続
    • fdiks -l で/dev/sdb2として認識されることを確認(sdb1がBoot、sdb2がルートパーティション)
    • fsck -y /dev/sdb2 で復旧
    • mount -t ext4 /dev/sdb2 /mnt でマウント
    • 重要なデータ(娘ちゃんの作ったプログラム)を救出
    • umount /mnt
    • 初代ラズパイに戻して、起動 ⇒ 成功!!

    httpd.confのオリジナルと比較

    Apacheの設定がOSインストール時の初期設定との差分を見たいとき、下記のようにRPMファイルをダウンロードして、解凍して、比較すると良い。

    cd /tmp
    yum reinstall --downloadonly --downloaddir=./ httpd
    

    一瞬、yum のインストールが行われた様に見えるので、ドキッとするが、最後にこんな表示があった。

    exiting because "Download Only" specified

    ※DeepLで翻訳すると・・・「ダウンロードのみ」が指定されているため、終了する。

    で、ダウンロードされたRPMファイルを解凍する

    mkdir httpd_rpm_work
    cd httpd_rpm_work
    rpm2cpio ../httpd-2.4.6-97.el7.centos.5.aarch64.rpm | cpio -idv

    で、比較する

    diff /etc/httpd/conf/httpd.conf ./etc/httpd/conf/httpd.conf

    以上


    ラズパイにおけるRAID(mdadm)のはなし

    ラズパイWebサーバー(CentOS7)が古くなってきたので、にRockyLinux8をインストールしてWebサーバー運用を検討した。

    以前、CentOS7にて、mdadmのRAID1にて運用していたが不運が重なり2台とも故障した結果、データロストを経験した為、RockyLinuxへの移管とともに、RAIDも1→6にすることを思いついた。RAID6であれば2台同時故障にも耐え得るので安心感が大きいのだが、構築してみて大きなデメリットがあることに気がついた。
    mdadmは週1回程度のRAIDのベリファイが必要なのだが、その負荷がRAID1と6では比べ物にならないくらい高く、また時間がかかることがわかった。ラズパイという非力なCPU上では、RAIDのベリファイが発生するとコンソールの受付もままならないほど、遅くなる。これではベリファイや障害時リカバリーの間は、Webサービスの提供が困難になってしまう。

    それでは、ベリファイやリカバリーの負荷が少なく、RAID1よりも安全なものは何かというと、RAID10ということになる。24時間365日サービス提供の必要がある為、今回はRAID10を採用することとした。

    RAIDについてはわかっているようでわかっていないことがまだまだあるのだと今回勉強になった。

    参考ページ

    ZipコマンドをGitBashで使えるようにする方法

    PowerShellにて便利なWindows用のパッケージツール「Scoop」をインストールする。
    PS> Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')

    エラーが発生した場合は、下記にて実行ポリシーを許可する。
    PS> Set-ExecutionPolicy RemoteSigned -scope CurrentUser

    再度、試みる
    PS> Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')

    Zipコマンドのインストール。
    PS> scoop install zip

    GitBash(コマンドプロンプト)にてZipコマンドが使えるようになる!
    cmd> zip -r xxxxx.zip hogehoge -x '*.mp4'

    ちなみに、Zipコマンド以外にも様々なパッケージ、例えばFireFoxなどもインストール出来るようです。これは便利!

    scoop search firefox などでインストールしたいパッケージ検索可能とのこと。
    パッケージが見つからない場合は、scoop bucket add extras にてextrasバケットを追加すると、インストールできるパッケージが一気に増えるとのこと



    
    

    FreeNASで古いHDDをWipeする

    FreeNASで古いHDDを再利用する際、以前にRAID等で利用してたHDDを使用した場合、クイックWipeしてもReplace が成功しないことがある。

    この場合、HDDを接続したら、最初に下記のddコマンドで、パーティション情報を保持しているセクタをサクッと初期化することで、WipeやReplaceに失敗せず利用可能となる。

    sysctl kern.geom.debugflags=0x10
    
    dd if=/dev/zero of=/dev/ada1 bs=512 count=1
    ada1 の部分を、ターゲットのHDDに変更する。間違えると大変なのでタイプミスに要注意。

    Cybozu2ical(Cybozu Office10からスケジュール抽出)

    Cybozu Office からスケジュールデータをスクレイピングして、ical形式でレスポンスするスクリプトです。

    元は名古屋の社長様が作られたもので、その後、望遠鏡ドットコム様が修正したものを勝手にメンテしたものとなります。

    
    <?php
    /*
    機能説明: CybozuOffice10に対してスケジュールをスクレイピングし、ical形式に変換して返却するスクリプト
    利用方法: https://hoge/cybouz2ical.php?user=username&pass=password
    	usernameはCybozuOfficeの下記ページの「ログイン名」欄にて確認できます。
    	https://hoge/fuga/ag.cgi?page=PersonalUser
    改版履歴:
    2009/05/13
    	名古屋ではたらく社長ブログだもんで
    	サイボウズofffice8と同期するツール暫定版
    	http://ameblo.jp/sitescope/entry-10260113074.html
    2013/08/26
    	上記にて公開していただいているスクリプトをサイボウズ9用に勝手改変版
    	サイボウズ Office Version 9.3.1 20130703181739にて確認
    	望遠鏡ドットコム
    	サイボウズ9・サイボウズ10のスケジュールをiCal形式でGoogleカレンダーに同期(一方通行)
    	
    サイボウズ9・サイボウズ10のスケジュールをiCal形式でGoogleカレンダーに同期(一方通行)
    2020/09/18 上記で公開しているソースについて以下を改修しました ・ icalのUIDの重複を避ける(Googleカレンダーで同日の複数予定が1日1件しか取り込めないのを修正) ・ 基本認証設置しているCybozuOfficeに対応 ・ URLパラメタにUser/Passを含めるように修正(SSLを使用しないと平文で送られるので要注意) ・ その他微修正 */ $username = $_GET['user']; $password = $_GET['pass']; if(empty($username) || empty($password)){ die("parameter error!"); } //------------------------------------------------------------------------------------------------------------------- // 設定 //------------------------------------------------------------------------------------------------------------------- //define("CHAR_CODE", 'SJIS'); //サイボウズの文字コード サイボウズ9はSJIS define("CHAR_CODE", 'UTF-8'); //サイボウズの文字コード サイボウズ10はUTF-8 define("SCHEDULE_TITLE", 'Cybozu'); //スケジュールタイトル define("SCHEDULE_MEMO", TRUE); //スケジュールメモまで取得する場合は'TRUE' define('PRODID', 'Cybozu2iCal'); //http://ameblo.jp/sitescope/entry-10260113074.html define('CYBOZU_URL', 'https://hoge/fuga/ag.cgi'); //サイボウズのURL define("VERSION", 10); //CybozuOfficeバージョン(9,10のみ対応) define("SALU_ID", ''); //基本認証(ある場合だけセット) define("SALU_PW", ''); //基本認証(ある場合だけセット) //------------------------------------------------------------------------------------------------------------------- //POSTデータ組み立て $data = array( "_System" => "login", "_Login" => "1", "LoginMethod" => "2", "_Account" => $username, "Password" => $password ); $data = http_build_query($data, "", "&"); //headerにセット $header = array( "Content-Type: application/x-www-form-urlencoded", "Content-Length: ".strlen($data) ); //基本認証があるサイボウズの場合 if(!empty(SALU_ID)){ $header[] = "Authorization: Basic " . base64_encode(SALU_ID . ":" . SALU_PW); } $context = array( "http" => array( "method" => "POST", "header" => implode("\r\n", $header), "content" => $data ) ); //個人月間スケジュール $url = CYBOZU_URL . '?page=ScheduleUserMonth'; //サイボウズからHTMLデータ取得 $work = file_get_contents($url, false, stream_context_create($context)); //文字コードをUTF-8へ変換 $work = mb_convert_encoding($work, "UTF-8", CHAR_CODE); //正規表現がめんどくさいのでそのまま文字列比較で不要なとこをまず削除 $work = substr(strchr($work,'<table class="schedule usermonth" id="schedulemonth" width="100%" >'), 0); $work = substr($work, 0, strpos($work, '<table class="monthNavi" ')); $work = substr(strchr($work,'<tbody id="um__body">'), 0); $work = substr($work, 0, strpos($work, '</table>')); //文字列比較でとりあえず、スケジュールを配列に格納 $wdate1 = ""; $wdate2 = ""; $schedule_list = ""; $loop_flg = TRUE; while ( $loop_flg == TRUE ) { //日付の取得 $wdate = ""; $wdate = substr(strchr($work,'<span class="date">'), 19); $wdate = substr($wdate, 0, strpos($wdate, '</span>')); if ($wdate == "") { break; } //日付のフォーマットを変更 $date_sp = ""; $date_sp = split('/', $wdate); $schedule_date = Date('Y') . sprintf("%02d",$date_sp[0]) . sprintf("%02d",$date_sp[1]); //次の日も取得しとく $schedule_date_tommorow = ""; $schedule_date_tommorow = Date('Ymd', mktime(0, 0, 0, (int)$date_sp[0], (int)((int)$date_sp[1] + 1), (int)Date('Y') ) ); //日付部分をカット $work = substr(strchr($work,'<span class="date">'), 30); $loop_flg2 = TRUE; while ( $loop_flg2 == TRUE ) { if ( strpos($work, '<a class="event" href=') > strpos($work, '<span class="date">') ) { break; } else { //スケジュールIDを取得 if( VERSION == 9 ){ // サイボウズ9 $schedule_id = substr(strchr($work,'<div class="eventLink scheduleMarkTitle0" name="'), 53); $schedule_id = substr($schedule_id, 0, strpos($schedule_id, '">')); }else{ // サイボウズ10 $schedule_id = substr(strchr($work,'<div class="eventLink scheduleMarkTitle0 highlight-event'), 56); $schedule_id = substr($schedule_id, 0, strpos($schedule_id, '" ')); } if ( $schedule_id == "" ) { break; } //---------------------------------- if ( SCHEDULE_MEMO ) { //スケジュール内容まで取得 $wlink = substr(strchr($work,'<a class="event" href="ag.cgi?'), 30); $wlink = substr($wlink, 0, strpos($wlink, '" title="')); $url = CYBOZU_URL . '?' . $wlink; //サイボウズからHTMLデータ取得 $work2 = file_get_contents($url, false, stream_context_create($context)); //文字コードをUTF-8へ変換 $work2 = mb_convert_encoding($work2, "UTF-8", CHAR_CODE); //正規表現がめんどくさいのでそのまま文字列比較で不要なとこをまず削除 $work2 = substr(strchr($work2,'<table class="dataView scheduleDataView" width="100%" >'), 0); $work2 = substr($work2, 0, strpos($work2, '<span class="vr_scheduleUserCount">')); //スケジュールタイトルを取得 $work2 = str_replace("\n\r","", $work2); $work2 = str_replace("\n","", $work2); $work2 = str_replace("\r","", $work2); $schedule_description = substr(strchr($work2,'<div id="scheduleMemo"><tt>'), 27); $schedule_description = substr($schedule_description, 0, strpos($schedule_description, '</tt>')); $schedule_description = strip_tags($schedule_description); } //---------------------------------- //スケジュールタイトルを取得 $schedule_title = substr(strchr($work,'=sm" title="'), 12); $schedule_title = substr($schedule_title, 0, strpos($schedule_title, '">')); //時刻を取得 if (strpos($work, '<span class="eventDateTime">') < strpos($work, '=sm" title="')) { $schedule_time = substr(strchr($work, '<span class="eventDateTime">'), 28); $schedule_time = substr($schedule_time, 0, strpos($schedule_time, ' ')); } else { $schedule_time = ''; } //タイトル部分をカット $work = substr(strchr($work,'=sm" title="'), 12); //時間指定があるか判定 if ( !empty($schedule_time) ) { $time_sp = ""; $time_sp = split('-', $schedule_time); $from_sp = split(':', @$time_sp[0]); //http://www.sunvisor.net/node/383 if ( count($time_sp) > 1 ) { $to_sp = split(':', @$time_sp[1]); } else { $to_sp = $from_sp; } $from_sp[0] = sprintf('%02d', @$from_sp[0]); $to_sp[0] = sprintf('%02d', @$to_sp[0]); $from_hour = ""; $to_hour = ""; if ($from_sp[0]<10) { $from_hour = '0' . @$from_sp[0]; } else { $from_hour = $from_sp[0]; } if ($to_sp[0]<10) { $to_hour = '0' . $to_sp[0]; } else { $to_hour = $to_sp[0]; } if (count($to_sp)<2){ $to_hour = $from_hour + 1; $to_sp[1] = $from_sp[1]; } $schedule_summary = $schedule_title; //http://www.sunvisor.net/node/383 $schedule_from = ':' . $schedule_date . 'T' . @$from_sp[0] . @$from_sp[1]. '00'; $schedule_to = ':' . $schedule_date . 'T' . @$to_sp[0] . @$to_sp[1]. '00'; $schedule_description = $schedule_title . " " . $schedule_description; } else { $schedule_summary = $schedule_title; //http://www.sunvisor.net/node/383 $schedule_from = ';VALUE=DATE:' . $schedule_date; $schedule_to = ';VALUE=DATE:' . $schedule_date_tommorow; $schedule_description = $schedule_title . " " . $schedule_description; } //http://www.sunvisor.net/node/383 $schedule_list[] = Array('id' => $schedule_id.$schedule_date, 'description' => $schedule_description, 'dtstart' => $schedule_from, 'dtend' => $schedule_to, 'summary' => $schedule_summary); } } } //ここから出力 header('Content-Type: text/calendar; charset=utf-8'); echo 'BEGIN:VCALENDAR'. "\n"; echo 'PRODID:' . PRODID. "\n"; echo 'VERSION:2.0'. "\n"; echo 'METHOD:PUBLISH'. "\n"; echo 'CALSCALE:GREGORIAN'. "\n"; echo 'X-WR-CALNAME:' . SCHEDULE_TITLE . "\n"; echo 'X-WR-CALDESC:' . SCHEDULE_TITLE . "\n"; echo 'X-WR-TIMEZONE:Asia/Tokyo'. "\n"; if ( !empty($schedule_list) ) { foreach ( $schedule_list as $key => $vale ) { echo 'BEGIN:VEVENT'. "\n"; // UIDの重複を避ける(Googleカレンダーで同日の複数予定が1件しか取り込めないのを修正) // echo 'UID:' . SCHEDULE_TITLE . '-' . $vale['id'] . "\n"; echo 'UID:' . SCHEDULE_TITLE . '-' . $vale['id'] . md5($vale['description'].$vale['dtstart'].$vale['dtend']) . "\n"; echo 'DESCRIPTION:' . $vale['description']. "\n"; //http://www.sunvisor.net/node/383 echo 'DTSTART;TZID=Asia/Tokyo' . $vale['dtstart'] . "\n"; echo 'DTEND;TZID=Asia/Tokyo' . $vale['dtend'] . "\n"; echo 'SUMMARY:'. $vale['summary']. "\n"; echo 'END:VEVENT'. "\n"; } } echo 'BEGIN:VTIMEZONE'. "\n"; echo 'TZID:Asia/Tokyo'. "\n"; echo 'BEGIN:STANDARD'. "\n"; echo 'DTSTART:19700101T000000'. "\n"; echo 'TZOFFSETFROM:+0900'. "\n"; echo 'TZOFFSETTO:+0900'. "\n"; echo 'END:STANDARD'. "\n"; echo 'END:VTIMEZONE'. "\n"; echo 'END:VCALENDAR'. "\n"; ?>

    CoreOS で docker-compose を自動起動

    CoreOSはもうサポート切れとなり、Fedora系に引き継がれているが我が家ではLAN内で使用している為、まだまだ現役である。

    今回、サーバーをRebootしてもすぐに起動してくるよう、設定した際のメモを残す。

    自動起動ファイル作成

    $ sudo vi /etc/systemd/system/docker1.service
    [Unit]
      Description=My Service
      After=docker.service
      Requires=docker.service
    [Service]
      WorkingDirectory=/opt/app/laradock
      ExecStart=/opt/bin/docker-compose up -d
    [Install]
      WantedBy=multi-user.target
    $ sudo systemctl enable docker1
    $ ln -s '/etc/systemd/system/docker1.service' '/etc/systemd/system/multi-user.target.wants/docker1.service'

    一覧確認

    $ ls -l /etc/systemd/system/multi-user.target.wants/docker*

    最後に、Rebootして docker-compose ps で全てUPしていることを確認した。

    WindowsのVisualStudioCode で PHP CS Fixer 拡張を使用する

    WindowsのVisualStudioCode で PHP CS Fixer 拡張を使用する場合、
    php.exeが必要みたいです。

    このようなエラーに悩まされました。
    PHP CS Fixer: executablePath not found, please check your settings. It will set to built-in php-cs-fixer.phar. Try again!

    さて、下記が対処方法となります。
    ・ PHP CS Fixer 拡張をVisualStudioCode 上でインストール
    ・Windows版のPHPを下記よりダウンロードし
     https://windows.php.net/download/
     適当なパス 、例えば C:\php\ にZipの中身を設置します。
    ・さらに settings.json にパスを設定します。
     C:\Users\[ユーザ名]\AppData\Roaming\Code\User\settings.json に
        “php.validate.executablePath”: “C:\\php\\php.exe”,
     を追加します。
    これで動作するようになります。

    Pritunl VPN環境の構築手順

    コロナの影響でリモート接続が必要となり構築した際のメモ。
    既存のセグメントに透過的にアクセス可能とするのではなく、新しい仮想のVPNセグメントを生成して、そのセグメントに必要なクライアントを参加させる形となる。

    Pritunlサーバ構築

    AWS(準備)

    • EC2のOS: Amazon Linux 2
    • EC2インスタンスタイプ: t3.micro
    • ストレージ: 8GB
    • ElasticIP付与: 必須(以降、111.111.111.111)
    • ドメイン設定: 任意
    • インバウンドポート設定
      • TCP SSH、HTTP、HTTPS 保守作業する場所(自宅/会社)のIPのみ許可
      • UDP 18055 VPNクライアント用(*後ほどPritunlのWeb設定画面で表示される番号)

    AWS(EC2サーバ構築)

    • SSHにて、ec2-userでログイン
    • ここを参考にPritunlをインストール(以下)

    sudo tee /etc/yum.repos.d/mongodb-org-4.2.repo << EOF
    [mongodb-org-4.2]
    name=MongoDB Repository
    baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/4.2/x86_64/
    gpgcheck=1
    enabled=1
    gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc
    EOF

    sudo tee /etc/yum.repos.d/pritunl.repo << EOF
    [pritunl]
    name=Pritunl Repository
    baseurl=https://repo.pritunl.com/stable/yum/amazonlinux/2/
    gpgcheck=1
    enabled=1
    EOF

    sudo rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
    gpg –keyserver hkp://keyserver.ubuntu.com –recv-keys 7568D9BB55FF9E5287D586017AE645C0CF8E292A
    gpg –armor –export 7568D9BB55FF9E5287D586017AE645C0CF8E292A > key.tmp; sudo rpm –import key.tmp; rm -f key.tmp
    sudo yum -y install pritunl mongodb-org
    sudo systemctl start mongod pritunl
    sudo systemctl enable mongod pritunl

    • セットアップキーを作成

    sudo pritunl setup-key
    0602d77d26fe4b22a8330a8c13c00000 のようなキーが表示される

    • デフォルトパスワードを作成

    sudo pritunl default-password
    Administrator default password:
    username: “pritunl”
    password: “xxxxxxxxxxxxxx”

    Pritunl コントロール画面(初期設定)

    • ブラウザで、Pritunlセットアップ画面を開き、セットアップキーを入力する。
      https://111.111.111.111/setup
    • 先程生成した、ユーザ、初期パスワードを入力しログインする。
    • Settingsダイアログが表示されるのでNew Password、Lets Encrypt Domain(ドメイン取得時のみ)などを設定する。
    • オーガナイゼーション作成
      • 上部メニューの Users をクリック
      • Add Organization ボタンをクリック
        ※最低この単位で、VPNのネットワークセグメントを分けることも可能
    • ユーザ作成
      • Add User ボタンをクリック
      • 対象ユーザを全員分作成
      • Linuxのファイルサーバをクライアントにする場合、Pinやメールは設定しない
    アカウント(半角) メール PIN(整数6文字以上)
    user1 user1@hoge.jp 123456
    user2 user1@hoge.jp 123456
    user3 user3@hoge.jp 123456
    linuxFileServer なし なし
    • サーバ作成
      Name: vpnの名称
      UDP: 18055 (自動で設定される)
      セグメント: 192.168.217.0/24 (自動で設定される)
      ※VPNセグメントを複数構築したい場合(ネットワークを分離したい場合)は複数作成する。
    • オーガナイゼーションをサーバに紐付ける
      • Attach Organization ボタンをクリック
      • オーガナイゼーションとサーバを入力
    • サーバの起動
      • 左側の Start Server 緑ボタンをクリック
      • 右側の Status が Online となればOK
    • 各ユーザのプロファイルをダウンロード
      ダウンロードしたプロファイルと、先程設定したPinを、各ユーザに配布する。

      このファイルとPinがあれば誰でも接続できてしまう為、配布は可能な限り安全な方法で行うこと。またPinは口頭で伝えるなどすること。

    Windowsクライアントアプリの導入

    • ここより Pritunl.exe をダウンロードし、インストール
    • クライアント起動
    • 設定ファイルをImport(予め、Pritunlのユーザ一覧画面の右側のダウンロードボタンで、各ユーザの.tarファイルをダンロードしておく)
    • 右上のハンバーガーメニューより「Connect」
    • Pinをいれれば接続完了

    リモートデスクトップを使用する場合は、接続元・先の2台にクライアントアプリをインストールします。
    また、既存のファイルサーバにアクセスしたい場合は、ファイルサーバにクライアントをインストールします(次章を参照)

    LinuxサーバにOpenVPNクライアントを導入

    ファイルサーバ等、Linuxマシンにアクセスを行う必要がある場合などに必要となる。
    ここの記事のclient側についてのみ参考にさせていただきました。

    • openvpnクライアントをインストール

    yum install epel-release
    yum install –enablerepo=epel openvpn

    • client.confの修正

    cat /usr/share/doc/openvpn/sample/sample-config-files/client.conf > /etc/openvpn/client.conf
    vi /etc/openvpn/client.conf

    下記項目を変更します。
    remote 111.111.111.111 18055
    ca /etc/openvpn/ca
    cert /etc/openvpn/cert
    key /etc/openvpn/key
    tls-auth /etc/openvpn/ta 1

    • 上記の4つの証明書(ca,cert,key,ta)に対応したファイルを作成
      Pritunlのユーザ一覧画面からダウンロードしたプロファイル(tarファイル)をLhaForge等のアーカイバで展開し、展開された .ovpnファイルを、サクラエディタ等のテキストエディタで開いて切り出し、ファイル化します。

    <ca>~この部分をコピーして単独のファイル ca にする~</ca>

    <tls-auth>~この部分をコピーして単独のファイル ta にする~</tls-auth>

    <cert>~この部分をコピーして単独のファイル certに する~</cert>

    <key>~この部分をコピーして単独のファイル key にする~</key>

    ※Linuxであれば tar -xf user1.tar のようにアーカイブを展開し、展開後のovpnファイルを vi user1.ovpn 等としてファイル内のタグで囲まれたテキスト部分を切り出してファイル化します。少々面倒なのですが、もっと良い方法を知っている方がいれば教えてほしいです・・・

    • VPNクライアント接続テスト

    openvpn /etc/openvpn/client.conf

    接続ログが画面にずらずらと表示される。エラーなどがなければOK。
    ※以下のようなPinエラーになる場合は、当該ユーザ作成時にPinを設定している為、Pinの設定を削除してください。

    Mon Mar 30 02:03:30 2020 AUTH: Received control message:
    AUTH_FAILED,CRV1:R:f52cbb8978cc402da249d2e00000003:bmls:Enter Pin
    Mon Mar 30 02:03:30 2020 SIGTERM[soft,auth-failure] received, process exiting

    • VPNクライアント自動起動

    vi /opt/openvpn-client.sh

    #!/bin/bash  
    openvpn /etc/openvpn/client.conf  

    chmod 755 /opt/openvpn-client.sh
    vi /etc/systemd/system/openvpn-client.service

    [Unit]  
    Description = OpenVPN-Client daemon  
    [Service]  
    ExecStart = /opt/openvpn-client.sh  
    Restart = always  
    Type = simple  
    [Install]  
    WantedBy=multi-user.target  
    • 起動

    systemctl start openvpn-client
    ps aux | grep openvpn

    下記のようなプロセスがあれば問題ない
    root 862 0.0 0.1 23284 3420 ? Ss 3月31 0:00 /bin/bash /opt/openvpn-client.sh
    root 867 0.0 0.4 56504 7976 ? S 3月31 0:05 openvpn /etc/openvpn/client.conf

    • 自動起動

    systemctl enable openvpn-client

    • サーバを再起動後しばらくして、Pritunl ユーザ一覧画面で、当該サーバが接続状態となっていればOK

    ヒアドキュメント

    「ヒアドキュメント」という言葉がいつも出てこなくなるので、メモ。
    
    大体、いつもやりたくなるのは、下記のようにシェルで変数にぶち込みたくなるパタンが多い。
    HOGE=$(cat << EOS
    hoge
    fuga
    EOS
    )
    
    もしくは
    
    HOGE=`cat << EOS
    hoge
    fuga
    EOS
    `