使用免费的SSL

Standard

公司收的一大堆论坛都要加SSL,每个都要购买的话会是一笔不小的费用。
所以准备全部使用Let’s Encrypt的免费SSL。

wget -O -  https://get.acme.sh | sh
cd .acme.sh/
#确保通过域名可访问到/var/www/yemaosheng/htdocs/.well-known/下的内容
./acme.sh --issue -d yemaosheng.com -d www.yemaosheng.com -w /var/www/yemaosheng/htdocs
[Tue Mar  7 21:19:34 CST 2017] Multi domain='DNS:www.yemaosheng.com'
[Tue Mar  7 21:19:34 CST 2017] Getting domain auth token for each domain
[Tue Mar  7 21:19:34 CST 2017] Getting webroot for domain='yemaosheng.com'
[Tue Mar  7 21:19:34 CST 2017] Getting new-authz for domain='yemaosheng.com'
[Tue Mar  7 21:19:36 CST 2017] The new-authz request is ok.
[Tue Mar  7 21:19:36 CST 2017] Getting webroot for domain='www.yemaosheng.com'
[Tue Mar  7 21:19:36 CST 2017] Getting new-authz for domain='www.yemaosheng.com'
[Tue Mar  7 21:19:36 CST 2017] The new-authz request is ok.
[Tue Mar  7 21:19:37 CST 2017] yemaosheng.com is already verified, skip http-01.
[Tue Mar  7 21:19:37 CST 2017] Verifying:www.yemaosheng.com
[Tue Mar  7 21:19:39 CST 2017] Success
[Tue Mar  7 21:19:39 CST 2017] Verify finished, start to sign.
[Tue Mar  7 21:19:40 CST 2017] Cert success.
-----BEGIN CERTIFICATE-----
MIIFFzCCA............FlYV3RaDYYpw=
-----END CERTIFICATE-----
[Tue Mar  7 21:19:40 CST 2017] Your cert is in  /root/.acme.sh/yemaosheng.com/yemaosheng.com.cer 
[Tue Mar  7 21:19:40 CST 2017] Your cert key is in  /root/.acme.sh/yemaosheng.com/yemaosheng.com.key 
[Tue Mar  7 21:19:40 CST 2017] The intermediate CA cert is in  /root/.acme.sh/yemaosheng.com/ca.cer 
[Tue Mar  7 21:19:40 CST 2017] And the full chain certs is there:  /root/.acme.sh/yemaosheng.com/fullchain.cer
 
crontab -l
7 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
 
vi /etc/httpd/conf.d/ssl.conf
...
<VirtualHost *:443>
        DocumentRoot "/var/www/yemaosheng/htdocs"
        ServerName yemaosheng.com
 
        SSLEngine on
        SSLProtocol all -SSLv2 -SSLv3
        SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
        SSLCertificateFile "/root/.acme.sh/yemaosheng.com/yemaosheng.com.cer"
        SSLCertificateKeyFile "/root/.acme.sh/yemaosheng.com/yemaosheng.com.key"
        SSLCertificateChainFile "/root/.acme.sh/yemaosheng.com/fullchain.cer"
        ...
</VirtualHost>
...

How to clone a Azure VM

Standard

run on your sample-vm

waagent -deprovision+user

run on your azure-cli env

$rgName = "VMTestGroup"
$template = "Template-test.json"
$vmName = "VMTest"
$vhdName = "VHDTest"
 
azure vm deallocate -g $rgName -n $vmName
azure vm generalize $rgName -n $vmName
azure vm capture $rgName $vmName $vhdName -t $template
 
# the $template should looks like this. and you have to change 'newvmname' before use.
...
         "storageProfile": {
          "dataDisks": [
            {
              "caching": "ReadOnly",
              "vhd": {
                "uri": "https://yourdiskname.blob.core.windows.net/vhds/dataDisk-0.newvmname.vhd"
              },
              "image": {
                "uri": "https://yourdiskname.blob.core.windows.net/system/Microsoft.Compute/Images/vhds/yourcapturedvmname-dataDisk-0.ff60129b-...3cf59bf9315a.vhd"
              },
              "createOption": "FromImage",
              "name": "yourcapturedvmname-dataDisk-0.ff60129b-4ec5-4dcd-ae97-3cf59bf9315a.vhd",
              "lun": 0
            }
          ],
          "osDisk": {
            "caching": "ReadWrite",
            "vhd": {
              "uri": "https://yourdiskname.blob.core.windows.net/vhds/osDisk.newvmname.vhd"
            },
            "image": {
              "uri": "https://yourdiskname.blob.core.windows.net/system/Microsoft.Compute/Images/vhds/yourcapturedvmname-osDisk.ff60129b-...3cf59bf9315a.vhd"
            },
            "createOption": "FromImage",
            "name": "yourcapturedvmname-osDisk.ff60129b-4ec5-4dcd-ae97-3cf59bf9315a.vhd",
            "osType": "Linux"
          }
        },
...
 
 
azure group deployment create $rgName MyDeployment -f Template-test-modified.json
    info:    Executing command group deployment create
    info:    Supply values for the following parameters
    vmName: NewVmName
    adminUserName: username
    adminPassword: password
    networkInterfaceId: /subscriptions/61719d1b-...ab74b6f77865/resourceGroups/VMTestGroup/providers/Microsoft.Network/networkInterfaces/YourNetworkInterfaceName
 
#If you do not have an existing NetworkInterface, you need create first. 
azure network nic create $rgName YourNetworkInterfaceName -k default -m YourSubnetVnetName  -l "westus2"

Percona Monitoring Plugins for Zabbix3

Standard
#Install
apt-get install percona-zabbix-templates
cp /var/lib/zabbix/percona/templates/userparameter_percona_mysql.conf /etc/zabbix/zabbix_agentd.conf.d/
#Configure 
vi /var/lib/zabbix/percona/scripts/ss_get_mysql_stats.php
...
$mysql_user = 'uid';
$mysql_pass = 'pwd';
...
#Test
/var/lib/zabbix/percona/scripts/get_mysql_stats_wrapper.sh gg

zbx_percona_mysql_template

Using SaltStack to deploy Auto-scaling EC2

Standard

SaltStack Master: 172.66.1.100

Create AMI by default VM:

root@ip-x.x.x.x:~# cat /etc/rc.local
/root/PkgInit.sh;
/root/SaltMinionInit.sh;
/root/SaltCall.sh;
 
root@ip-x.x.x.x:~# cat /root/PkgInit.sh 
add-apt-repository ppa:saltstack/salt -y;
apt-get update;
apt-get install salt-minion -y;
apt-get install awscli -y;
 
root@ip-x.x.x.x:~# cat /root/SaltMinionInit.sh
INSTANCE_ID=$(ec2metadata --instance-id);
REGION=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | grep region | awk -F\" '{print $4}');
TAG=$(aws ec2 describe-tags --filters "Name=resource-id,Values=$INSTANCE_ID" --region=$REGION --output=text --max-items=1 | cut -f5);
/bin/echo -e "master: 172.66.1.100\ngrains:\n  roles:\n    - "$TAG > /etc/salt/minion;
service salt-minion restart;
 
root@ip-x.x.x.x:~# cat /root/SaltCall.sh
sleep 15s;
salt-call state.highstate;

Setup Saltstack Master:

root@ip-172-66-1-100:~# add-apt-repository ppa:saltstack/salt
root@ip-172-66-1-100:~# apt-get update
root@ip-172-66-1-100:~# apt-get install salt-master
root@ip-172-66-1-100:~# cat /etc/salt/master | grep -v '^#' | grep -v '^$'
file_roots:
  base:
    - /srv/salt
pillar_roots:
  base:
    - /srv/pillar
reactor:
  - 'salt/auth':
    - /srv/reactor/auth-pending.sls
 
# Automating Key Acceptance
# salt-run state.event pretty=True
root@ip-172-66-1-100:~# cat /srv/reactor/auth-pending.sls
{% if 'act' in data and data['act'] == 'pend' and data['id'].startswith('ip-172') %}
minion_add:
  wheel.key.accept:
    - match: {{ data['id'] }}
{% endif %}
 
# Get grains item
root@ip-172-66-1-100:~# salt '*' grains.item os
ip-172-66-2-214:
    ----------
    os:
        Ubuntu
ip-172-66-4-93:
    ----------
    os:
        Ubuntu
root@ip-172-66-1-100:/srv/reactor# salt '*' grains.item roles
ip-172-66-2-214:
    ----------
    roles:
        - YeMaosheng_com
ip-172-66-4-93:
    ----------
    roles:
        - YeMaosheng_com
 
root@ip-172-66-1-100:~# salt -G 'roles:YeMaosheng_com' state.highstate -t 60 test=True
root@ip-172-66-1-100:~# salt -G 'roles:YeMaosheng_com' state.highstate

网站所用EC2的安装及发布配置

├── pillar
│   ├── yemaosheng_com
│   │   ├── nginx.sls
│   │   ├── php56.sls
│   │   └── website.sls
│   └── top.sls
├── reactor
│   └── auth-pending.sls
└── salt
    ├── crontab
    │   └── init.sls
    ├── mysql-client
    │   └── init.sls
    ├── nginx
    │   ├── configs
    │   │   └── yemaosheng_com
    │   │       ├── blockrules.conf
    │   │       ├── nginx.conf
    │   │       └── sites-enabled
    │   │           └── yemaosheng.com
    │   └── init.sls
    ├── php56
    │   ├── configs
    │   │   └── yemaosheng_com
    │   │       └── php5-fpm
    │   │           └── www.conf
    │   └── init.sls
    ├── top.sls
    ├── website
    │   ├── configs
    │   │   └── yemaosheng_com
    │   │       ├── dhparam.pem
    │   │       └── sslkey
    │   └── init.sls
    └── websitefiles
        └── yemaosheng_com -> /var/www/yemaosheng_com
 
cat /srv/salt/top.sls 
base:
 'roles:yemaosheng_com':
 - match: grain
 - mysql-client
 - php56
 - nginx
 - website
 - crontab
 
cat /srv/pillar/top.sls 
base : 
 'roles:yemaosheng_com':
 - match: grain
 - yemaosheng_com.nginx
 - yemaosheng_com.php56
 - yemaosheng_com.website
 
cat /srv/pillar/yemaosheng_com/nginx.sls 
nginx_conf: nginx/configs/yemaosheng_com/nginx.conf
nginx_site-enable: nginx/configs/yemaosheng_com/sites-enabled
 
cat /srv/salt/nginx/init.sls 
{% set site_name = pillar['site_name'] %}
 
nginx:
  pkg:
    - name: nginx
    - installed
 
nginx_conf:
  service.running:
    - name: nginx
    - enable: True
    - reload: True
    - watch:
      - file: /etc/nginx/*
  file.managed:
    - name: /etc/nginx/nginx.conf
    - source: salt://{{ pillar['nginx_conf'] }}
    - user: root
    - group: root
    - mode: '0640'
    - require:
      - pkg: nginx
 
{% if site_name == 'yemaosheng_com' %}
upload_sslkey_to_nginx:
  file.recurse:
    - name: /srv/ssl
    - user: root
    - group: root
    - file_mode: '0644'
    - source: salt://website/configs/yemaosheng_com/sslkey
    - include_empty: True
 
upload_dhparam_to_nginx:
  file.managed:
    - name: /etc/nginx/dhparam.pem
    - source: salt://website/configs/yemaosheng_com/dhparam.pem
    - user: root
    - group: root
    - mode: '0644'
    - require:
      - pkg: nginx
{% endif %}
 
/etc/nginx/sites-enabled:
  service.running:
    - name: nginx
    - enable: True
    - reload: True
    - watch:
      - file: /etc/nginx/sites-enabled
  file.recurse:
    - name: /etc/nginx/sites-enabled
    - user: root
    - group: root
    - dir_mode: 2775
    - file_mode: '0644'
    - source: salt://{{ pillar['nginx_site-enable'] }}
    - include_empty: True
    - clean: True
    - require:
      - pkg: nginx

AWS VPC point to point with gre tunnel

Standard

related AWS VPC通过IPsec连接不同Region

AWS China EC2:

root@ip-10-33-30-103:/home/ubuntu# cat /etc/network/interfaces.d/gre1.cfg
auto gre1
iface gre1 inet tunnel
  mode gre
  netmask 255.255.255.255
  address 10.0.0.2
  dstaddr 10.0.0.1
  endpoint 52.63.189.251
  local 10.33.30.103
  ttl 255
 
root@ip-10-33-30-103:/home/ubuntu# route add -net 172.33.0.0 netmask 255.255.0.0 gw 10.0.0.2

AWS Sydney EC2:

root@ip-172-33-1-190:/home/ubuntu# cat /etc/network/interfaces.d/gre1.cfg 
auto gre1
iface gre1 inet tunnel
  mode gre
  netmask 255.255.255.255
  address 10.0.0.1
  dstaddr 10.0.0.2
  endpoint 54.222.193.171
  local 172.33.1.190
  ttl 255
 
root@ip-172-33-1-190:/home/ubuntu# route add -net 10.33.0.0 netmask 255.255.0.0 gw 10.0.0.1

Mikrotik L2TP with IPsec for mobile clients

Standard

转自: http://www.firstdigest.com/2015/01/mikrotik-l2tp-with-ipsec-for-mobile-clients/

1.Add a new pool

GUI
IP > Pool
Name: L2TP-Pool
Adresses: 172.31.86.1-172.31.86.14
Next Pool: None
 
CLI
/ip pool add name="L2TP-Pool" ranges=172.31.86.1-172.31.86.14

L2TP Configuration

1. Configure L2TP Profile

GUI
PPP > Profiles
Name: l2tp-profile
Local Address: L2TP-Pool
Remote Address: L2TP-Pool
DNS Server: 8.8.8.8
Change TCP MSS: yes
Use Encryption: required
 
CLI
/ppp profile add name=l2tp-profile local-address=L2TP-Pool remote-address=L2TP-Pool use-encryption=required change-tcp-mss=yes dns-server=8.8.8.8

2. Add a L2TP-Server

GUI
PPP > Interface > L2TP Server
Enabled: Checked
Max MTU: 1460
Max MRU: 1460
Keepalive Timeout: 30
Default Profile: mschap2
Use IPsec: Checked
IPsec Secret: MYKEY
 
CLI
/interface l2tp-server server set authentication=mschap2 default-profile=l2tp-profile enabled=yes ipsec-secret=MYKEY max-mru=1460 max-mtu=1460 use-ipsec=yes

3. Add PPP Secrets

GUI
PPP > Secrets
Enabled: Checked
Name: MYUSER
Password: MYPASSWORD
Service: l2tp
Profile: l2tp-profile
 
CLI
/ppp secret add name=MYUSER password=MYPASSWORD service=l2tp profile=l2tp-profile

IPsec Configuration

1. IPsec Proposals

GUI
IPsec > Proposals
Enabled: Checked
Name: L2TP-Proposal
Auth. Algorithm: sha1
Encr. Algorithm: 3des, aes-256 cbc
PFS Group: none
 
CLI
/ip ipsec proposal add name=L2TP-Proposal auth-algorithms=sha1 enc-algorithms=3des,aes-256-cbc pfs-group=none

2. IPsec Peers

GUI
IPsec > Peers
Enabled: Checked
Address: 0.0.0.0
Auth. Method: pre shared key
Secret: MYKEY
Policy Template Group: default
Exchange Mode: main l2tp
Send Initial Contact: Checked
NAT Traversal: Checked
My ID: auto
Proposal check: obey
Hash Algorithm: sha1
Encryption Algorithm: 3des, aes-256
DH Group: modp1024
Generate policy: port override
 
CLI
/ip ipsec peer add address=0.0.0.0/0 port=500 auth-method=pre-shared-key secret="MYKEY" generate-policy=port-override exchange-mode=main-l2tp send-initial-contact=yes nat-traversal=yes hash-algorithm=sha1 enc-algorithm=3des,aes-256 dh-group=modp1024

3. IPsec Policies

GUI
Enabled: Checked
Src. Address: ::/0
Dst. Address: ::/0
Protocol: 255(all)
Template: Checked
Group: default
Action: encrypt
Level: require
IPsec Protocols: esp
Tunnel: Not checked
SA Src. Address: 0.0.0.0
SA Dsr. Address: 0.0.0.0
Proposal: L2TP-Proposal
 
CLI
/ip ipsec policy add src-address=::/0 dst-address=::/0 protocol=all template=yes group=default action=encrypt level=require ipsec-protocols=esp tunnel=no sa-src-address=0.0.0.0 sa-dst-address=0.0.0.0 proposal=L2TP-Proposal

PS:
因为同事们在家里连国外的VPN不太稳,所以用它从园区分给公司的IP上绕一绕。
具体可见之前发的那贴: http://yemaosheng.com/?p=1587

网站指向不同路径的nginx配置

Standard
upstream fastcgi_backend {
    server 127.0.0.1:9000;
    server unix:/var/run/php5-fpm.sock;
    keepalive 10;
}
...
server {
  ...
  ...
  location ~ \.php {
    set $php_root /var/www/website/abc/public;
    include /etc/nginx/fastcgi_params;
 
    if ($request_uri ~ /(api/user/photos|api/user/posts) ) {
      set $php_root /var/www/website/rest/public;
    }
 
    if ($request_uri ~ /api/user/(photos|posts|links) ) {
      set $php_root /var/www/website/rest/public;
    }
 
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED $php_root$fastcgi_path_info;
    fastcgi_param SCRIPT_NAME $fastcgi_script_name;
    fastcgi_param SCRIPT_FILENAME $php_root$fastcgi_script_name;
    fastcgi_pass fastcgi_backend;
    fastcgi_index index.php;
  }
  ...
}

Add basic HTTP access auth via HAProxy

Standard
userlist UsersForES
  user your_username insecure-password your_password
 
frontend elasticsearch_pwd
    bind *:9201
    mode http
    default_backend es-nodes_pwd
 
backend es-nodes_pwd
    acl AuthOkay_ES http_auth(UsersForES)
    http-request auth realm ES if !AuthOkay_ES
    mode http
    balance roundrobin
    option forwardfor
    server es-node1.yemaosheng.com 10.0.0.2:9200 check
    server es-node2.yemaosheng.com 10.0.0.3:9200 check
    server es-node3.yemaosheng.com 10.0.0.4:9200 check

haproxy cfg for redis sentinel

Standard
frontend redis-cluster
        mode tcp
        option tcplog
        bind *:6379
        # If at least 3 sentinels agree with the redis host that it is master, use it.
        use_backend redis-node1 if { srv_is_up(redis-node1/redis-1:10.25.0.2:6379) } { nbsrv(check_master_redis-1) ge 3 }            
        use_backend redis-node2 if { srv_is_up(redis-node2/redis-2:10.25.0.3:6379) } { nbsrv(check_master_redis-2) ge 3 }
        # If sentinel cant tell us, well, fall back to master detection
        default_backend redis-cluster
 
backend redis-node1
        mode tcp
        balance first
        option tcp-check
        tcp-check send AUTH\ password\r\n
        tcp-check expect string +OK
        tcp-check send info\ replication\r\n
        tcp-check expect string role:master
        server redis-1:10.25.0.2:6379 10.25.0.2:6379 maxconn 5000 check inter 1s
 
backend redis-node2
        mode tcp
        balance first
        option tcp-check
        tcp-check send AUTH\ password\r\n
        tcp-check expect string +OK
        tcp-check send info\ replication\r\n
        tcp-check expect string role:master
        server redis-2:10.25.0.3:6379 10.25.0.3:6379 maxconn 5000 check inter 1s
 
backend redis-cluster
        mode tcp
        balance first
        option tcp-check
        tcp-check send AUTH\ password\r\n
        tcp-check expect string +OK
        tcp-check send info\ replication\r\n
        tcp-check expect string role:master
        tcp-check send info\ persistence\r\n           
        tcp-check expect string loading:0
        server redis-1:10.25.0.2:6379 10.25.0.2:6379 maxconn 5000 check inter 1s
        server redis-2:10.25.0.3:6379 10.25.0.3:6379 maxconn 5000 check inter 1s
 
## Check 4 sentinels to see if they think redis-1 (10.25.0.2) is master
backend check_master_redis-1
        mode tcp
        option tcp-check
        tcp-check send PING\r\n
        tcp-check expect string +PONG
        tcp-check send SENTINEL\ master\ redis\r\n
        tcp-check expect string 10.25.0.2
        tcp-check send QUIT\r\n
        tcp-check expect string +OK
 
        server redis-1:10.25.0.2:26379 10.25.0.2:26379 check inter 2s
        server redis-2:10.25.0.3:26379 10.25.0.3:26379 check inter 2s
        server redis-sentinel1:10.25.0.4:26379 10.25.0.4:26379 check inter 2s
        server redis-sentinel2:10.25.0.5:26379 10.25.0.5:26379 check inter 2s
 
## Check 4 sentinels to see if they think redis-2 (10.25.0.3) is master
backend check_master_redis-2
        mode tcp
        option tcp-check
        tcp-check send PING\r\n
        tcp-check expect string +PONG
        tcp-check send SENTINEL\ master\ redis\r\n
        tcp-check expect string 10.25.0.3
        tcp-check send QUIT\r\n
        tcp-check expect string +OK
 
        server redis-1:10.25.0.2:26379 10.25.0.2:26379 check inter 2s
        server redis-2:10.25.0.3:26379 10.25.0.3:26379 check inter 2s
        server redis-sentinel1:10.25.0.4:26379 10.25.0.4:26379 check inter 2s
        server redis-sentinel2:10.25.0.5:26379 10.25.0.5:26379 check inter 2s

AWS Cloudwatch query script for Zabbix

Standard
#!/usr/bin/python
import boto.ec2.cloudwatch
import sys
import datetime
 
try:
    metName = sys.argv[1]
    funcName = sys.argv[2]
    dimSpace = sys.argv[3]
    region = sys.argv[4]
    accessKey = sys.argv[5]
    secretKey = sys.argv[6]
 
except:
    print "Usage: GetFromCloudwatch.py MetricName Function Dimension Region AWS_ACCESS_KEY AWS_SECRET_ACCESS_KEY"
    print "Example: GetFromCloudwatch.py FreeableMemory Average \"CacheClusterId=ElsticCacheName\" us-east-1 ACCESS_KEY SECRET_ACCESS_KEY"
    print "         GetFromCloudwatch.py CPUUtilization Average \"DBInstanceIdentifier=RDSName\" us-east-1 ACCESS_KEY SECRET_ACCESS_KEY"
    print "         GetFromCloudwatch.py ApproximateNumberOfMessagesVisible Average \"QueueName=SQSName\" us-east-1 ACCESS_KEY SECRET_ACCESS_KEY"
    sys.exit(1)
 
dim = {}
firstSplit = dimSpace.split(',')
for word in firstSplit:
    secondSplit = word.split('=')
    dim[secondSplit[0]] = secondSplit[1]
 
regions = boto.ec2.cloudwatch.regions()
 
reg = ''
for r in regions:
    if region == r.name:
        reg = r
 
c = boto.ec2.cloudwatch.CloudWatchConnection(aws_access_key_id=accessKey, aws_secret_access_key=secretKey, region=reg)
metrics = c.list_metrics(dimensions=dim)
 
end = datetime.datetime.utcnow()
start = end - datetime.timedelta(minutes=15)
 
dataPoints = [];
for met in metrics:
    if met.name == metName:
        dataPoints = met.query(start, end, funcName)
 
if len(dataPoints) > 0:
    max = datetime.datetime.utcnow() - datetime.timedelta(hours=1)
    index = 0
    for i in range(0,len(dataPoints)):
        if max < dataPoints[i][u'Timestamp']:
            max = dataPoints[i][u'Timestamp']
            index = i
    for key in dataPoints[index].keys():
        if funcName in key:
            value = dataPoints[index][key]
    print value
else:
    print 'Error! No response from Amazon.'
    sys.exit(2)