顯示具有 linux 標籤的文章。 顯示所有文章
顯示具有 linux 標籤的文章。 顯示所有文章

2020年12月15日 星期二

同時跑兩個PHP版本(5.6+7.3)的laradock

 參考資料

實作

拉兩個目錄的laradock,到時候跑同一個目錄的 info.php ( php_info(); ),相同的 nginx/sites/ 配置
/var/www/html/laradock/ - 跑PHP 7.3
/var/www/html/laradock5/ - 跑PHP 5.6

/var/www/html/laradock5/.env

使用不同的project name,最後會build出的容器名字會是:laradock5_docker-in-docker_1、laradock5_nginx_1、laradock5_php-fpm_1、laradock5_workspace_1
#   COMPOSE_PROJECT_NAME=laradock
COMPOSE_PROJECT_NAME=laradock5

使用PHP 5.6
#   PHP_VERSION=7.3
PHP_VERSION=5.6

如果你的網路不好,一直裝不成node,可以這樣跳過安裝node
#   WORKSPACE_INSTALL_NODE=true
WORKSPACE_INSTALL_NODE=false

如果你的網路不好,一直裝不成yarn,可以這樣跳過安裝yarn
#   WORKSPACE_INSTALL_YARN=true
WORKSPACE_INSTALL_YARN=false

避免端口和 /var/www/html/laradock/ (PHP 7.3 )的容器衝突
#   WORKSPACE_SSH_PORT=2222
WORKSPACE_SSH_PORT=2226
...
#   WORKSPACE_BROWSERSYNC_HOST_PORT=3000
WORKSPACE_BROWSERSYNC_HOST_PORT=3004
#   WORKSPACE_BROWSERSYNC_UI_HOST_PORT=3001
WORKSPACE_BROWSERSYNC_UI_HOST_PORT=3005
#   WORKSPACE_VUE_CLI_SERVE_HOST_PORT=8080
WORKSPACE_VUE_CLI_SERVE_HOST_PORT=8084
#   WORKSPACE_VUE_CLI_UI_HOST_PORT=8001
WORKSPACE_VUE_CLI_UI_HOST_PORT=8005

使用5567端口訪問PHP 5.6容器(PHP 7.3 端口5566)
#   NGINX_HOST_HTTP_PORT=80
NGINX_HOST_HTTP_PORT=5567
#   NGINX_HOST_HTTPS_PORT=443
NGINX_HOST_HTTPS_PORT=444

#   VARNISH_BACKEND_PORT=81
VARNISH_BACKEND_PORT=82

/var/www/html/laradock/ 和 /var/www/html/laradock5/ 都執行
[user@localhost laradock5 ]$ docker-compose up -d nginx workspace
Starting laradock5_docker-in-docker_1 ... done
Starting laradock5_workspace_1        ... done
Starting laradock5_php-fpm_1          ... done
Starting laradock5_nginx_1            ... done

[user@localhost laradock ]$ docker-compose up -d nginx workspace
Starting laradock_docker-in-docker_1 ... done
Recreating laradock_workspace_1      ... done
Recreating laradock_php-fpm_1        ... done
Recreating laradock_nginx_1          ... done

檢查

打開 http://app3.test:5566/info.php (php 7.3) 和 http://app3.test:5567/info.php (php 5.6) 






2019年10月7日 星期一

docker 心得2019

系統:CentOS 7.6

安裝docker CE

由於 Docker 後來分為 Docker EE(Enterprise Edition)與 Docker CE(Community Edition)兩種版本,新的套件名稱與舊的不同,所以在安裝 Docker 之前,要先移除 CentOS Linux 系統上舊版的 Docker 套件:(新系統可略)
# yum remove docker docker-common container-selinux docker-selinux docker-engine docker-engine-selinux

安裝一些必要套件:
# yum install -y yum-utils device-mapper-persistent-data lvm2

新增 Docker 官方的 stable 套件庫(repository):
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

安裝 Docker CE 版:
# yum install docker-ce

將你的用戶加入docker group (實測該用戶還是不能執行docker  重啟機器打開新的screen才生效)
$ sudo usermod -aG docker $(whoami)
執行後可檢查 /etc/gshadow 和 /etc/group

docker 開機自動啟動
# systemctl enable docker.service

開啟docker 服務
# systemctl start docker.service

測試
# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:b8ba256769a0ac28dd126d584e0a2011cd2877f3f76e093a7ae560f2a5301c00
Status: Downloaded newer image for hello-world:latest
之後docker images 會多一個 hello-world:latest 的鏡像

安裝Docker Compose

安裝 epel
# yum install epel-release

查裝什麼package才能用pip
# yum provides */pip

安裝pip
# yum install python34-pip

安裝docker compose
# pip3.4 install docker-compose
...
You are using pip version 8.1.2, however version 19.2.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

升級pip
# pip3.4 install --upgrade pip
...
Successfully installed pip-19.2.3


檢測pip版本(升級後pip可以直接用了)
# pip --version
pip 19.2.3 from /usr/lib/python3.4/site-packages/pip (python 3.4)


升級Python packages,讓docker-compose 正確執行(我沒做)
# yum upgrade python*

查 docker-compose 版本
# docker-compose version
docker-compose version 1.24.1, build 4667896
docker-py version: 3.7.3
CPython version: 3.4.10

安裝Docker Compose - 方法2

如果pip安裝遇到 RuntimeError: Python 3.5 or later is required 錯誤,可使用這個方法。更無腦
https://phoenixnap.com/kb/install-docker-compose-centos-7  How To Install Docker Compose On CentOS 7
# curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose

如果報錯:
curl: (35) Peer reports incompatible or unsupported protocol version.
https://blog.csdn.net/feinifi/article/details/79629904  git clone 报错:Peer reports incompatible or unsupported protocol version解决办法
原因是curl,nss的版本低

解法:

# yum update nss curl



docker-compose 自動完成

# curl -L https://raw.githubusercontent.com/docker/compose/1.25.4/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose
讓安裝前的tty  docker-compose可以自動完成
# . /etc/bash_completion.d/docker-compose

開啟ipv4 ip_forward

啟動時如果報錯
# docker run -d --name my-running-app -p 5656:80 -v /root/php5.6-apache/src:/var/www/html my-php-app:latest
WARNING: IPv4 forwarding is disabled. Networking will not work.
b44f4990a94025f7d03329dfb32c64b2677dc595d937a309582150b409c0404a

https://stackoverflow.com/questions/41453263/docker-networking-disabled-warning-ipv4-forwarding-is-disabled-networking-wil Docker Networking Disabled: WARNING: IPv4 forwarding is disabled. Networking will not work
https://blog.csdn.net/weiguang1017/article/details/76212203 centos 7 Docker容器启动报WARNING: IPv4 forwarding is disabled. Networking will not work
https://carlislebear.blogspot.com/2014/11/arch-linux-internet-sharing.html  Arch Internet sharing(透過另一台電腦上網)
Windows是無法訪問容器的web服務的(hyper-v上可以),要開啟以下設定
/etc/sysctl.conf
net.ipv4.ip_forward=1
重啟網路
# systemctl restart network
這樣windows才能訪問容器的web服務
如果打不開,要注意有沒有因為被XDebug斷住了所以打不開

laradock

重啟Exited 的 laradock container

# docker ps -a
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS                      PORTS                                        NAMES
cc866de06b61        laradock_nginx       "/bin/bash /opt/star…"   2 months ago        Exited (255) 11 days ago    0.0.0.0:443->443/tcp, 0.0.0.0:5566->80/tcp   laradock_ngin
x_1
ce974cde40bf        laradock_php-fpm     "docker-php-entrypoi…"   3 months ago        Exited (255) 11 days ago    9000/tcp                                     laradock_php-
fpm_1
cb36fbf53996        laradock_workspace   "/sbin/my_init"          3 months ago        Exited (255) 11 days ago    0.0.0.0:2222->22/tcp                         laradock_work
space_1
d475c0f6d18f        docker:dind          "dockerd-entrypoint.…"   3 months ago        Exited (255) 11 days ago    2375-2376/tcp                                laradock_dock
er-in-docker_1
64c1a5ed1659        laradock_mysql       "docker-entrypoint.s…"   3 months ago        Exited (255) 2 months ago   0.0.0.0:3306->3306/tcp, 33060/tcp            laradock_mysq
l_1

啟動單一容器

# docker start laradock_workspace_1
laradock_workspace_1

但因為laradock 是很多容器組合而成的

正確的重啟laradock

# docker-compose up -d workspace nginx
laradock_docker-in-docker_1 is up-to-date
laradock_workspace_1 is up-to-date
Starting laradock_php-fpm_1 ... done
Starting laradock_nginx_1   ... done

如果報錯:
Creating network "laradock_frontend" with driver "bridge"
ERROR: Failed to Setup IP tables: Unable to enable SKIP DNAT rule:  (iptables failed: iptables --wait -t nat -I DOCKER -i br-7d0b53dc35e0 -j RETURN: iptables: No chain/target/match by that name.
 (exit status 1))
原因:
應該是改過防火墻iptables造成的
https://stackoverflow.com/a/53766860  iptables: No chain/target/match error (with docker network create)
https://github.com/wodby/docker4drupal/issues/211#issuecomment-351016274  Unable to enable SKIP DNAT rule (未使用)
解法:
重啟docker
# systemctl restart docker
再重啟laradock
# docker-compose up -d workspace nginx

進入workspace容器

# docker exec -it laradock_workspace_1 bash
上面是以root身份進入,跑composer 會有警告。如何進入容器跑composer不報警告?
以laradock身份進入容器
# docker-compose exec --user=laradock workspace bash
laradock@daa4f318e534:/var/www$ composer --version
Composer version 1.9.0 2019-08-02 20:55:32


關閉laradock

# docker-compose down

多人開發

配置.env

#   APP_CODE_PATH_HOST=../  
# APP_CODE_PATH_HOST=../project-z/coolapp/   # 使用 laradock/nginx/sites/default.conf 不需特別設定
APP_CODE_PATH_HOST=../project-z/  # 多個專案,複製 laradock/nginx/sites/app.conf.example 成 coolapp.conf 和 coolapp2.conf
#   WORKSPACE_INSTALL_XDEBUG=false
WORKSPACE_INSTALL_XDEBUG=true
#   PHP_FPM_INSTALL_XDEBUG=false
PHP_FPM_INSTALL_XDEBUG=true  # workspace 和 php-fpm容器都裝XDebug
#   NGINX_HOST_HTTP_PORT=80
NGINX_HOST_HTTP_PORT=5566


coolapp.conf

root /var/www/app;  => root /var/www/coolapp/public;

coolapp2.conf

server_name app.test; => server_name app2.test;
root /var/www/app;  => root /var/www/coolapp2/public;

windows設hosts,重啟laradock(down 和 up),然後 http://app.test:5566/ 訪問coolapp,http://app2.test:5566/ 訪問 coolapp2

更新laradock

git pull 更新laradock後重新build會報錯,因為env-example 已經被改過了,加了一些配置
先備份自己的.env(要記得你改了什麼),然後cp env-example .env 然後再把你原本在.env改的配置改到新的.env。這樣build才會成功

php安裝memcache

修改.env
#   PHP_FPM_INSTALL_MEMCACHED=false
PHP_FPM_INSTALL_MEMCACHED=true

需重新build php-fpm容器出錯

# docker-compose build php-fpm
...
E: Failed to fetch http://deb.debian.org/debian/pool/main/c/cups/libcupsimage2_2.2.10-6+deb10u1_amd64.deb  404  Not Found [IP: 151.101.10.133 80]
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
ERROR: Service 'php-fpm' failed to build: The command '/bin/sh -c if [ ${INSTALL_IMAGEMAGICK} = true ]; then     apt-get install -y libmagickwand-dev imagemagick &&     pecl install imagick &&     docker-php-ext-enable imagick ;fi' returned a non-zero code: 100
build 失敗
https://github.com/laradock/laradock/issues/2434
https://blog.51cto.com/beijing0414/1633956 
原來是hyper-v 系統的時間錯誤(當天應為4/8)
[root@localhost laradock]# date
Mon Apr  6 00:06:11 -02 2020
解法:
先安裝ntpdate
# yum install ntpdate
[root@localhost laradock]# date
Mon Apr  6 00:36:28 -02 2020
[root@localhost laradock]# ntpdate cn.pool.ntp.org
 8 Apr 13:07:13 ntpdate[14154]: step time server 119.28.206.193 offset 217834.861195 sec
[root@localhost laradock]# date
Wed Apr  8 13:07:15 -02 2020

重新build php-fpm(不吃緩存,比較慢)
# docker-compose build --no-cache php-fpm
# docker-compose up --build  // 不要不指定service,否則會全部build

這樣phpinfo()和命令行php -m 才有memcached

安裝docker-machine (無使用)

# base=https://github.com/docker/machine/releases/download/v0.16.0 &&
  curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine &&
  sudo mv /tmp/docker-machine /usr/local/bin/docker-machine &&
  chmod +x /usr/local/bin/docker-machine

檢視配置檔案位於哪裡

https://codertw.com/%E4%BC%BA%E6%9C%8D%E5%99%A8/160314/
$ systemctl show --property=FragmentPath docker
FragmentPath=/usr/lib/systemd/system/docker.service

開啟docker API

https://gist.github.com/styblope/dc55e0ad2a9848f2cc3307d4819d819f
新增文件:/etc/docker/daemon.json
{"hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]}
新增文件:/etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
重新加載 systemd daemon
# systemctl daemon-reload
重啟docker
# systemctl restart docker.service
在機器上測試
$ curl http://localhost:2375
{"message":"page not found"}
但是windows上打不開 => server要打開 2375 端口
# firewall-cmd --zone=public --add-port=2375/tcp --permanent
# firewall-cmd --reload
然後在Windows 瀏覽器上直接打開 http://192.168.1.9:2375/info 顯示json即成功

忽然進不了XDebug斷點

commit ab4e06f270ae83d6e41702b2b652a980b12816ce
Author: Jordy Schreuders <3071062+99linesofcode@users.noreply.github.com>
Date:   Fri Feb 14 15:15:04 2020 +0100

    Default to host.docker.internal

因為更新重新build php-fpm後這個commit把 xdebug.remote_connect_back 改成0了
修改 php-fpm/xdebug.ini 、 workspace/xdebug.ini 將 xdebug.remote_connect_back 改回1,然後重新build
# docker-compose build php-fpm
ps. 重新build 時間比較久,改 xdebug.ini 後沒法像  nginx/sites/default.conf 只需要重啟laradock就能生效,必須build

進不了XDebug斷點-2

新hyper-v虛擬機上裝的laradock,在windows本機不要用同一個PHPStorm 專案改deployment去連,會一直進不了斷點,開一個新project後重新設deployment,請求接口和cli時會自動匹配,PHP CLI無需設docker。不要在同一個PHPStorm projcet上折騰。
實體開發機裝了兩個PHP(php 5.5 + 7.3),上面的laradock http能進xdebug,但是cli不行 => php7.3改用hyper-v的laradock去斷點

進不了XDebug斷點-3

如果laradock中 http請求可以斷點,但是CLI不能斷點。別折騰了,直接在hyper-v上面裝PHP去做CLI斷點,不一定要在laradock中斷點。
檢查:
使用-d 自定義INI條目
$ php -dxdebug.remote_enable=1 -dxdebug.remote_mode=req -dxdebug.remote_port=9000 -dxdebug.remote_host=192.168.1.7 -dxdebug.remote_connect_back=0 -dxdebug.idekey=PHPSTORM public/index.php

要注意 xdebug.remote_enable=1 是否開啟

其實是 laradock 的 workspace 容器的xdebug 版本是3.0.0這個原因造成的,workspace和php-fpm容器裝的是不同的xdebug,workspace負責cli,php-fpm負責網頁,所以網頁上的phpinfo()查到的是是php-fpm的xdebug版本,而workspace的xdebug版本要在容器裡cli執行,如:
root@e7aa5f3bd006:/var/www# php -r 'phpinfo();' | grep Xdebug
    with Xdebug v2.5.5, Copyright (c) 2002-2017, by Derick Rethans
需要改 workspace/Dockerfile 的 xDebug 部分,讓workspcace 容器安裝低版本的xdebug

laradock中websocket 端口對外

https://github.com/laradock/laradock/issues/2002#issuecomment-468884705
編輯 docker-compose.yml 加入
services:
  workspace:
    port:
      - 2346:2346
然後重啟laradock



和gitlab端口衝突

目前已知 8080 和3000端口會和gitlab衝突(gitlab已開啟)

解法:

https://github.com/laradock/laradock/issues/2512#issuecomment-589719158  Bind for 0.0.0.0:8080 failed: port is already allocated

換一個端口,修改.env
WORKSPACE_VUE_CLI_SERVE_HOST_PORT=8080 => 8084
...
WORKSPACE_BROWSERSYNC_HOST_PORT=3000 => 3002

安裝特定版本的xdebug

如果你的專案和xdebug最新版本(3.0.0+)有衝突
https://bugs.xdebug.org/view.php?id=1883  0001883: Function xdebug_is_enabled has been removed
XDebug 3.0.0beta1版本把 xdebug_is_enabled() 移除了
可以這樣做
diff --git a/php-fpm/Dockerfile b/php-fpm/Dockerfile
index 1837b45..a64bf63 100644
--- a/php-fpm/Dockerfile
+++ b/php-fpm/Dockerfile
@@ -193,7 +193,7 @@ RUN if [ ${INSTALL_XDEBUG} = true ]; then \
     if [ $(php -r "echo PHP_MINOR_VERSION;") = "0" ]; then \
       pecl install xdebug-2.9.0; \
     else \
-      pecl install xdebug; \
+      pecl install xdebug-2.9.8; \
     fi \
   fi && \
   docker-php-ext-enable xdebug \
ps. PHP_MINOR_VERSION就是PHP的中版本號,ex. php 7.3,PHP_MINOR_VERSION就是3

因為改了Dockerfile,所以要重新build,雖然有緩存,但還是有點久
$ docker-compose build php-fpm
...
Step 29/159 : RUN if [ ${INSTALL_XDEBUG} = true ]; then   if [ $(php -r "echo PHP_MAJOR_VERSION;") = "5" ]; then     pecl install xdebug-2.5.5;   else     if [ $(php -r "echo PHP_MINOR_VERSION;") = "0" ]; then       pecl install xdebug-2.9.0;     else       pecl install xdebug-2.9.8;     fi   fi &&   docker-php-ext-enable xdebug ;fi
 ---> Running in 999878a0db51
downloading xdebug-2.9.8.tgz ...
Starting to download xdebug-2.9.8.tgz (245,293 bytes)
...................................................done: 245,293 bytes
91 source files, building
running: phpize
Configuring for:
PHP Api Version:         20180731
Zend Module Api No:      20180731
Zend Extension Api No:   320180731
building in /tmp/pear/temp/pear-build-defaultusergNFJEA/xdebug-2.9.8
running: /tmp/pear/temp/xdebug/configure --with-php-config=/usr/local/bin/php-config
checking for grep that handles long lines and -e... /bin/grep

自定義workspace中的.bashrc

由 workspace/Dockerfile 
COPY ./aliases.sh /home/laradock/aliases.sh
...
USER laradock
RUN echo "" >> ~/.bashrc && \
    echo "# Load Custom Aliases" >> ~/.bashrc && \
    echo "source ~/aliases.sh" >> ~/.bashrc && \
      echo "" >> ~/.bashrc

修改 workspace/aliases.sh 可以客製化容器中laradock用戶的.bashrc
然後需重新build workspace容器
# docker-compose build workspace

Dockerfile

以安裝 php:5.6-apache 為例
https://hub.docker.com/_/php

新建 Dockerfile 

內容為
FROM php:5.6-apache
COPY src/ /var/www/html/
新增目錄src 和 文件src/index.php

build Docker image

# docker build -t my-php-app .
Step 1/2 : FROM php:5.6-apache
5.6-apache: Pulling from library/php
...
他會從線上把 php:5.6-apache 拉下來,用下面方法查看
# docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
my-php-app              latest              10cc9a5aa0c2        25 seconds ago      355MB
...
php                     5.6-apache          24c791995c1e        14 months ago       355MB

刪除dangling的images(部份<none>TAG的image)

https://stackoverflow.com/a/33913711
因為每次都build同一個image名字時,前一個同名的image的REPOSITORY和TAG會變成<none>
# docker rmi $(docker images --filter "dangling=true" -q --no-trunc)


啟動容器

# docker run -d --name my-running-app -p 5656:80 -v /root/php5.6-apache/src:/var/www/html my-php-app:latest

--name my-running-app => 指定容器的名字
-p 5656:80 => 容器中的80端口對應到host的5656端口,http://192.168.1.9:5656/ 可訪問容器中的web伺服器
-v /root/php5.6-apache/src:/var/www/html => host的/root/php5.6-apache/src對應到容器中的/var/www/html,直接改host目錄的文件容器中文件就會改動

進入容器

# docker exec -it my-running-app bash
用 -d 啟動後再用此目錄進容器,否則容器內的apache不會啟動

停止容器

# docker stop my-running-app

刪除 Exited 的容器

# docker rm my-running-app

進階使用

Dockerfile
FROM php:5.6-apache
COPY src/ /var/www/html/
RUN docker-php-ext-install mysqli \
    && apt-get update \
    && apt-get install -y libfreetype6-dev libjpeg62-turbo-dev \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    && docker-php-ext-install gd \
    && pecl install xdebug-2.5.5 && docker-php-ext-enable xdebug \
    && echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" >> /usr/local/etc/php/php.ini  \
    && echo "xdebug.remote_enable=1" >> /usr/local/etc/php/php.ini \
    && echo "xdebug.remote_connect_back=1" >> /usr/local/etc/php/php.ini \
    && echo "xdebug.idekey=PHPSTORM" >> /usr/local/etc/php/php.ini \
    && echo "xdebug.remote_log=/tmp/xdebug.log" >> /usr/local/etc/php/php.ini

註:
安裝mysqli
安裝gd函式庫
安裝xdebug並配置


使用docker安裝beanstalk console

github上推薦用composer安裝,但是如果你的機器沒有php和composer,你可以這樣做。直接拉取github上專案
$ git clone https://github.com/ptrofimov/beanstalk_console.git
$ cd beanstalk_console/
$ docker build --rm -t beanstalk_console .
$ docker run -d -p "8899:80" --name beanstalk_console beanstalk_console

然後瀏覽器打開 http://x.x.x.x:8899  即可顯示 Beanstalk console

在容器內測端口

https://stackoverflow.com/a/2226759  Test if port open and forwarded using PHP
php-fpm容器內可能沒有telnet,可以用PHP去測端口通不通
$host = 'stackoverflow.com';
$ports = array(21, 25, 80, 81, 110, 443, 3306);

foreach ($ports as $port)
{
    $connection = @fsockopen($host, $port);

    if (is_resource($connection))
    {
        echo '<h2>' . $host . ':' . $port . ' ' . '(' . getservbyport($port, 'tcp') . ') is open.</h2>' . "\n";

        fclose($connection);
    }

    else
    {
        echo '<h2>' . $host . ':' . $port . ' is not responding.</h2>' . "\n";
    }
}
輸出:
stackoverflow.com:21 is not responding.
stackoverflow.com:25 is not responding.
stackoverflow.com:80 (http) is open.
stackoverflow.com:81 is not responding.
stackoverflow.com:110 is not responding.
stackoverflow.com:443 is not responding.
stackoverflow.com:3306 is not responding.

如果端口忽然不通可以嘗試重啟docker

參考資料:

https://blog.gtwang.org/linux/centos-linux-7-install-docker-tutorial/  CentOS Linux 7 安裝 Docker 步驟與使用教學
https://github.com/NaturalHistoryMuseum/scratchpads2/wiki/Install-Docker-and-Docker-Compose-(Centos-7)   Install Docker and Docker Compose (Centos 7)





2019年3月13日 星期三

hyper-v 安裝CentOS 7.6

Windows 10 Pro 內建 Hyper-v
安裝 CentOS 7.6 + PHP 7.3 + nginx + laravel 5.8

安裝Hyper-v 和 WSL( Windows Subsystem for Linux ) - 略
ps. WSL可以在Microsoft Store 搜尋Linux 下載不同版本Linux(Kali、ubuntu、Debian...)等Subsystem
ps. Hyper-v 和安卓的夜神模擬器nox無法同時執行,Windows會報錯SYSTEM_SERVICE_EXCEPTION 藍色畫面
https://www.reddit.com/r/windows/comments/9wdmcc/help_bsod_when_i_start_nox_player_hyperv_enabled/
NOX cannot run when Hyper-V is enabled.
ps. BlueStacks 和 Hyper-v 也無法同時執行


該使用WSL還是Hyper-v?
結論:你不應該使用WSL
1. Microsoft did not design or build WSL for production workloads.
微軟設計WSL不是為了生產環境
2. Running a virtual machine (VM) can be more efficient.
虛擬機更高效
3. 4. 5. 略

Windows 10 啟用hyper-v

https://www.itread01.com/content/1550134651.html  WIN10 Hyper-V 安裝 CentOS 7
https://dotblogs.com.tw/gelis/2010/07/30/16892  開啟Hyper-V的內部虛擬網路

下載Minimal版本

開啟hyper-v 功能

設定 =》 應用程式 =》 應用程式與功能 =》 選用功能 =》 更多Windows功能 =》 開啟hyper-v
(開啟後需重開機)

新增虛擬交換器

hyper-v 管理員 =》 虛擬交換器管理員 =》 新虛擬網路交換器 =》 新增【外部網路】,選擇有線網卡


虛擬機器 =》 設定 =》 網路界面卡 =》 選擇剛剛新增的【外部網路】虛擬交換器

新裝的機器要有網路

開機自動啟動eth0網路
# vi /etc/sysconfig/network-scripts/ifcfg-eth0
ONBOOT=no
ONBOOT=yes


hyper-v 虛擬交換器 使用「外部網路」,(ThinkPad T460)不要使用無線網卡,使用網路線連接區域連線,不然虛擬機和win 10 hosts會同一個內網ip,win 10 SSH連不上虛擬機

Hyper-v 儲存後即使重開Windows 10 ,再重開虛擬機器,工作狀態還在,等於沒有重開虛擬機

安裝完CentOS 7.6後


安裝一些常用package
# yum install vim epel-release screen git bash-completion telnet
裝完bash-completion後讓root可以正常使用
# source /etc/profile.d/bash_completion.sh
查裝什麼package才能用netstat
# yum provides */netstat
安裝net-tools以使用netstat
# yum install net-tools

升級git

因為yum安裝的git版本是1.8.3.1 ,用以下方法安裝2.x 最新版本的git

移除git

# yum -y remove git

新增 End Point 倉庫

# yum -y install https://packages.endpoint.com/rhel/7/os/x86_64/endpoint-repo-1.9-1.x86_64.rpm
然後安裝2.x版本的git
# yum install git

檢查

# git --version
git version 2.30.1

End Point 倉庫過期造成yum無法更新

# yum update
...
https://packages.endpoint.com/rhel/7/os/x86_64/repodata/repomd.xml: [Errno 14] curl#6 - "Could not resolve host: packages.endp
oint.com; Unknown error"

解法

# yum-config-manager --disable endpoint

安裝php、php-fpm、nginx

安裝remi
# yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
如果你要最新的php 7.3.x,必須這樣做
# yum --enablerepo=remi,remi-php73 update -y
查remi的版本
# yum info remi-release
開啟remi-php73
# yum-config-manager --enable remi-php73
安裝php7.3
# yum install php73-php
使php能夠呼叫到php 7.3 bash ( 直接加到.bashrc 可以自動enable )
# source /opt/remi/php73/enable
查php版本
# php -v
PHP 7.3.3 (cli) (built: Mar  5 2019 13:50:38) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.3, Copyright (c) 1998-2018 Zend Technologies
安裝 php 7.3的php-fpm
# yum install php73-php-fpm
安裝nginx
# yum install nginx
啟動php-fpm
# systemctl start php73-php-fpm
查php-fpm狀態
# systemctl status php73-php-fpm
啟動nginx
# systemctl start nginx
查nginx 開機是否自動啟動
# systemctl is-enabled nginx
disabled
開機自動啟動nginx、php-fpm
# systemctl enable nginx
# systemctl enable php73-php-fpm.service

訪問網頁不通時,打開80 port
# firewall-cmd --zone=public --add-port=80/tcp --permanent
success
# firewall-cmd --reload
success
檢查配置是否生效
# iptables-save | grep 80
-A IN_public_allow -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT

關閉端口

https://docs.fedoraproject.org/en-US/quick-docs/firewalld/  Using firewalld
# firewall-cmd --remove-port=port-number/port-type
# firewall-cmd --runtime-to-permanent
如:
# firewall-cmd --remove-port=80/tcp
# firewall-cmd --runtime-to-permanent

查當前zone開放的端口

# firewall-cmd --list-ports


下載composer-steup.php
# php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
# ls
anaconda-ks.cfg  composer-setup.php
# php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
Installer verified
安裝composer
# php composer-setup.php
All settings correct for using Composer
Downloading...

Composer (version 1.8.4) successfully installed to: /root/composer.phar
Use it: php composer.phar
# ls
anaconda-ks.cfg  composer.phar  composer-setup.php
刪除 composer-setup.php
# php -r "unlink('composer-setup.php');"
讓composer方便呼叫
# mv composer.phar /usr/local/bin/composer
# which composer
/usr/local/bin/composer

更新composer

$ composer --version
Composer version 1.7.2
$ composer self-update
Updating to version 1.8.5 (stable channel).
   Downloading (100%)
Use composer self-update --rollback to return to version 1.7.2

加速composer

$ composer global require hirak/prestissimo
...
    Failed to download hirak/prestissimo from dist: The zip extension and unzip command are both missing, skipping.
Your command-line PHP is using multiple ini files. Run `php --ini` to show them.
    Now trying to download from source
解決上面黃底的錯誤
# yum install zip unzip php73-php-pecl-zip

安裝 https://laravel.com/docs/5.8/installation  上laravel 5.8 必裝的php extension
檢查php extension有無安裝
# php -m | grep mbstring

安裝laravel 5.8需要的php extension

# yum install php73-php-pdo
# yum install php73-php-mbstring
# yum install php73-php-xml
# yum install php73-php-bcmath

安裝Xdebug

# yum install php73-php-pecl-xdebug

xdebug.ini報 invalid ELF header 錯誤

$ php --ini | grep xdebug
Failed loading /etc/opt/remi/php73/php.d/15-xdebug.ini:  /etc/opt/remi/php73/php.d/15-xdebug.ini: invalid ELF header
Additional .ini files parsed:      /etc/opt/remi/php73/php.d/15-xdebug.ini,
解法:
重新安裝php73-php-common
# yum remove php73-php-common
# yum install php73-php php73-php-fpm php73-php-pdo php73-php-mbstring php73-php-xml php73-php-bcmath php73-php-pecl-xdebug 
當然 php73-php-fpm 需重啟和重新enable
# systemctl start php73-php-fpm
# systemctl enable php73-php-fpm.service

讓XDebug  CLI 生效

.bashrc 加入
export XDEBUG_CONFIG="remote_host=192.168.1.7 idekey=PHPSTORM"
export PHP_IDE_CONFIG="serverName=localhost"
/etc/opt/remi/php73/php.d/15-xdebug.ini 修改:
xdebug.remote_enable = true


安裝 php-process

如果你要用workerman需要安裝php-process,否則啟動時會報錯
Uncaught Error: Call to undefined function posix_getpid()
# yum install php73-php-process

安裝memcached擴展

# yum install php73-php-pecl-memcached

安裝pdo_mysql擴展

# yum install php73-php-pecl-mysql

yum安裝時404報錯

# yum install php73-php-pecl-memcached
...
http://repo.mongodb.org/yum/redhat/7/mongodb-org/4.2/x86_64/repodata/repomd.xml: [Errno -1] Error importing repomd.xml for MongoDB: Damaged repomd.xml file
Trying other mirror.
http://mirror.pregi.net/centos/7.7.1908/os/x86_64/repodata/repomd.xml: [Errno 14] HTTP Error 404 - Not Found
Trying other mirror.
...

解法

# yum clean all --enablerepo=*
Loaded plugins: fastestmirror
Cleaning repos: C7.0.1406-base C7.0.1406-centosplus C7.0.1406-extras ...
...
Cleaning up list of fastest mirrors
必須清除yum緩存。這邊和IP無關,使用 proxychains4 掛代理IP執行無效

避免出現Memcached::get(): could not unserialize value, no igbinary support的錯誤

memcached有個memcached.serializer,預設採用igbinary。但是,當主機上沒有安裝igbinary時,則會改用php模式(standard PHP serializer)。如果有台主機沒有安裝Igbinary,且該主機的程式由memcache取回資料時為Igbinary格式,因無法使用Igbinary而發生錯誤。所以統一改為使用php模式。

檢查當前PHP CLI的memcached.serializer是什麼值:

# php -r "echo ini_get('memcached.serializer');"
igbinary
或
# php -i | grep memcached.serializer
memcached.serializer => igbinary => igbinary

查配置文件路徑

# php --ini | grep memcached
/etc/opt/remi/php73/php.d/50-memcached.ini,

修改 /etc/opt/remi/php73/php.d/50-memcached.ini 的 memcached.serializer配置為php

memcached.serializer = "php"

檢查修改後的結果(直接生效)

# php -r "echo ini_get('memcached.serializer');"
php
# php -i | grep memcached.serializer
memcached.serializer => php => php


安裝 laravel 5.8

$ composer create-project --prefer-dist laravel/laravel blog

配置nginx

nginx.conf 將server 改成以下
server {
    listen       80;
    server_name  localhost;
    root /var/www/html/blog/public;
    index index.php index.html index.htm;
    location / {
    #   autoindex on; // 如果想要開啟顯示資夾目錄的話加入這條
    #                  // 建議只在debug階段開啟
        try_files $uri $uri/ /index.php?$query_string;
    }
    #error_page  404              /404.html;
    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
    location ~ \.php$ {
        root /var/www/html/blog/public;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        include        fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    }
}
如果前一步驟沒配好,訪問網頁會直接下載index.php 文件
https://stackoverflow.com/questions/25591040/nginx-serves-php-files-as-downloads-instead-of-executing-them/41838767#41838767
I had similar problem which was resolved by emptying the browser cache (also worked fine with different browser).
調好後要清空瀏覽器緩存


當storage 為777時,仍然報錯 storage/logs/laravel.log Permission denied
這個是 selinux 的問題
關掉selinux以證明這個問題
# setenforce 0
(可正常訪問)
這解法不好,因為你把被添加的服務器安全,所以把它改回去
# setenforce 1
應使用 SELinux 所允許的寫檔命令
blog ]$ sudo chcon -R -t httpd_sys_rw_content_t storage

laravel連不同(實體)機器DB時報錯

SQLSTATE[HY000] [2002] Permission denied
但是用mysql 命令或Navicat ssh通道卻能連,只有laravel不能連
https://stackoverflow.com/a/56381932  SQLSTATE[HY000] [2002] Permission denied Laravel PDO Driver (credentials working via artisan migrate)
解法:
# setsebool httpd_can_network_connect_db 1

beanstalk也不通 - 
Socket error 13: Permission denied  
https://stackoverflow.com/a/44092808 SQLSTATE[HY000] [2002] Permission denied
# setsebool httpd_can_network_connect 1


安裝workerman/gateway-worker

$ composer require workerman/gateway-worker
https://learnku.com/articles/13151/using-laravel-to-carry-out-socket-communication-in-workerman

新增 Workerman 啟動文件

用命令 php artisan make:command WorkermanCommand 新增 Workerman 啟動文件 app/Console/Commands/WorkermanCommand.php
  namespace App\Console\Commands;

use GatewayWorker\BusinessWorker;
use GatewayWorker\Gateway;
use GatewayWorker\Register;
use Illuminate\Console\Command;
use Workerman\Worker;

class WorkermanCommand extends Command
{

    protected $signature = 'workman {action} {--d}';

    protected $description = 'Start a Workerman server.';

    public function handle()
    {
        global $argv;
        $action = $this->argument('action');

        $argv[0] = 'wk';
        $argv[1] = $action;
        $argv[2] = $this->option('d') ? '-d' : '';

        $this->start();
    }

    private function start()
    {
        $this->startGateWay();
        $this->startBusinessWorker();
        $this->startRegister();
        Worker::runAll();
    }

    private function startBusinessWorker()
    {
        $worker                  = new BusinessWorker();
        $worker->name            = 'BusinessWorker';
        $worker->count           = 1;
        $worker->registerAddress = '127.0.0.1:1236';
        $worker->eventHandler    = \App\Workerman\Events::class;
    }

    private function startGateWay()
    {
        $gateway = new Gateway("websocket://0.0.0.0:2346");
        $gateway->name                 = 'Gateway';
        $gateway->count                = 1;
        $gateway->lanIp                = '127.0.0.1';
        $gateway->startPort            = 2300;
        $gateway->pingInterval         = 30;
        $gateway->pingNotResponseLimit = 0;
        $gateway->pingData             = '{"type":"@heart@"}';
        $gateway->registerAddress      = '127.0.0.1:1236';
    }

    private function startRegister()
    {
        new Register('text://0.0.0.0:1236');
    }
}

創建事件監聽文件

namespace App\Workerman;

class Events
{

    public static function onWorkerStart($businessWorker)
    {
    }

    public static function onConnect($client_id)
    {
    }

    public static function onWebSocketConnect($client_id, $data)
    {
    }

    public static function onMessage($client_id, $message)
    {
    }

    public static function onClose($client_id)
    {
    }
}
s

啟動Workerman 服務端

$ php artisan workman start --d

檢查是否啟動成功

瀏覽器打開看到這個畫面就是啟動成功
在hyper-v上(不在容器內)竟然也能啟動成功...

設定固定IP

https://www.cyberciti.biz/faq/howto-setting-rhel7-centos-7-static-ip-configuration/

使用 Network Manager 文字GUI,比較無腦
# nmtui edit eth0
IPv4 CONFIGURATION:<Manual>
Addresses:192.168.1.x
Gateway:192.168.1.1
DNS servers:192.168.1.1   (使用host的DNS,沒配置ping 不到域名)

點擊<OK>後即是自動修改了 /etc/sysconfig/network-scripts/ifcfg-eth0
BOOTPROTO="dhcp"
BOOTPROTO=none
IPADDR=192.168.1.x
PREFIX=24
GATEWAY=192.168.1.1

重啟網路服務
# systemctl restart network
機器ip即固定 192.168.1.x ,原本的ssh會斷掉重連 192.168.1.x 即可

如果常常有時候連不上 hyper-v  192.168.1.9 (ping不通,但是瀏覽器打得開的詭異現象),重啟網卡(hyper-v CentOS + Windows) 無效
解法:
Bear-WAN先改【內部網路】再改【外部網路】,再重啟hyper-v 虛擬機

調整pagefile.sys到D碟後ssh無法登陸

http://www.xiaobaixitong.com/win10jiaocheng/31951.html  win10的pagefile.sys是什么文件?文件太大如何移动到其它盘
因為C碟只有100G,使用TreeSizeFreePortable發現pagefile.sys就佔了16G,要把他移動到D碟。
設置完需重啟電腦,移動完發現hyper-v重啟,gitlab更新不了,而且ssh也登陸不上了。以後需要注意此操作

2018年7月5日 星期四

netstat 使用心得

$ netstat -ant
Rellik:通常是拿來 debug
服務可能被 ddos 之類的
要看總連線數
-ant 可能會發現 established 異常過高, 或是 time_wait 連線數異常之類的
就情境不太依樣

$ netstat -tlunp
只看哪些服務被listen

-l 通常只是列出本機有在 listen
t = tcp
u = udp
p = 列出哪隻程式


netstat 也能看出有沒跑起怪東西
sshd有兩個是因為 :::xxxx 是ipv6的關係

避免memcached 的port對外
/etc/sysconfig/memcached
OPTIONS="-l 127.0.0.1 -U 0"

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN      19291/memcached
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      3396/sshd

0 0.0.0.0:22 => 對外
以防止被當做DDos攻擊跳板

參考資料:
https://blog.gslin.org/archives/2018/02/28/8177/%E9%80%8F%E9%81%8E-memcached-udp-port-11211-%E7%9A%84%E6%94%BB%E6%93%8A/  透過 memcached UDP (Port 11211) 的攻擊...
https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-memcached-on-centos-7  How To Install and Secure Memcached on CentOS 7





2017年8月16日 星期三

laravel 4.2 心得

安裝PHP memcached(非memcache)

錯誤:
Class 'Memcached' not found
# yum install php-pecl-memcached

PHP 5.4升級5.5

環境:centOS 7.1
http://www.techoism.com/how-to-upgrade-php-version-5-4-to-5-5-on-centosrhel/
移除舊的php
# yum remove php-common
安裝PHP 5.5和其套件
# yum -y install php55w php55w-opcache
# yum -y install php55w-xml php55w-mcrypt php55w-gd php55w-devel php55w-mysql php55w-intl php55w-mbstring
安裝其餘必要擴展
# yum install php55w-fpm
# yum install php55w-pecl-memcache
# yum install php55w-pecl-memcached
重啟php-fpm
# service php-fpm restart

安裝redis

https://www.linode.com/docs/databases/redis/install-and-configure-redis-on-centos-7
# yum install redis
啟動redis
# systemctl start redis
開機自動啟動redis(可選)
# systemctl enable redis
測試redis是否安裝成功
# redis-cli ping
PONG

安裝supervisor

# yum install python-setuptools
# yum install supervisor
配置
# vim /etc/supervisord.conf
[include]
files = supervisord.d/*.ini
files = supervisord.d/*.conf
# vim /etc/supervisord.d/your.conf
[program:ga2-main]
command = php /laravel_path/artisan queue:listen ga2-main
process_name = %(program_name)s_%(process_num)s
numprocs = 1
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/ga2-main.log

啟動supervisor
# service supervisord start
停用supervisor
# service supervisord stop

檢查是否有跑
# ps aux | grep supervisord
root     14983  0.3  0.2 223064  2696 ?        Ss   12:25   0:01 /usr/bin/python /usr/bin/supervisord -c /etc/supervisord.conf
# ps aux | grep ga2-main
root     16471  0.1  2.1 411032 22236 ?        S    12:26   0:00 php /laravel_path/artisan queue:listen ga2-main

勿用pip或 easy_install 安裝,測試安裝後啟動不了supervisor
移除用pip或easy_install安裝的supervisor
# pip uninstall supervisor
列出systemd的unit files
# systemctl list-unit-files




2016年9月16日 星期五

使用SSH通道翻牆

原本我都是用shadowsocks來走代理的,但是要訪問不對外的網站時,ss的DNS不知道如何設定成機器上的private DNS,設定hosts也無效,最後發現用ssh通道效果出奇的好,只需要設機器上的hosts即可

雖然我電腦是windows,但是cygwin安裝openssh後搭配chrome SwitchySharp依然能使用ssh代理

打開SSH通道
$ ssh -i your.key -D 1234 user@x.x.x.x

然後在瀏覽器上設定代理,如圖



參考資料:
http://www.pchou.info/linux/2015/11/01/ssh-tunnel.html  SSH隧道翻墙的原理和实现



2016年9月15日 星期四

Letsencrypt 使用心得

前言

想把網站升級到https,避免被gateway的MIS監控
雖然他要看到 https 網站上的內容是可以的,但是如果是要把  client-> server 中間的封包擷取出來分析出內容,以目前技術很難做,他看到的只會是加密的一串不知道什麼東西。除非他用類似 man in the middle attack 的技術,植入一些木馬程式在你的 client 電腦上,讓 client <-> server 中間的加解密失效
但如果是http,那gateway可以看到明文,連cookie也行
所以才說不要隨便亂上一些沒有 https 加密的網站
你如果不信任公司網路的話,一些 http 網站,建議你跳到自己的 server 上

SSH代理

1. Windows 打開 cygwin (需安裝openssh)
# ssh -D 3128 your.server.ip
2. 然後 browser 打開 proxy
底下 localhost 直接連線的設定都要清空,然後在 socket server 那邊填上  127.0.0.1  port 3128,這樣就會透過 ssh tunnel 到你的 server 再連上網站
如圖:
與用shadowsocks方法類似


Letsencrypt 使用限制

Registrations/IP 限制就是每個 IP 只能在 3 小時內發送 10 次請求,如果超過 10 次就會被阻擋,所以申請成功的 Domain,不要隨便砍掉 /etc/letsencrypt/accounts 目錄,否則你就不能重複申請了 => 不是說你的 client -> https server 的連線,是要註冊幾次
Certificates/Domain 限制就是在七天內你的主 Domain 跟 sub Domain 夾起來只能申請五個,所以當你申請五個 domain 時,Letsencrypt 就會阻擋你申請下一個 domain 了,最後要注意的是,Letsencrypt 申請憑證使用期限是 90 天,官方建議如果使用在正式網站,請 60 天重新 renew 一次。

如果某個網站 a.bear.com 沒設dns,直接寫hosts, 這樣還能上http?
這樣也可以上,dns 是 dns

使用lukas2511 的letsencrypt.sh產生證書

Let's Encrypt的腳本不只lukas2511 ,還有其他的。如:
https://github.com/Neilpang/acme.sh
https://github.com/certbot/certbot
這邊以lukas2511 的版本為例
github lukas2511的 letsencrypt.sh 專案後來改名成dehydrated ,需注意
下載最新版本
$ cd ~; git clone https://github.com/lukas2511/letsencrypt.sh.git
$ cd letsencrypt.sh/
把程式安裝到 /etc/letsencrypt.sh/ 下:
# mkdir /etc/letsencrypt.sh/
# cp ~/letsencrypt.sh/dehydrated /etc/letsencrypt.sh/
設定config
# echo "WELLKNOWN=/var/www/letsencrypt" > /etc/letsencrypt.sh/config
# mkdir -p /var/www/letsencrypt/
設定/etc/nginx/nginx.conf  ,主要網址 yourdomain.com 設定的server{}中加入
location /.well-known/acme-challenge/ {
    alias /var/www/letsencrypt/;
}
我有把 /var/www/letsencrypt/ 權限改成apache
產生SSL certificate
# /etc/letsencrypt.sh/dehydrated -c -d yourdomain.com
(成功訊息)
# INFO: Using main config file /etc/letsencrypt.sh/config
Processing yourdomain.com
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for yourdomain.com...
 + Responding to challenge for yourdomain.com...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!

成功後產生的檔案都在 /etc/letsencrypt.sh/certs/yourdomain.com/
# ls /etc/letsencrypt.sh/certs/yourdomain.com/ -l
-rw------- 1 root root 1643 Sep 15 03:22 cert-14739097xx.csr
-rw------- 1 root root    0 Sep 15 03:22 cert-14739097xx.pem
-rw------- 1 root root 1643 Sep 15 03:38 cert-14739106xx.csr
-rw------- 1 root root    0 Sep 15 03:38 cert-14739106xx.pem
-rw------- 1 root root 1643 Sep 15 03:49 cert-14739113xx.csr
-rw------- 1 root root    0 Sep 15 03:49 cert-14739113xx.pem
-rw------- 1 root root 1643 Sep 15 03:54 cert-14739116xx.csr
-rw------- 1 root root 2134 Sep 15 03:55 cert-14739116xx.pem
lrwxrwxrwx 1 root root   19 Sep 15 03:55 cert.csr -> cert-14739116xx.csr
lrwxrwxrwx 1 root root   19 Sep 15 03:55 cert.pem -> cert-14739116xx.pem
-rw------- 1 root root 1647 Sep 15 03:55 chain-14739116xx.pem
lrwxrwxrwx 1 root root   20 Sep 15 03:55 chain.pem -> chain-14739116xx.pem
-rw------- 1 root root 3781 Sep 15 03:55 fullchain-14739116xx.pem
lrwxrwxrwx 1 root root   24 Sep 15 03:55 fullchain.pem -> fullchain-14739116xx.pem
-rw------- 1 root root 3243 Sep 15 03:22 privkey-14739097xx.pem
-rw------- 1 root root 3243 Sep 15 03:38 privkey-14739106xx.pem
-rw------- 1 root root 3243 Sep 15 03:49 privkey-14739113xx.pem
-rw------- 1 root root 3243 Sep 15 03:54 privkey-14739116xx.pem
lrwxrwxrwx 1 root root   22 Sep 15 03:55 privkey.pem -> privkey-14739116xx.pem

接著就可以修改 nginx 的 SSL 設定:
server {
    listen       80 default_server;
    listen       [::]:80 default_server;
    listen 443 default_server ssl;
    
    # other configs
    ...

    location /.well-known/acme-challenge/ {
        alias /var/www/letsencrypt/;
    }
    ssl_certificate /etc/letsencrypt.sh/certs/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt.sh/certs/yourdomain.com/privkey.pem;
}

listen 443 default_server ssl; 要記得設,不然訪問https 報ERR_CONNECTION_REFUSED 錯誤。
可以檢查443 port有沒有開
# netstat -ant | grep 443
tcp        0      0 0.0.0.0:4433            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN  # 設 listen 後才有
tcp6       0      0 :::4433                 :::*                    LISTEN

重啟nginx
# service nginx restart

配置subdomain 上SSL
server {
    listen  80;
    listen 443 ssl;
    server_name test.yourdomain.com;

    # other configs
    ...

    location /.well-known/acme-challenge/ {
        alias /var/www/letsencrypt/;
    }
    ssl_certificate /etc/letsencrypt.sh/certs/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt.sh/certs/yourdomain.com/privkey.pem;
}
用同一張證書即可

讓不同port的gitlab也掛上SSL
因為我的gitlab走的是不同的port,
在多次修改 /etc/gitlab/gitlab.rb 
external_url 'http://yourdomain.com:1234'
nginx['redirect_http_to_https'] = true
nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"
nginx['custom_gitlab_server_config']="location /.well-known/acme-challenge/ {\n alias /var/www/letsencrypt/;\n}\n"
和重啟gitlab後
# gitlab-ctl reconfigure

仍無法實現 https://yourdomain.com:1234 訪問gitlab,但是關閉系統nginx,只啟動gitlab的nginx時可以

讓cron每天自動檢查並更新
設定 /etc/cron.d/letsencrypt-yourdomain_com (因為 /etc/cron.d/ 裡面的檔名不能有 . 這個符號,用 _ 取代)
0 0 * * * root sleep $(expr $(printf "%d" "0x$(hostname | md5sum | cut -c 1-8)") % 86400); ( /etc/letsencrypt.sh/dehydrated -c -d yourdomain.com; /sbin/service nginx reload ) > /tmp/dehydrated-yourdomain.com.log 2>&1
在cron job 中 $(expr $(printf "%d" "0x$(hostname | md5sum | cut -c 1-8)") % 86400) 
設計是利用機器名稱產生出十六進位 hash 值,抓一部分轉成十進位後除以一天的秒數,得到餘數後先停這個秒數再跑 dehydrated ,這樣可以避免同時間有太多機器到 Let's Encrypt 的伺服器,造成類似 DDoS 的攻擊。

使用wireshark 查封包
選擇網卡後篩選出傳到自己主機的封包
HTTP:
http && ip.addr == x.x.x.x
HTTPS:
ssl && ip.addr == x.x.x.x
刷網頁時記得用ctrl+f5清緩存,否則封包304緩存去看是不準確的
可以發現 ssl 的封包被加密過,http的封包可以看到明文(HTML)
Linux可以用tcpdump

參考資料:
Rellik
https://letsencrypt.tw/   (主要)
https://github.com/lukas2511/dehydrated (主要)
https://blog.wu-boy.com/2015/12/letsencrypt-entering-public-beta-free-ssl/  Letsencrypt 開放申請免費 SSL 憑證
https://www.digitalocean.com/community/tutorials/how-to-create-an-ssl-certificate-on-nginx-for-ubuntu-14-04  How To Create an SSL Certificate on Nginx for Ubuntu 14.04
https://www.foolegg.com/how-to-secure-your-websites-with-lets-encrypt-certificate/  [教學] 如何使用 Let’s Encrypt 加密網站的連線
http://stackoverflow.com/questions/34189199/how-do-i-use-let-s-encrypt-with-gitlab  How do I use let’s encrypt with gitlab?
https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/nginx.md  NGINX settings
https://www.digitalocean.com/community/tutorials/how-to-secure-gitlab-with-let-s-encrypt-on-ubuntu-16-04  How To Secure GitLab with Let's Encrypt on Ubuntu 16.04













2016年8月16日 星期二

MySQL SSH Tunnel

聽Jethro和Ike討論 Naticat的強大,如:SSH Tunnel、structure sync 

因為我常用的是phpmyadmin,所以找一下SSH Tunnel + phpmyadmin的解決方法

我有一台VPS機器,ssh需要私鑰登入,MySQL port沒有對外,如何使用phpmyadmin連線?

打開ssh通道
$ ssh -N <username>@<Bastian server IP> -L 3307:<internal ip of mysql server>:3306
-N 你不執行任何命令,僅端口轉發( port forward )
3307 本地要轉發的port
Bastian server IP 必須能連到MySQL 伺服器
3306 遠端機器的MySQL端口

因為我電腦使用Windows 7 ,所以這道命令在虛擬機上下的
ex. 
$ ssh -i vps.key -N user@vps.ip -L 3307:localhost:3306
3307:localhost:3306 是指虛擬機的3307端口 轉發到 vps.ip上的localhost 3306端口

檢測
$ telnet localhost 3307
...
5.6.28-76.1-log ... mysql_native_password
VPS上的mysql版本是5.6.28 沒錯

連線
$ mysql -u root -p  -h localhost -P 3307
經過幾次測試後, -P 是無效的,因為虛擬機和VPS的MySQL密碼和版本不一樣,但是都要輸入虛擬機的密碼,只能連到虛擬機的MySQL
原因:
當使用 localhost 參數時, MySQL使用sockets。請改用127.0.0.1
$ mysql -u root -p  -h 127.0.0.1 -P 3307

後記,因為虛擬機上沒裝phpmyadmin,所以Windows 7 在 config.inc.php 設不了 127.0.0.1:3307,只能設 192.168.x.x:3307 (虛擬機IP) ,去連VPS的MySQL。但是VPS的MySQL只允許 localhost或127.0.0.1登入

結論,使用Naticat的SSH Tunnel功能在此場景會比較方便,不過私鑰記得轉成ppk去連線





2016年7月14日 星期四

xz壓縮

亞馬遜機器上有一個12G的純文字檔,現在因為亞馬遜的流出是按量收費的
所以把它壓縮後再下載,以節省流量

推薦使用 xz,壓縮比例很高(tar 不壓縮)
$ mysqldump -Aa -u root -pxxx   | xz > xxx.sql.xz

https://blog.gtwang.org/linux/linux-why-are-tar-archive-formats-switching-to-xz-compression-to-replace-bzip2-and-what-about-gzip/
$ tar -J => xz壓縮,tar 要新版才有 -J
$ tar -j => bz2壓縮
$ tar -z => gz壓縮
壓縮單檔直接用 xz

# time xz xxx.txt -T 4 --lzma2
--lzma2 => lzma2的算法
-T => muti threads,用top看 有幾棵CPU,想加快壓縮時間吃滿的話就指定線程數量
real    35m0.091s
user    134m59.372s
sys     0m6.908s
花了35分, 12G-> 746MB


解壓縮,速度比壓縮快很多,不能指定-T,只有單線程
$ time xz -d xxx.txt.xz
real    2m40.746s
user    1m12.542s
sys     0m9.335s







2016年6月30日 星期四

Linux tarball使用心得


壓縮時忽略.git資料夾和.gitignore檔案
http://stackoverflow.com/questions/984204/shell-command-to-tar-directory-excluding-certain-files-folders
$ tar zcvf project.tar.gz project/ --exclude='.git' --exclude='.gitignore'
注意:
--exclude='xxx' 要放到最後



2016年3月2日 星期三

解壓縮中文檔名亂碼

有一個資料夾,在Linux上用tar壓縮成tar.gz檔放到百度雲上後,
下載回Windows 7 後用Winrar解壓縮,發現中文檔名是亂碼

解法:
使用 7-Zip 解壓縮(tar.gz要解壓縮兩次才行,第一次會解壓縮成xxx.tar然後再解壓縮一次成為原始內容)

參考資料:
https://tw.answers.yahoo.com/question/index?qid=20100811000010KK05376  請問壓縮檔裡面的檔案名都是亂碼,怎麼解決?

2016年2月5日 星期五

ssh免密碼登入

為了安全性,我們使用ssh key 登入

使用ssh key登入有兩個方式
1. 使用本機的id_rsa和id_rsa.pub => 該組key有在server上認證(在.ssh/authorized_keys的清單中)過,
2. 使用server的id_rsa  => aws的作法:登入aws後台後,下載server上的id_rsa
請將key放到隨身碟,不要上傳到網路,要傳上網路請放到有雙因素認證的地方(輸入簡訊驗證碼和密碼兩種以上才能登入)

ssh-keygen的演算法用ecdsa還是rsa?
產生ecdsa的key
$ ssh-keygen -t ecdsa
密碼強度非常高也很難破解,改用橢圓曲線的話 ssl handshake 速度會加快 , 加解密也會快一點
產生rsa的key
$ ssh-keygen -t rsa
PuTTY Key Generator( puttygen.exe )匯入private key時,演算法只能選rsa,因為putty 不是 openssh,只是一個 ssh client
為了在windows使用putty,所以還是選擇RSA

使用server的id_rsa
(在Server上)
$ ssh-keygen -t rsa => 產生出 id_rsa, id_rsa.pub
$ cat .ssh/id_rsa.pub >> .ssh/authorized_keys => 遺漏在下一步 $ ssh -i private.key user@server_ip時會出現錯誤:Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
將id_rsa存到Win 7本機命名為private.key,然後使用cygwin
$ ssh -i private.key user@server_ip
或是使用puttygen.exe 產生Private Key( ppk 檔)後使用putty連線

使用id_rsa產生ppk
puttygen.exe => Load (id_rsa檔案) => Save private key
puttygen.exe 到 https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html 下载

使用本機的id_rsa和id_rsa.pub
(在本機)
$ ssh-keygen -t rsa
$ ssh-copy-id -i id_rsa.pub server_ip =>這步驟server必須開啟密碼登入,設定完再關閉

要關閉使用密碼登入, 只允許使用 Key 來做登入,請修改這兩個參數
# vim /etc/ssh/sshd_config
PubkeyAuthentication yes
PasswordAuthentication no
# service sshd restart

參考資料:
https://blog.longwin.com.tw/2005/12/ssh_keygen_no_passwd/  ssh keygen 免輸入密碼
https://blog.cloudflare.com/ecdsa-the-digital-signature-algorithm-of-a-better-internet/  ECDSA: The digital signature algorithm of a better internet
https://www.jianshu.com/p/d6c45729f7d0  私钥文件id_rsa转换成putty的ppk格式


2016年1月29日 星期五

Amazon EC2使用心得

前陣子為了嘗試 Amazon SES 寄送email的功能,申請了Amazon免費是用一年的帳號,申請時需驗證email、手機、信用卡(但沒要你輸入檢查碼)、信用卡帳單地址


申請一台EC2

登陸後台後,如圖:

功能太多,要從哪裡先下手?
Rellik:你要開機器不就是 ec2 和  vpc( Isolated Cloud Resources ) 先吧,先把 vpc 搞懂再來才是 ec2。
什麼是VPC?
Rellik:vpc 算是網路規劃。你要想好如果是正式服務的話要怎麼規劃網段 scale 起來比較容易。就是當你的量大起來的時候你要怎麼樣比較容易加機器或是量減少時縮減機器,因為ec2 on demand 開機器很貴,所以透過上面的一些監控機制可以做到自動增加和縮減。
好複雜喔...
Rellik:小小的複雜,但是對一般養不起 sa 的小公司( rd 自己學 )來說很有用,因為所有事情都可以透過 api 來達成,然後你就可以想辦法把這些東西自動化

選擇Compute的EC2,近入EC2 Dashboard。如圖:
1. 修改地區為東京
2. 點擊 Launch Instance去產生新機器

選主機地點?
Rellik:看你用途,因為有些 aws 的點會有特定服務還沒開通,你有需要用到那些服務的話就得選特定 region,不然就是選離自己最近的,因為 latency 越低越好
東京、首爾、新加坡、美西? 
Rellik:以東京的 scale 來說比起新加坡要大。新加坡之前有人踩到總體頻寬不足的問題。首爾的話是最近新增的 region,沒興趣踩地雷,不然韓國的網路速度應該還算蠻快的。東京的話台灣過去大概在 30~50ms
北京和香港有Amazon嗎?
Rellik:香港沒有,北京不要用,上面連個可用的 image 都沒有。http://www.amazonaws.cn/ 連domain都不一樣了,是個與世隔絕的山寨 aws
amazon有直接搬家服務?
Rellik:不清楚。但有可能是透過 s3,s3 是跨 region 的 service。他把機器打 snapshot 以後儲存到 s3,然後在東京開起來


1. Choose AMI

a. 選擇AWS Marketplace
b. 搜尋debian
c. 選擇非pvm的hvm image

如何選擇image?
Rellik:用官方的,不要用一些有人放出來的 images,一些 user 也會把自己的東西包成 ami,但是有可能被污染過,不要亂用(選 AWS Marketplace頁籤,不要選Community AMIs)
在Choose AMI中第一個Quick Start頁籤的Amazon Linux ( Amazon Linux AMI 2015.09.1 (HVM), SSD Volume Type ) 鏡像,這個好用?
Rellik:不好。amazon linux 是 亞馬遜自己開出的 linux,很近似 redhat 但很多東西都用非常的新版。不建議。可以的話 debian 或是 redhat( 要錢 )
註:雖然在 AWS Marketplace 中搜尋 red hat,會出現 Free tier eligible 標籤的red hat 鏡像,但以Red Hat Enterprise Linux (RHEL) 6 為例 ,每小時的收費是 $0.08 to $5.70/hr incl EC2 charges + other AWS usage fees。或參考下面兩張表
https://aws.amazon.com/marketplace/pp/B00WUNJIEE/ref=srh_res_product_title?ie=UTF8&sr=0-3&qid=1453969222685  Debian GNU/Linux 8 (Jessie)
https://aws.amazon.com/marketplace/pp/B007ORSS8I?ref=cns_srchrow  Red Hat Enterprise Linux (RHEL) 6
同樣micro的機器,Red Hat $0.086/hr,Debian $0.02/hr (但我不知道t1和t2的差別在哪)
Rellik:t2 micro 是最小規格機器
debian和centos哪個好?
Rellik:我會建議你用 debian,centos 找 package 找不到很煩,你如果沒有安裝 epel-relesae 的 yum repo site,你能用的東西幾近於無,我都希望只要透過 yum 能找得到的東西就直接安裝進來就好了,你就不需要管安裝 + 編譯,我有算過 centos 官方 repository .. 才收了 5000 個左右的 package,debian 官方則是有 30000 套以上。光是我弄個 smokeping  centos 就要自己編譯到死,你不會想要自己搞編譯 + dependency
在Community AMIs搜尋debian後出現多個images,如debian-jessie-amd64-hvm-2015-06-07-12-27-ebs和debian-jessie-amd64-pvm-2015-06-07-12-35-ebs。hvm  和pvm差在哪?
Rellik:用 hvm。pvm 是舊型態的 vm type。hvm 在 aws 官方文件上有推薦要你們多用這個。pvm 的話在升級 kernel 的時候會出問題
關於DB要裝哪個版本?
Rellik:建議用 percona,強烈不建議你 mariadb,踩了很多次 mariadb 地雷,官方 mysql 更是不要用,被 oracle 污染的有點嚴重。建議你安裝 mysql5.6 ( percona ),效能非常好

選擇( Select )了image後會出現每小時的收費,如圖
然後按藍色Continue按鈕進入下一步

2. Choose Instance Type

因為是免費試用一年的會員,所以只能選t2.micro。如圖
可以直接點 Review and Launch跳過 3-6的步驟

3. Configure Instance

Rellik:我建議你選 az(availability zones,Subnet那欄) 的時候選在 1b,那邊的 latency 大概在 30ms。另外要有個基本觀念:everything will fail。所以在設計的時候就要把東西盡量以 ha 架構來部署,他之所以有這麼多 region 是因為有過整個 region  fail 的情形。1 region 底下有 multilpe az,1az =  multiple IDC (機房)。所以才要你先搞懂 vpc,vpc 是關係到你的 service整個網路架構 => 他的專有名詞很多,很煩

實際跑一遍時發現沒有1b可以選,就隨便選了,點Create new subnet 後會跳到VPC那邊去

4. Add Storage

Rellik:storage type 有好幾種,你東西要關機之後可以保存著的話,要選 ebs,ebs 又分幾個 type。magnetic volume 代表是本機硬碟,但是這種 type 資料存不住不能關機,關了會消失,原因是你關機之後再開機 , 他因為是 virtual host,所以不一定會開到同樣一台。general purpose 不用算 iops ( input/output per second ) 費用,provision iops 這種會算 iops 費用。一般來說 mysql都蠻需要 iops。iops 和 硬碟 through put 有關
如圖:


好複雜...
Rellik:沒辦法,他每個都是錢,但是所有東西都可以弄成 code,包括我們整個 server 架構都可以用 json  code 來表示

5. Tag Instance

沒重點,直接下一步。如圖

6. Configure Security Group

沒重點,直接下一步。如圖

7. Review

把你前面客製化的設定列出來,可以看到我們即將建置Debian 8 t2.micro ebs hvm 每小時0收費的instance。如圖


1. 看完Review後點擊Launch,會出現lightbox(aws網頁做的怪怪的,lightbox跳出來後chrome不能複製(ctrl+c)和搜尋(ctrl+f))
2. 選擇Create a new key pair,生成後下載到電腦上(ex. key.pem)
3. Launch Instances

開始創建instance,等待...
最後出現成功的畫面

點擊View Usage Instructions查看你的instance列表
如何刪除instance?
http://serverfault.com/questions/117123/how-to-delete-instances-in-amazon-ec2-change-pair-key
give it some time. deletion of terminated instances is not a high priority task within the EC2 stack (seems reasonable to me). eventually the terminated instance will drop out of the interface.
terminate(終止)後過一段時間他會自己不見

使用PuTTY連線 Amazon EC2
Rellik:建議你機器不要開密碼登入,開 key登入比較保險(實務上不是掛vpn就是用key登陸,不讓外面的ip直接ssh來try帳號密碼),外面 ssh 通常很容易掃得到,都會有無聊人士,所以不建議用密碼登入。
http://unix.stackexchange.com/questions/116303/convert-amazon-pem-key-to-putty-ppk-key-linux
因為AWS下載的.pem檔,不能直接相容於PuTTY
1. 在AWS上下載你的.pem檔(上面步驟的key.pem)
2. 到 http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html 下載PuTTYgen,並打開他,選擇Type of key to generate為SSH-2 RSA
3. 點擊Load按鈕
4. 設定檔案類型為 *.*
5. 打開你的.pem檔
6. 點擊 Save private key ,把它存為 ppk檔
7. 打開PuTTY。Connection -> SSH -> Auth -> Private key file for authentication選擇你產生的ppk檔
8. PuTTY  Session的連線地址設。AWS Instances列表,你的機器的Public DNS
9. 連線後使用者名稱輸入admin(不能輸入root)
10. 連進去後直接 sudo su - 切換成root

申請VPC
因為免費方案不能使用VPC,他的NAT gateway是要收費的( 收費表:http://aws.amazon.com/tw/vpc/pricing/  )因次作罷

安裝nginx後訪問不到
ps aux | grep nginx 和 netstat -ant | grep 80 看起來都正常,但是外面telent x.x.x.x 80 卻連不上( telnet: Unable to connect to remote host: Connection timed out )
先在 EC2後台查詢你的instances是用哪個 Security groups ,再去左側菜單的 NETWORK & SECURITY => Security groups ,更改你的 Security groups的 inbound,
Security groups 就是 AWS的防火牆


參考資料:
Rellik Hsu