:>/dev/null

ラガードエンジニアの不撓不屈の精神/unlearning/go beyond

PHP-FPMに環境変数を渡す

centos+nginx+php-fpmで構築したサーバで外部プロキシ経由のインターネット接続設定時でのメモ。
apache+phpで構築したサーバでは「/etc/environment」を起動時に読み込み可能な為、環境変数設定が可能だが上記環境では正常に読み込まれない。
調査・対応を下記へ記載しておく。

  • 以下構築要件
    • apache+php ← 「/etc/environment」読み込まれる (env設定可能)
    • centos+nginx+php-fpm ←「/etc/environment」読み込まれない(env設定不可)
■ 改修前
$ vim www_root/index.php

$context = stream_context_create(['http' => ['timeout' => 3]]);
$content = file_get_contents('http://[DST_SRV]', false, $context);
↓
■ 改修後
nginx?php-fpm?側で/etc/environmentの設定が読み込まれない為、下記設定したが環境変数が反映されない。。
※nginx、php-fpmの各ホームディレクトリで~/.bash_profileを設置したが、こちらも反映されず。。

$ /etc/php-fpm.d/www.conf
clear_env = noの行のコメントアウトをはずして再読み込みすると解消する。
@@ -367,7 +367,7 @@
 ; Setting to "no" will make all environment variables available to PHP code
 ; via getenv(), $_ENV and $_SERVER.
 ; Default Value: yes
-;clear_env = no
+clear_env = no


上記設定で環境変数が反映されない為、confへ直接記載する。
$vim /etc/php-fpm.d/www.conf
env[HTTP_PROXY] = gwproxy.mysrv.com:3128


$ vim www_root/index.php
$proxy_context = array(
      "http" => array(
         "proxy" => "tcp://".$_SERVER['HTTP_PROXY'],
         'request_fulluri' => true,
         'timeout' => 3,
      ),
);
$context = stream_context_create($proxy_context);
$content = file_get_contents('http://[DST_SRV]', false, $context);

上記設定で外部プロキシ経由したインターネット接続が可能になります。
apache+php環境同様にアプリ側でproxyを意識せず、透過的に設定可能なら良いのですが。
curl_init関数使用した環境では、「/etc/environment」環境辺変数指定でproxy経由接続可能。file_get_contents関数を使用した場合で発生する事象と判明。関数仕様に依存した現象。
clear_env = noの行のコメントアウトをはずして再読み込みすると解消する。

$vim /etc/php-fpm.d/www.conf
clear_env = no

red)

PHP-FPMに環境変数を渡す - Qiita

Centos7でFirewalldを用いたポートフォワード設定

CentOS 7で採用されたFirewallでのポートフォワード設定を構築したのでメモしておく。
firewall-cmd –directよりfirewall-cmd –add-rich-ruleの方が個人的には分かりやすく感じたのでこちらで。

  • 以下構築要件
    • 内部ネットワークは全許可
    • 80番ポートにアクセスしてきたらsquidの3128番ポートへポートフォワード
firewall-cmd --add-masquerade
firewall-cmd --add-rich-rule="rule family="ipv4" source address="10.0.0.0/8" accept"
firewall-cmd --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" forward-port port="80" protocol="tcp" to-port="3128"'
※firewall-cmd --directの場合、[firewall-cmd --direct --add-forward-port=port=80:proto=tcp:toport=3128]

# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens160 ens192
  sources: 
  services: dhcpv6-client ssh
  ports: 
  protocols: 
  masquerade: yes
  forward-ports: 
  sourceports: 
  icmp-blocks: 
  rich rules: 
        rule family="ipv4" source address="10.0.0.0/8" accept
        rule family="ipv4" source address="10.0.0.0/8" forward-port port="80" protocol="tcp" to-port="3128"

これは”–permanent“が無いので一時的な設定になります。
firewall-cmd –reloadを実行すれば解除できます。
ルールを削除する場合、sed -i -e "s/--add-forward-port --remove-forward-port/"

参考

透過型proxyの構築まで~その2~ - いつまでも高みを目指して

Firewalldで特定のポートに特定のネットワークから許可 ← RootLinks Co., Ltd.

Centos系でのMASQUERADE構築

Centos7

●マスカレードホストルータ

  • firewallコマンドにてMASQUERADE設定
# firewall-cmd --direct --get-all-rules
firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.0.0.0/8 -j MASQUERADE
firewall-cmd --direct --add-rule ipv4 filter POSTROUTING 0 -t nat -s [src_server_gip] -j MASQUERADE
firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -o ens160 -j ACCEPT
firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i ens192 -m state --state RELATED,ESTABLISHED -j ACCEPT

※ens160:GIP,ens192:LIP
※ルール削除する場合、sed -i -e "s/--add-rule --remove-rule/"

# vim /etc/sysctl.conf
net.ipv4.ip_forward=1
  • 設定確認
# sysctl -p
net.ipv4.ip_forward=1

●適用&確認

# systemctl unmask firewalld
# systemctl enable firewalld
# systemctl start firewalld
# systemctl status firewalld

●一時的設定と恒久的設定について

設定のコマンドを説明する前に一時的設定と恒久的設定について説明していきます。

一時的設定(–permanentオプション無し)

「firewall-cmd」コマンドで設定を行う際に、「–permanent」オプションを指定しなければその設定は一時的な設定となり、サーバや>「firewalld」のサービスを再起動すると設定が消えてしまいます。

恒久的設定(–permanentオプションあり)

サーバの再起動や「firewalld」サービスの再起動で設定が消えてしまわないようにするためには、「–permanent」オプションを使用して設> 定を行う必要があります。

その際、「–permanent」オプションを指定して設定を行った場合は、そのままでは「firewalld」に設定が反映されないため「fiewall-cmd –reload」で設定を反映させる必要があります。

●子クライアント

# route add default gw [MASQUERADE_server_ip]
※削除する場合 route del default gw [MASQUERADE_server_ip]
  • ルーティングの永続化
    • /etc/sysconfig/network-scripts/route-[インタフェース名]
    • これに下記のようなルーティング情報を記載
# cat /etc/sysconfig/network-scripts/route-eth0
[dst_server_gip]/32 via [MASQUERADE_server_ip] eth0
  • 特定Dstの場合、ルーティング追加にて個別設定可能
# route add -net [dst_server_gip] netmask 255.255.255.255 gw [MASQUERADE_server_ip] eth0
  • 確認
# ip route show

Centos6

●マスカレードホストルータ

  • iptablesコマンドにてMASQUERADE設定
# iptables -t nat -I PREROUTING -i eth0 -s 172.31.0.0/16 -p tcp --dport 80 -j DNAT --to-destination [MASQUERADE_server_ip:port]

※上記で正常に動作しない場合、下記書き方も検討

# iptables -t nat -A PREROUTING -i eth0 -s ! [src_server_ip] -p tcp --dport 80 -j DNAT --to [MASQUERADE_server_ip:port]
# iptables -t nat -A POSTROUTING -o eth0 -s 172.31.0.0/16 -d [MASQUERADE_server_ip] -j SNAT --to [src_server_ip]
# iptables -A FORWARD -s 172.31.0.0/16 -d [MASQUERADE_server_ip] -i eth0 -o eth0 -p tcp --dport [MASQUERADE_server_port] -j ACCEPT

参考

firewalldの設定方法(基本設定編) | server-memo.net

squidによる多段プロキシ

多段でプロキシを組む場合、つまずいたのでメモがてら残しておく。

以下の様なパターンでアクセスが発生する。

  • PC => WWW
  • PC => PROXY (外部Proxy)(認証有) => WWW
  • PC => PROXY (イントラGW) => PROXY(外部Proxy)(認証有) => WWW

今回の目的

  • 外部Proxyサーバを経由して、アクセスさせる事により外部連携時のIP申請を省略する。
  • イントラGWを経由する事により、外部Proxyサーバの認証情報を一括管理する。
    • 各PCで外部Proxyサーバの認証情報を保持したくない。⇒セキュリティーポリシー・メンテナンス低下
  • 上記構成を実現する為、下記ネットワークを組む。
    • 各PC(ルーティング設定) ⇒ イントラGW ⇒ 外部Proxy ⇒ 外部接続

設定関連

各クライアントPC

  • OSのシステムファイルへイントラGWを指定
$ cat /etc/environment
# プロキシ設定 ==============================================
# 実際の環境変数の設定
export http_proxy="http://gwproxy.mysrv.com:3128"
export https_proxy="http://gwproxy.mysrv.com:3128"
# プロキシを利用しないアドレスの指定(必須)
export no_proxy="127.0.0.1,localhost"
export NO_PROXY="$no_proxy"

イントラGW

$ sudo vim /etc/squid/squid.conf
acl localnet src 192.168.0.0/16
http_access allow localnet
cache_peer proxy.srv.com parent 3128 0 proxy-only login=ID:PASS
never_direct allow all
never_direct allow CONNECT
visible_hostname unknown
forwarded_for off
  • cache_peer [上位プロキシの IP アドレス] parent [上位プロキシの ポート番号] [icp ポート番号] no-query [login=id:PASS]
  • proxy-only…ピアから取ってきたオブジェクトは、ローカルに保存しない
  • never_direct allow all…全てのリクエストを上位プロキシに転送する
  • never_direct allow CONNECT…社外ネットワークに接続する場合のSSL接続は、上位Proxyへパス(SSLはデフォルトで直接接続しようとする)
  • visible_hostname unknown…ホスト名の非表示
    • 「HTTP_VIA」というプロキシサーバーのホスト名を表示する環境変数を表示させない。 squid.conf では、「visible_hostname」というセクションがこれに対応しており、ここには通常は自分のホスト名を記述するのですが、「unknown」としてあたかも判別できなかったかのようにします。
  • forwarded_for off…一応IP隠す。

挙動確認

  • 各クライアントPCから下記コマンド発行
$ curl -v -H 'Cache-Control: no-cache' -L 'http://google.com/'

// 443の場合
$ git clone https://[user]@stash.test.com/src/test.git mydir

ホワイトリスト・除外リスト

never_direct

インターネット接続、つまりここまでに定義されていないドメインへのアクセスは、最終的に暗黙の転送先へ転送されます。
プロキシを使用する範囲、つまり「Exampleドメイン以外」の直接取得を禁止します。
never_direct allow yahoo
never_direct allow !example

always_direct

Exampleドメインだけは明示的に直接取得を許可します。さもないとプロキシーへ投げます。
always_direct allow example

サンプル
acl all src 0.0.0.0/0.0.0.0
acl host1 src [GIP:xxx.xxx.xxx.xxx]/255.255.255.255
acl yahoo dstdomain .yahoo.ne.jp .yimg.jp
acl google dstdomain .google.com .google.co.jp
acl mydomain dstdomain .mydomain.com .mydomain.co.jp


#always_direct allow host1
#always_direct allow yahoo
#always_direct allow google
always_direct allow !mydomain ←mydomainは親プロキシを経由。通常特定URL許可指定するが、今回は特定URLのみ親プロキシを経由する為
#always_direct allow all ←上記マッチしなかったもの、つまり「上記リストではないもの」は親プロキシを経由せず直接アクセス許可
# cat access.log
1495610456.780    126 10.131.0.206 TCP_MISS/200 103173 GET http://www.mydomain.com/ - FIRSTUP_PARENT/[親プロキシIP] text/html←親プロキシ経由
1495610490.536    204 10.131.0.206 TCP_MISS/200 46298 GET http://www.google.co.jp/? - HIER_DIRECT/[DST_IP] text/html←直接アクセス
// 443の場合
1497595884.998   2082 127.0.0.1 TCP_TUNNEL/200 4728 CONNECT stash.test.com:443 - FIRSTUP_PARENT/[親プロキシIP] -

ref)
Squid→Squidへ の多段プロキシ - それマグで!
cache_peer

HTTP proxy越しにSSHする

イントラGW

$ sudo vim /etc/squid/squid.conf

# ssh proxy
acl SSH_ports port 2222
acl Safe_ports port 2222        # ssh
http_access allow CONNECT SSH_ports

各クライアントPC

  • sshのconfig設定を使用してssh設定を行う
$ cat .ssh/config 
Host stash.test.com
        User user
        HostName stash.test.com
        Port 2222
        IdentityFile ~/.ssh/test.key
        ProxyCommand connect -H gwproxy.mysrv.com:3128 %h %p

$ chmod 600 .ssh/config
$ vim .ssh/test.key
-- 鍵内容をコピー ---
$ chmod 600 .ssh/test.key

// connectコマンドが「/bin/bash: line 0: exec: connect: not found」の場合
$ rpm -ivh http://mirror.fairway.ne.jp/dag/redhat/el6/en/x86_64/rpmforge/RPMS/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
$ rpm -ivh http://mirror.fairway.ne.jp/dag/redhat/el7/en/x86_64/rpmforge/RPMS/rpmforge-release-0.5.3-1.el7.rf.x86_64.rpm
$ yum install --enablerepo=rpmforge connect

// sshプロトコルよりソース取得
$ git clone ssh://git@stash.test.com:2222/test/test.git mydir
# cat access.log
1497509393.078      1 127.0.0.1 TCP_TUNNEL/502 0 CONNECT stash.test.com:2222 - FIRSTUP_PARENT/[親プロキシIP] - ←親プロキシ経由(親プロキシ側で拒否されている)
1498460374.471   7051 10.131.0.217 TCP_TUNNEL/200 1700614 CONNECT stash.test.com:2222 - FIRSTUP_PARENT/[親プロキシIP] - ←親プロキシ経由(正常接続)

CentOSCVSを使用する場合

proxy経由でcvsを使用する場合、cvs 1.12.7以降で対応されいる様だが
CentOS6の標準repoでは現時点(20170712)でv1.11.xしか提供されてない為、src⇒buildの必要有り。
※CentOS7系では対象ソース無し

$yum install rpm-build.x86_64 libtool zlib-devel krb5-devel pam-devel
$mkdir -p /usr/src/redhat/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
$wget -P /usr/src/redhat/SRPMS http://ftp.tmapy.cz/tmapy-twist/centos/6Server/obsolete/SRPMS/cvs-1.12.13-2.el6.1.src.rpm
$rpmbuild --rebuild /usr/src/redhat/SRPMS/cvs-1.12.13-2.el6.1.src.rpm
$rpm -ivh /root/rpmbuild/RPMS/x86_64/cvs-1.12.13-2.el6.1.x86_64.rpm
  • 挙動確認
cvs -d ":pserver;proxy=gwproxy.mysrv.com;proxyport=3128:[user]@[cvs_server]:[port]/usr/home/cvsroot" login

ref)
Ubuntu日本語フォーラム / [質問] cvs pserver proxy経由でのアクセスについて

  • エラー対応
    sshdで「refused connect from ...」で繋がらない

    • 原因
      TCP Wrapperの可能性。
----hosts.allowの内容----
ALL: 192.168.0.0/255.255.0.0
ALL: 127.0.0.1
  • 対策 hosts.allowに設定追加。
sshd: ALL

PHPのcRUL関数を用いたProxy接続

PHPでの開発時、Proxy経由で外部連携等々でcRUL接続を行う場合のサンプルコードを以下に示す。

<?php

$ch = curl_init();
$fp = fopen("/tmp/test.txt", "w");

// 通信内容を保存するためのテンポラリファイル
$errfp = tmpfile();

$loginpassw = 'ID:PASS';
$proxy_ip = 'http://proxy.test.com';
$proxy_port = '3128';
$url = 'http://www.google.com';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// proxy接続を無効にする場合、以下ブロックをコメント
curl_setopt($ch, CURLOPT_PROXYPORT, $proxy_port);
curl_setopt($ch, CURLOPT_PROXYTYPE, 'HTTP');
curl_setopt($ch, CURLOPT_PROXY, $proxy_ip);
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $loginpassw);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_STDERR, $errfp);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);



// file output
//curl_setopt($ch, CURLOPT_FILE, $fp);

$ret = curl_exec($ch);
print_r($ret);


// 記録した通信内容を読み出す
fseek($errfp, 0);
while (($line = fgets($errfp)) !== FALSE) {
    $tmp .= $line . "<br />";
}
// 通信状況を出力
echo $tmp;

curl_close($ch);
fclose($fp);
?>

参考

https://ameblo.jp/itboy/entry-11983530735.html

■wwwサーバのProfileとして読み込ませる事も可能

wwwサーバをapacheユーザーとして起動しいる場合
proxy-user = "ID:PASS"
proxy = "http://proxy.test.com:3128"

■システム全体へ適用

OS構成ファイル/etc/environmentへ配置

  • environmentファイル作成
    • $ vim /etc/environment
# プロキシ設定 ==============================================
# 実際の環境変数の設定
export http_proxy="http://ID:PASS@proxy.test.com:3128"
export https_proxy="http://ID:PASS@proxy.test.com:3128"
# 大文字バージョンしか認識しないプログラム用
export HTTP_PROXY="http://ID:PASS@proxy.test.com:3128"
export HTTPS_PROXY="http://ID:PASS@proxy.test.com:3128"
# プロキシを利用しないアドレスの指定(必須)
export no_proxy="127.0.0.1,localhost"
export NO_PROXY="$no_proxy"

上記により全てのユーザーで共通して使用可能。

■蛇足

curl の基本設定ファイルを作ることが出来る
~/.curlrc

Default config file, see -K, --config for details.

.curlrc に書く書き方は -K で指定する config ファイルと同じ

  • ①configファイル作成
    • $ vim /etc/curlrc
      • [/var/www/.curlrc]参照
  • ②configファイル指定した挙動確認
ここら辺を良しなに作成する一括設定スクリプト

下記サイト参照

http://www.magtranetwork.com/aws/batch_proxy_settings.html

中国のインターネット通信状況

中国国内からのパフォーマンス比較サイト

また別サイトの過去情報ですが、下記に調査結果を転載

<Yahoo・Googleへの上海からのアクセススピード> Yahoo・Googleへの上海からのアクセススピードを計測したところ(2/2 12:30時点)、Yahoo!JAPANのスピードは、8.3 KB/秒、Yahoo!中国雅> 虎(サーバー在中国)のスピードは、188.1 KB/秒という結果になっています。つまり、Yahoo!中国雅虎のアクセススピードは、Yahoo!JAPAN> のアクセススピードの22.6倍の速さとなっており、大きな差が生じています。

参考

https://www.value-press.com/pressrelease/34618

`

www site performance

■スピード調査方法

  • 1.以下をコピー
javascript:(function(){%20var%20d=document;%20var%20s=d.createElement('scr'+'ipt');%20s.charset='UTF-8';%20s.language='javascr'+'ipt';%20s.type='text/javascr'+'ipt';%20s.src='//web-tan.forum.impressrd.jp/tools/pagespeedtiming/pagesppedtiming.js?t='+(new%20Date()).getTime();%20d.getElementsByTagName('head')[0].appendChild(s);%20})();
  • 2.アドレスバーの[☆](星)をクリック
  • 3.[編集]ボタンをクリック
  • 4.[URL]にカーソルを移動して中身を全部消してクリップボードの内容を貼り付ける
  • 5.[名前]には「ページ速度チェック」とか適当に入れる
  • 6.完了ボタンをクリックし保存
  • 7.調査対象サイトをchromeで表示(アドレスバーに対象URLを貼り付ける)
  • 8.6で保存したブックマークを表示する
  • 9.解析結果が表示されるので保存する
    • 9-1.キーボードのctrl+Aにて全選択
    • 9-2.キーボードのctrl+Cにて全コピー
  • 10.txtエディターに貼り付ける
  • 11.貼り付け結果を調査称名で保存する

参考

http://web-tan.forum.impressrd.jp/e/2013/01/29/14562