NginxのSSLでブラウザでは問題ないのにPythonのrequestsでSSLErrorが出た

弊社のソフトウェアはpythonのrequestsでSSL通信を行っているが、今回証明書を更新するタイミングでssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failedが出て焦った。

これ原因は中間証明書にあります!

例えばアルファSSLだとG2の有効期限は2024-02-20で、G4は2027-10-12までで、私は2027年までのG4の証明書だけをPEMにして入れたらいいと思ってました。

これ違います!

実は中間証明書は階層構造になっていて、G2の証明書とG4の証明書の両方が必要になります!

https://info-globalsign.com/news/20221108

なので

NG:

—–BEGIN CERTIFICATE—–
Your CRT
—–END CERTIFICATE—–
—–BEGIN CERTIFICATE—–
MIIEijCCA3KgAwIBAgIQfU1CqStDHX5kU+fBmo1YdzANBgkqhkiG9w0BAQsFADBX
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE
CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIyMTAx
MjAzNDk0M1oXDTI3MTAxMjAwMDAwMFowTDELMAkGA1UEBhMCQkUxGTAXBgNVBAoT
EEdsb2JhbFNpZ24gbnYtc2ExIjAgBgNVBAMTGUFscGhhU1NMIENBIC0gU0hBMjU2
IC0gRzQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtJCmVZhWIPzOH
A3jP1QwkuDFT8/+DImyZlSt85UpZwq7G0Sqd+n8gLlHIZypQkad5VkT7OLU+MI78
lC7LVwxpU19ExlaWL67ANyWG8XHx3AJFQoZhuDbvUeNzRQyQs6XS5wN6uDlF0Bf1
AtCUQWrGGLGYwyC1xTrzgrFKpESsIXMqklUGTsh8i7DKZhRUVfgrPLJUkbbLUrLY
42+KRCiwfSvBloC5PgDYnj3oMZ1aTe3Wfk3l1I4D3RKaJ4PU1qHXhHJOge2bjGIG
l6MsaBN+BB2sr6EnxX0xnMIbew2oIfOFoLqs47vh/GH4JN0qql2WBHfDPVDm3b+G
QxY6N/LXAgMBAAGjggFbMIIBVzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYI
KwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE
FE/LrKjC76vdg29rv86YPVxYJXYVMB8GA1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTN
NKj//P1LMHoGCCsGAQUFBwEBBG4wbDAtBggrBgEFBQcwAYYhaHR0cDovL29jc3Au
Z2xvYmFsc2lnbi5jb20vcm9vdHIxMDsGCCsGAQUFBzAChi9odHRwOi8vc2VjdXJl
Lmdsb2JhbHNpZ24uY29tL2NhY2VydC9yb290LXIxLmNydDAzBgNVHR8ELDAqMCig
JqAkhiJodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jvb3QuY3JsMCEGA1UdIAQa
MBgwCAYGZ4EMAQIBMAwGCisGAQQBoDIKAQMwDQYJKoZIhvcNAQELBQADggEBABol
9nNkiECpWQenQ7oVP1FhvRX/LWTdzXpdMmp/SELnEJhoOe+366E0dt8tWGg+ezAc
DPeGYPmp83nAVLeDpji7Nqu8ldB8+G/B6U9GB8i2DDIAqSsFEvcMbWb5gZ2/DmRN
cifGi9FKAuFu2wyft4s4DHwzL2CJ2zjMlUOM3RaE1cxuOs+Om6MCD9G7vnkAtSiC
/OOfHO902f4yI2a48K+gKaAf3lISFXjd32pwQ21LpM3ueIGydaJ+1/z8nv+C7SUT
5bHoz7cYU27LUvh1n2WSNnC6/QwFSoP6gNKa4POO/oO13xjhrLRHJ/04cKMbRALt
JWQkPacJ8SJVhB2R7BI=
—–END CERTIFICATE—–

OK:

—–BEGIN CERTIFICATE—–
Your CRT
—–END CERTIFICATE—–
—–BEGIN CERTIFICATE—–
MIIGVDCCBTygAwIBAgIMCJEO0BA+aoDxjYPKMA0GCSqGSIb3DQEBCwUAMEwxCzAJ
BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSIwIAYDVQQDExlB
bHBoYVNTTCBDQSAtIFNIQTI1NiAtIEc0MB4XDTIzMDIxMjEyNTAxN1oXDTI0MDMx
NTEyNTAxNlowHTEbMBkGA1UEAwwSKi5tZWRpY2FsZmllbGRzLmpwMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm48J3rSAZWccx0w+43wR6LaAG6CiECmf
fGBlqNbzojoDlNM+aEIiNvYKspkxQhu1C+pZJ1wfHHqR7Zir+km7I9e+tXuP8pGA
T7gkxFGgPCB3xEQZ51kp105idV7mVdIwS7FGgHeetboCZDty+KqXc3SzUCdXKAyO
YCQQN9i0UI6PZ2zvBm5QMWDTzFQyYPld04ACABPEH7k6uK5arXkt7rZKOjHhDc8Q
bhf6XkGwX5qdG8Db9/MkqsgZ1PdkvOKkFR1vv/5QOslMGopatq1E15hqCGfB+541
Cgcua6oG/AdL9nMPTXkw0+cNKewYKXSATr5E21+ZaIFDpAJpSAecSwIDAQABo4ID
YzCCA18wDgYDVR0PAQH/BAQDAgWgMIGTBggrBgEFBQcBAQSBhjCBgzBGBggrBgEF
BQcwAoY6aHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQvYWxwaGFz
c2xjYXNoYTI1Nmc0LmNydDA5BggrBgEFBQcwAYYtaHR0cDovL29jc3AuZ2xvYmFs
c2lnbi5jb20vYWxwaGFzc2xjYXNoYTI1Nmc0MFcGA1UdIARQME4wCAYGZ4EMAQIB
MEIGCisGAQQBoDIKAQMwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFs
c2lnbi5jb20vcmVwb3NpdG9yeS8wCQYDVR0TBAIwADBBBgNVHR8EOjA4MDagNKAy
hjBodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL2FscGhhc3NsY2FzaGEyNTZnNC5j
cmwwLwYDVR0RBCgwJoISKi5tZWRpY2FsZmllbGRzLmpwghBtZWRpY2FsZmllbGRz
LmpwMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAfBgNVHSMEGDAWgBRP
y6yowu+r3YNva7/OmD1cWCV2FTAdBgNVHQ4EFgQUAXsU+ABU/dt1i/xKq0JNwrQs
ghswggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2AEiw42vapkc0D+VqAvqdMOsc
UgHLVt0sgdm7v6s52IRzAAABhkWtNUQAAAQDAEcwRQIhAPgamklBv6V/FsBj0x3J
JwP88Kg/d+grzVMlEIgs+o7TAiA+PoRMp+m6L9lWicyBtHHgcUn8mvKcrxVRJF4f
rJt6jwB1AO7N0GTV2xrOxVy3nbTNE6Iyh0Z8vOzew1FIWUZxH7WbAAABhkWtNhsA
AAQDAEYwRAIgbk9SKl405qzjKBxrojOfA5BaaiQTUDMGAXnM5wqAzYcCIBciIXnd
GfCET5allakjTSz8RSdFjQI0W7+/1iRk5LLvAHcA2ra/az+1tiKfm8K7XGvocJFx
bLtRhIU0vaQ9MEjX+6sAAAGGRa0zmAAABAMASDBGAiEA4ekNPp+uSlKHIYxs2XR/
w09GCv04P55jRHQQSORpps4CIQC7qG0qhsPhnLK+t6hJEvXZi7AJ2NYPxtc5nGWZ
JOBKWTANBgkqhkiG9w0BAQsFAAOCAQEAMzxtntb/K0oJWUf6j0NsIMK6oIIKsUou
HRTesA0jjFYGWDAXXom6pNBkQK5I/EkU/TNdhvLRSwJD4u1BAuqpp/p2uvQQdzOI
Cvf1sA9yNRomHvay0hkLw3XU6Va4mPHWfvKkFXtrl+0I1MDZBBYbYD03IpBV8XrY
2YiSOMIbKZXLIZUHz0Pt7jitj4nvrO0ijWogoU1aHjEK0qWKlFgg73nZtB0gTOQk
JyLYlJe+xswXl1LJaPXKH29yo2DaUI1BA7zVD0Hxw8vzer7siImWQ3FgVE5yrYRp
+fN5yMgOAPYqXWvcS6ndLGe9kaGSpLpfo6sNlAnR786ZV84/tAQCeQ==
—–END CERTIFICATE—–
—–BEGIN CERTIFICATE—–
MIIEijCCA3KgAwIBAgIQfU1CqStDHX5kU+fBmo1YdzANBgkqhkiG9w0BAQsFADBX
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE
CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIyMTAx
MjAzNDk0M1oXDTI3MTAxMjAwMDAwMFowTDELMAkGA1UEBhMCQkUxGTAXBgNVBAoT
EEdsb2JhbFNpZ24gbnYtc2ExIjAgBgNVBAMTGUFscGhhU1NMIENBIC0gU0hBMjU2
IC0gRzQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtJCmVZhWIPzOH
A3jP1QwkuDFT8/+DImyZlSt85UpZwq7G0Sqd+n8gLlHIZypQkad5VkT7OLU+MI78
lC7LVwxpU19ExlaWL67ANyWG8XHx3AJFQoZhuDbvUeNzRQyQs6XS5wN6uDlF0Bf1
AtCUQWrGGLGYwyC1xTrzgrFKpESsIXMqklUGTsh8i7DKZhRUVfgrPLJUkbbLUrLY
42+KRCiwfSvBloC5PgDYnj3oMZ1aTe3Wfk3l1I4D3RKaJ4PU1qHXhHJOge2bjGIG
l6MsaBN+BB2sr6EnxX0xnMIbew2oIfOFoLqs47vh/GH4JN0qql2WBHfDPVDm3b+G
QxY6N/LXAgMBAAGjggFbMIIBVzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYI
KwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE
FE/LrKjC76vdg29rv86YPVxYJXYVMB8GA1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTN
NKj//P1LMHoGCCsGAQUFBwEBBG4wbDAtBggrBgEFBQcwAYYhaHR0cDovL29jc3Au
Z2xvYmFsc2lnbi5jb20vcm9vdHIxMDsGCCsGAQUFBzAChi9odHRwOi8vc2VjdXJl
Lmdsb2JhbHNpZ24uY29tL2NhY2VydC9yb290LXIxLmNydDAzBgNVHR8ELDAqMCig
JqAkhiJodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jvb3QuY3JsMCEGA1UdIAQa
MBgwCAYGZ4EMAQIBMAwGCisGAQQBoDIKAQMwDQYJKoZIhvcNAQELBQADggEBABol
9nNkiECpWQenQ7oVP1FhvRX/LWTdzXpdMmp/SELnEJhoOe+366E0dt8tWGg+ezAc
DPeGYPmp83nAVLeDpji7Nqu8ldB8+G/B6U9GB8i2DDIAqSsFEvcMbWb5gZ2/DmRN
cifGi9FKAuFu2wyft4s4DHwzL2CJ2zjMlUOM3RaE1cxuOs+Om6MCD9G7vnkAtSiC
/OOfHO902f4yI2a48K+gKaAf3lISFXjd32pwQ21LpM3ueIGydaJ+1/z8nv+C7SUT
5bHoz7cYU27LUvh1n2WSNnC6/QwFSoP6gNKa4POO/oO13xjhrLRHJ/04cKMbRALt
JWQkPacJ8SJVhB2R7BI=
—–END CERTIFICATE—–

としましょう

Material ColorのIllustratorのSwatchesのダウンロード

マテリアルデザインのカラーのスウォッチがGoogle公式サイトからダウンロードできなくなっています。

公式サイト→https://material.io/design/resources/color-palettes.html

こちらからダウンロードできます。

ダウンロード

【 https://medicalfields.jp/uploads/color-swatches.zip 】

どうぞ使ってください。

CentOS Stream 8にアップグレードしたらnginxのstatusがactive(running)なのに何も表示されない

タイトルそのままです。

めちゃんこ悩んだ

なんと、アップデートしたら勝手にNginxの設定ファイルがリネームされてた。

自分のケースでは

/etc/nginx/conf.d/default.conf

/etc/nginx/conf.d/default.conf.rpmsave

にリネームされてた。

設定ファイルがないなら動かないよね。

あと、Nginxのtmpフォルダ(fastcgi)の位置が変わってた

古いのは

/var/cache/nginx

新しいのは

/var/lib/nginx/tmp

なので

/var/lib/nginx/ にパーミッション許可を与えましょう

そうしないと

open() “/var/lib/nginx/tmp/fastcgi/x/xx/0000000007” failed (13: Permission denied) while reading upstream, client: xxx.xxx.xxx.xxx, server: _, request: “POST /xxx.php HTTP/1.1”, upstream: “fastcgi://unix:/var/run/php-fpm/php-fpm.sock:”, host:xxx

と出て、メモリに入り切らない処理が出たときにTMPに書き込みできずエラーになります。

さらに、index.htmlが上書きされてました。

修正しましょう。

 

For English User.

After upgrading to CentOS Stream 8, the status of nginx is active(running), but nothing is displayed.

Solution!

After updating, the Nginx configuration file was renamed.

In my case

Original

/etc/nginx/conf.d/default.conf

Renamed

/etc/nginx/conf.d/default.conf.rpmsave

Just Rename to original Filename….

 

Android Q (API:29)以上でgetExternalStorageDirectoryに保存ができない

Googleさんのポリシーの変更によりファイルの書き込みや読み込みの権限が厳しくなった

一応暫定処理でAndroidManifest.xmlに

android:requestLegacyExternalStorage="true"

を追加することで使うことはできたのだが、とうとうAndroid API 30以上では完全に書き込みが出来なくなってしまった。

もしAndroid API 30以上で今までのコードのままで使う場合はAndroidManifest.xmlに

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

を追加し、全てのファイルのアクセス権限をもらえば、getExternalStorageDirectoryに書き込める。でもこれだとGoogle Playにアップロードする場合MANAGE_EXTERNAL_STORAGEの権限は基本的にもらえないのでAPKの更新が出来なくってしまう(申請したが弾かれた)

非常に困った。

とりあえず今のところ、MediaStore経由で保存するしかなさそう

ということでJavaコードで対応させてみた

@RequiresApi(Build.VERSION_CODES.Q)
private String saveFileUsingMediaStore(Context context , String url , String fileName, String mimeType) {
    //https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
    ContentValues contentValues = new ContentValues();
    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
    contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
    contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);

    ContentResolver resolver = context.getContentResolver();
    Uri uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
    if (uri != null) {
        InputStream is = null;
        OutputStream os = null;
        try {
            is = new FileInputStream(url);
            os = resolver.openOutputStream(uri);
            inputCopy(is, os);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    // ignore
                }
            }
            if(os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    // ignore
                }
            }
            new File(url).delete();//delete original file
        }
        return getPathURI(context,uri);
    }
    return null;
}
public static String getPathURI(Context context, Uri uri) {
    ContentResolver contentResolver = context.getContentResolver();
    String[] columns = { MediaStore.Downloads.DATA };
    Cursor cursor = contentResolver.query(uri, columns, null, null, null);
    cursor.moveToFirst();
    String path = cursor.getString(0);
    cursor.close();
    return path;
}
void inputCopy(InputStream source, OutputStream target) throws IOException {
    byte[] buf = new byte[8192];
    int length;
    while ((length = source.read(buf)) > 0) {
        target.write(buf, 0, length);
    }
}

WindowsHello対応の指紋認証付きキーボードの購入

ノートパソコンでの指紋認証が早く、便利すぎてデスクトップでも導入しようとした。
(Windows Helloの指紋認証は使い勝手がとても良い)

一番いいと思ったのが今使っているノートパソコンと同じ、キーボードと一体型で指紋認証センサーが搭載されていてるものだ。

※イメージ

ただ、調べてみたら驚くほどラインナップが少なくとても高価だった。(英字配列を含めても数えるほど)

※プリファード・プロとかは日本語JIS配列かつ指紋認証センサーがついてはいるが、生産中止で、古いスライド式の為認識も良くないと思われるからやめた

※Microsoft Modern Keyboard (指紋認証センサー付き)はUS配列だからやめた
(むかしUS配列を使ったことがあるが、JIS配列に慣れすぎて、非常に使い辛かった)

 

そこで快適さ、価格、デザインを考え編み出した解決案がこちら

 

これすごく良い!

Amazonのリンク

・エレコム キーボード 有線 プレミアムメンブレン フルキーボード 1000万回高耐久 メカニカルライク USB2ポート付 ブラック TK-FCM094HBK

・アルカナイト(ARCANITE) USB指紋認証リーダー Windows Hello機能対応 0.05秒 指紋認証でセキュリティ対策 1年保証 AKFSD-07 

認識も抜群でしかももう1ポートUSBも使えちゃう!しかもお値段も安い!

なのでぜひオススメのやり方です。

Androidでjava.lang.NoClassDefFoundError: Failed resolution of: Landroid/icu/text/Transliterator;

半角全角の文字の切り替えをAndroidでしたいと思って

https://qiita.com/makimaki913/items/df745b85b802099a6e32

を見ながらICU4Jを使おうとした。

Transliterator fullToHalf = Transliterator.getInstance(“Fullwidth-Halfwidth”);
Transliterator halftoFull = Transliterator.getInstance(“Halfwidth-Fullwidth”);

でもどうもAndroidで公式にICU4JをサポートしているのはAndorid7からのようでAndroid5.0で動かしたい場合はGradleに

implementation 'com.ibm.icu:icu4j:53.1'

※参考

https://developer.android.com/guide/topics/resources/internationalization

のように記述する必要がある。

これでAndroid5.0で動くぞーと思ったら、なぜか動かない

 

FATAL EXCEPTION: main
java.lang.NoClassDefFoundError: Failed resolution of: Landroid/icu/text/Transliterator;

とでる。

原因は公式のサジェストでライブラリをインポートしたことでした。


import android.icu.text.Transliterator;

から

import com.ibm.icu.text.Transliterator;

にしましょう

PHPでGS1からJANを作成

なかったので作りました。

 自己責任でお使いください

class gs1 {
    function gs1tojan($gs1) {
        //すべて半角数字または()であるかをチェック
        if (preg_match("/^[0-9()]+$/", $gs1))
            //最初の桁のインジケーターを判断
            if(mb_strlen($gs1)==18){
                if (strpos($gs1, '(010)') === 0|strpos($gs1, '(01)0') === 0) {
                    $janNoCheckDigit=mb_substr($gs1, 5, 12);
                    return $janNoCheckDigit.gs1::calcJanCodeDigit($janNoCheckDigit);
                }
            }else if(mb_strlen($gs1)==17){
                if (strpos($gs1, '(01)') === 0) {
                    $janNoCheckDigit=mb_substr($gs1, 4, 12);
                    return $janNoCheckDigit.gs1::calcJanCodeDigit($janNoCheckDigit);
                }
            }else if(mb_strlen($gs1)==16){
                if (strpos($gs1, '010') === 0) {
                    $janNoCheckDigit=mb_substr($gs1, 3, 12);
                    return $janNoCheckDigit.gs1::calcJanCodeDigit($janNoCheckDigit);
                }
            }else if(mb_strlen($gs1)==15){
                if (strpos($gs1, '01') === 0) {
                    $janNoCheckDigit=mb_substr($gs1, 2, 12);
                    return $janNoCheckDigit.gs1::calcJanCodeDigit($janNoCheckDigit);
                }
            }else if(mb_strlen($gs1)==14){
                if (strpos($gs1, '1') === 0) {
                    $janNoCheckDigit=mb_substr($gs1, 1, 12);
                    return $janNoCheckDigit.gs1::calcJanCodeDigit($janNoCheckDigit);
                }
            }
        }
        return false;
    }
    function calcJanCodeDigit($num) {
        $arr = str_split($num);
        $odd = 0;
        $mod = 0;
        for($i=0;$i<count($arr);$i++){
            if(($i+1) % 2 == 0) {
                //偶数の総和
                $mod += intval($arr[$i]);
            } else {
                //奇数の総和
                $odd += intval($arr[$i]);
            }
        }
        //偶数の和を3倍+奇数の総和を加算して、下1桁の数字を10から引く
        $cd = 10 - intval(substr((string)($mod * 3) + $odd,-1));
        //10なら1の位は0なので、0を返す。
        return $cd === 10 ? 0 : $cd;
    }   
}

26歳でITベンチャーを立ち上げて

早いものでもうすぐ起業して6年がたつ。

小学生だと卒業しちゃう年だ。こわいね。

 

恥ずかしながらお話を聞きたいとのご要望があったので、ちょっと自分語りをしようと思います!

 

 

ベンチャーを立ち上げた経緯について

 

これは結構、理由はシンプルです。

・自分が薬局で働いてた時に本当に調剤過誤が多くて、それを解決したかったこと

・当時からプログラミングがとても得意(もともと携帯アプリなんか色々と作っていた)で、自分でも調剤過誤が防げるソフトが作れるはずと思ったこと

・当時でも薬局向けの調剤過誤防止機器はあったけど、値段が高すぎてとても気軽に導入できないから、もっと気軽に導入できる値段で、使いやすいのが作りたいって思ったこと

これが監査システムを作り始めたのがきっかけです。

 

でも当時、なにも起業のこととか分からなかった。でもネット検索していろいろ調べて自分で株式会社作りました。(会社設立ひとりでできるもんっていうサービスを使った)

 

※いきなり株式会社にしたのは、NSIPSという薬局のレセコン(処方箋入力用のパソコン)から、処方データと連携するためには、法人じゃないとだめって事で、いきなり法人になりました。ふつうは個人事業主→法人の流れがいいと思います。(消費税の特例とか、会社の維持費とかから)

 

でも立ち上げてからまぁ大変でした。

忘れないうちに起業の軌跡を残したいと思います!

 

立ち上げて1年目ぐらい

普通に薬剤師として週2~3でバイトしてました。(正社員→バイトに)

バイトしてアプリ作って、バイトしてアプリ作ってを繰り返してた。でもいっぱいシフトはいって欲しいといわれて、ちょっと忙しいんで~って言っても、忙しくないでしょみたいな風に思われてる(ホント)から、なんか「ミスばっかするし、なんかあんまり働いてくれなし」みたいな感じで現場の評価は低かった。

ただ、社長に近い役員の方々とは割と仲良くて、やめるとき割と悲しそうな感じだった。よく現場と管理は考え方違うっていうけど、本当にそう思う。

 

他に、依頼を受けてソフト作成するとかは結構してた。技術があるなら割と時間かからずに作成できて、結構おいしい仕事もあったりした。

ただ、知り合いの社長から、業務ソフトウェア作ってほしいって言われて作って納品したのに、結局お金払ってくれなかった事があった。(正確に言うと、作ったソフトを発注元の社長が販売して、ソフトが売れたらその売り上げの一部を支払うみたいな感じだけど、完成してから俺は売らないとか言われた。別に不具合とかバグはなく。仕様以上のクオリティで作ったつもり)3か月無駄になってかなり辛かった。

 

結局、請負契約はリスクあるからやらない方がいいと思います。

基本的に監査システムの開発が中心でした。

 

立ち上げて2年目ぐらい

監査システムのオフライン版(薬局内にサーバー設置型)がとりあえず、動くようになったので販売開始。

でも当時はこれ不具合があるし品質的に良くないって思ってたから積極的に販売はしなかった。(一応WEBページから購入できるようにはしてた)

いろんな人に意見聞きたくてベンチャー起業家向けのセミナーとかいってみた。

なんか怪しい人に俺が売ってやるから専売させろみたいなことを言われたけど(なんか人脈自慢すごくて今思えばマルチとかの関係者だと思う)あんまり信用できないなーって思ったから断ったらブチ切れられて怖かった。(この俺が売るって言ったのに断るなど、お前は間違えなく失敗するとかいわれた)

商品自体は完成していたので割と変な人が寄ってきて、起業セミナーってなんか自己評価高い人おおくて、意識低い系のわたくしにとっては、居心地よくなかった。

まぁでも自信をもっておススメできるぐらいに品質を改善しようとしていた。

品質改善って労力の割に地味でモチベーションを保つのに結構大変で、てか俺ってニートじゃね?みたいに思ってた。

 

立ち上げて3年目ぐらい

実は監査システムの開発と販売を積極的にやってなかったです。

というのも、あるきっかけから今の社員と一緒に投資ソフトを開発して、それが大当たりした。1日チャートに張り付いたり、いろいろストラテジー考えたり結構楽しかった。

その儲かった資金を使って不動産投資したり、薬局経営したりしたいと考えたりもした。(結局やらなかったけど)

フロー収入じゃなくてストック収入が大事だなとかお金について結構勉強したり、節税について必死で調べた。とんでもなく税金かかったから。

投資だけで暮らせるなぁ~と悠長な事を考えていた(フラグ)。

正直、もっと監査システムの開発やっとけばよかった。

 

立ち上げて4年目ぐらい

投資ソフトの成績が超微妙になって、なんかあんまりうまいこと行かなくなったので、オフライン版の監査システムの問題点を考えて、売れるようにしようと真剣に考えた。

当時の問題点

・導入に薬局でのサーバー設置・初期機器が必要

→導入コストが上がって、工事などが大変で管理も必要

・UIが分かり辛い

→ヘルプやマニュアルが充実しておらず、口頭での説明がないと使いにくい

・誰も知らない

→広告宣伝していないから当然誰も知らない。知らないと導入の比較にすら上がらない。

 

と問題が山積みだったので、とりあえず最優先して導入コスト削減に取り組んだ。

多分一番気にするところだから。

結果的にアプリだけで完結する、(サーバー設置が必要ない)クラウドでやることに決めた。

 

投資ソフトの改良は続けてたけど、結局成績が微妙すぎて最終的にはやめた。多分みんな考える複利の計算は計算通りいかないです。

 

立ち上げて5年目ぐらい

クラウド版がとりあえず動くようになったのでクラウド版の販売開始。

色々な販売方法はあるけど、やっぱり今の時代ネットかなと思ってそれに合うように色々と調べた。

販売用のランディングページを作りなおしたりしたけど、最初は全然アクセスもないし、本当にWEBから売れるのかなって感じだった。

(今まで売れてたオフライン版は全部知人とかの紹介だった)

色々と調べてるうちに、SEOについて知った。

SEO対策は本当に大事です! (ホームページの検索順位を上げる対策)

これで調剤過誤の対策を行いたい人が 検索して調べることで弊社のページを見つけることが出来るようになった。※さらにうれしいのが弊社のシステムを選んでくれた薬局さんは比較検討したうえで選んで頂けることが多く、しっかりされた薬局さんばっかりだった。

 

この対策を行うことで徐々にランディングページに訪問してくれるユーザーが増えてきてくれて、アプリもインストールしてくれて、そして初めて契約してくれた時はかなりうれしかった。あと、いける!って思った。

導入の流れができたので、あとは実際に使ってるユーザーさんに意見を聞いて、問題点を直していくっていう事を続けていった。これは今も心掛けていることです。

 

立ち上げて6年目ぐらい(今)

アプリの改善をずっと続けています。初期のころよりかなり改善されたと思う。

お陰様で、導入店舗もかなり増えて、とりあえず会社としてちゃんと経営できるぐらいにはなりました。

あとフロー収入とストック収入だとストック収入が大半になったので精神的安定が全然違う。正直、下請け的な感じで請負の仕事だけだと安定しないし、発注元がダメになったら当然発注先もダメになるのでお勧めしないです。

 

これから起業するかたへ

 

最初はみんな分からないので、調べながらで全然大丈夫です。

あと若いうちにやったほうがいいと思います。失敗いっぱいするけど割と若いからで許してくれたりします。

ただ、だまされないように気を付けましょう。特に起業したては悪い人かの区別もわからないです。セミナーもマルチとか自称大物起業家みたいな変な人が多かったです。いかなくていいです。

 

また、とにかく出ていくコストは最小限にしたほうがいいです。(最初の2~3年は基本赤字です。ある程度は収入がなくても暮らしていける資金は用意すべき)

固定費も最小限のままで、人員も今は最低限の人員だけど、今後も最小限の人員でやっていくつもりです。

 

最後に

起業してとてもよかったです。

自由です。あと自分で作った製品が認めてもらえたら嬉しいです。(小並感)

起業したい方はリスクを取りすぎず起業するのをお勧めします!

 

 

メモリとCPUに余裕があるのにnginxで503エラーが出て、php-fpmが止まった

特に前兆はなく(実はあったんだけど)サーバーが死んだ。

最近はアクティブユーザーが増えてくれて、POSTで1日200万リクエスト(転送量20GB)をこえたりしてたんだけど、突然503エラーで完全に応答しなくなった。(アプリでは通信エラーと出る)

構成としてConohaの メモリ 4GB/CPU 4Core×2台

これをロードバランサーでつないでいる。

 

まぁhtopでロードアベレージも両サーバー0.6とかで、これだったら余裕だろ~って眺めてたら死んだ。

てか実際に落ちたときにhtopで確認したけどロードアベレージが1を超えてなかった。

なんで??という思いが強かったけど、TCPコネクション使い切ったとおもって、とりあえずサーバーリブートで問題なく治った。

これはメモリリークの可能性があるなと思って(サーバー自体は半年以上再起動とかしてない)

とりあえず、様子見したら一日問題なく動いた。

 

実は設定悪い可能性があります!

 

nginx_error.log

connect() to unix:/var/run/php-fpm/php-fpm.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client:

 

php-fpm-error.log

[21-Jan-2021 10:50:43] WARNING: [pool www] server reached pm.max_children setting (100), consider raising it
[21-Jan-2021 11:01:23] NOTICE: Terminating …
[21-Jan-2021 11:01:23] NOTICE: exiting, bye-bye!
[21-Jan-2021 11:01:43] NOTICE: fpm is running, pid 1009
[21-Jan-2021 11:01:43] NOTICE: ready to handle connections
[21-Jan-2021 11:01:43] NOTICE: systemd monitor interval set to 10000ms
[21-Jan-2021 11:01:52] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 0 idle, and 17 total children
[21-Jan-2021 11:01:53] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 16 children, there are 0 idle, and 25 total children
[21-Jan-2021 11:01:54] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 35 total children
[21-Jan-2021 11:01:55] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 45 total children
[21-Jan-2021 11:01:56] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 55 total children
[21-Jan-2021 11:01:57] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 65 total children
[21-Jan-2021 11:01:58] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 9 idle, and 75 total children
[21-Jan-2021 11:01:59] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 9 idle, and 76 total children
[21-Jan-2021 11:02:21] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 8 idle, and 84 total children
[21-Jan-2021 11:02:22] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 16 children, there are 9 idle, and 86 total children
[21-Jan-2021 11:02:45] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 8 idle, and 98 total children
[21-Jan-2021 11:02:49] WARNING: [pool www] server reached pm.max_children setting (100), consider raising it

 

まずworker_processes を確認!

worker_processes auto;←これが良い

これがworker_processes  1(!?)になってた

CPUコア4なのに、これじゃあ1個しか使わない

あとコネクションの上限も念の為あげとく
worker_rlimit_nofile 16384;

events {
worker_connections 4096;
}

※worker_rlimit_nofileは設定しないと1024とかに制限されちゃうから必要

 

前提としてdynamicで

あと、php-fpmが平均してどれぐらいメモリ使うかによってpm.max_children

の設定も変えましょう

pm.max_children = 200

にした

ps -ylC php-fpm –sort:rss

で調べれる

RSSがメモリ使用率でKBで表示されます(24116だったら24116KB)

だいたい雰囲気の平均をとって、20MBぐらいだな~とおもって

メモリ4GBだったら

4000MB/20MBの200

この200をpm.max_childrenにした(本当はもっと安全をとって低いほうがいいかも)

参考→https://myshell.co.uk/blog/2012/07/adjusting-child-processes-for-php-fpm-nginx/

 

あとpm.max_requestsが自分的にはちょっと大事!

今まではpm.max_requestsはデフォルトの0にしていた

でも多分メモリリークの可能性があって、メモリ使い切って不安定になった可能性がある。このpm.max_requestsっていうのはmax_requestsの回数に達したらプロセスを再起動する設定になるからメモリリークがあっても解消できる。

つまりこれが実は大事だったかも。

ただ現在、1日200万PVなので1日ぐらいで再起動させたい場合、

1日のリクエスト(PV)数 ÷ pm.max_spare_serversになるので

だいたい50000ぐらい?

なんか凄く大きな値になった。

まぁ0よりはいいでしょう

 

とりあえずこれで様子をみる。

 

追記:念のためメモリも8GBにした。

でもこれ多分2台でやる、 8GB×8GBより4GB×4GB×4GBとかのほうが良い気もする。