存档

‘Linux’ 分类的存档

nginx跨域设置

2018年6月27日 没有评论

跨域问题在现在前后端分离的项目中是一个很常见的问题,以前我写过一篇《nginx反向代理解决跨域问题》的文章。前段时间在做nginx配置允许跨域时一直失败,参考的是segmentflaut上面的一篇文章,尝试了许久都没有成功,搞的我都有点开始怀疑人生了。

后来我去查看了一下nginx官方add_header的文档,发现它教程中放在location块中是没有问题的,add_header支持放在”httpserverlocationif in location“,也就是不仅可以放在location中,也可以放在location中的if块里面。那么到底哪里出了问题哪?

在一篇叫《Using CORS》文章中,作者提到”Access-Control-Allow-Origin (required) – This header must be included in all valid CORS responses。”,也就是说我们必须要保证所有cors请求都要返回我们设置的header,而”location /”是一个默认的匹配块,如果匹配到其他块,那么 我们设置在location中的跨域header设置就会无效了,于是就做了下面的改动。

在nginx配置文件下面增加cors.conf配置文件,内容如下:

add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

if ($request_method = 'OPTIONS') {
    return 204;
}

然后在server块中include进来跨域配置文件:

location / {
       index  index.html index.htm index.php;
       autoindex on;
       try_files $uri $uri/ /index.php?$query_string;
}

include cors.conf;

这样在其他的网站配置文件中只需要 “include cors.conf”即可。当然如果你也可以直接用cors.conf配置文件里面的内容替换”include cors.conf”。重启nginx,就成功可以让js跨域请求了啊!

nginx反向代理解决跨域问题

2018年3月28日 没有评论

现在随着前端技术的发展,前端渲染模板越来成熟,前后端的分离就变得越来越普遍了。其中一个很目标的问题就是跨域问题,这里就不展开跨域问题了。以前常见的解决办法是在返回的header部分增加”‘Access-Control-Allow-*”系列header来解决问题。以前我也写过一篇类似的文章《ajax跨域解决方案-Cross Origin Resource Sharing》,感兴趣的话可以去看看一下。今天要说的是利用nginx的反向代理来解决这个问题。

现在我们有2个站点,front.aaa.com和api.aaa.com。假设这里我们2个站点都用nginx搭建,front.aaa.com的nginx配置文件为front.conf,api.aaa.com的nginx的配置文件为api.conf。当front站点的页面ajax访问api站点的时候就会起因这个跨域问题。我们在front站点配置1个针对api的反向代理,配置如下:

server {
     ....
       location /api/ {
            rewrite ^/api/(.*) /$1 break;
            proxy_pass http://api.aaa.com;
        }
        ....

}

如此一来所有访问api的接口我们可以同构http://front.aaa.com/api/{realApi}来实现对后端接口的访问。

分类: Linux, nginx, Web 标签:

yum安装elasticsearch

2018年3月13日 没有评论

centos环境下面安装elasticsearch(后面用es代称)有多重方法,可以yum、rpm包或者源码。今天就简单说一下yum安装es的过程,而且也推荐这么做,可以方便的通过systemd系列命令管理es。

安装依赖

这里面真正需要的是java,但是如果你不安装java其实也可以安装成功,不过安装插件时会有问题,所以我们先安装java。

yum install java

 配置官方yum源

我们可以通过官方提供的源来安装,所以我们先配置官方源。

[elasticsearch-6.x]
name=Elasticsearch repository for 6.x packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

安装Elasticsearch

然后更新本地yum缓存,安装es。

yum makecache
yum install elasticsearch

 安装中文分词插件

这里的中文分词插件选择analysis-ik,我们通过elasticsearch-plugin命令来安装。首先我们需要知道命令的位置,默认是在”/usr/share/elasticsearch/bin/elasticsearch-plugin”.

cd /usr/share/elasticsearch
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.2/elasticsearch-analysis-ik-6.2.2.zip

  启动ES

下面我们启动es,查看是否安装成功。

 systemctl start elasticsearch

用curl访问9200端口,查看服务是否正常。

curl http://127.0.0.1:9200
#看到下面内容,说明es启动正常
{
  "name" : "id7JTQQ",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "0JLalDUYS_y1FFEsLFsqlg",
  "version" : {
    "number" : "6.2.2",
    "build_hash" : "10b1edd",
    "build_date" : "2018-02-16T19:01:30.685723Z",
    "build_snapshot" : false,
    "lucene_version" : "7.2.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

 查看ES安装插件

访问“http://127.0.0.1:9200/_cat/plugins”可以查看es安装的插件。

curl http://127.0.0.1:9200/_cat/plugins

至此,我们的es安装初步完成了,开始使用它吧!

分类: Linux 标签:

php-memcached扩展安装

2017年11月3日 没有评论

由于服务器上的php-memcached的序列化处理使用的是igbinary,而本地使用的是php默认的,在本地跑线上环境代码的时候就遇到问题了。具体是查看错误日志看到如下信息:

'ErrorException' with message 'Memcached::get(): could not unserialize value, no 
igbinary support'

查看memcached的igbinary support发现值是”no”,由于以前没自己动手搞过这块的东西。看了官方配置手册以后,以为只需要在配置文件中把”memcached.serializer”的配置设置为igbinary就可以了那。但是修改以后发现并没有作用。

接下来查看了一下扩展的编译参数,发现有个选项是”–enable-memcached-igbinary”,另外2个类似的参数分别是”–enable-memcached-json” 和”–enable-memcached-msgpack”.现在就找到了问题所在,需要重新重新编译memcached扩展以支持igbinary。

开始编译,编译参数如下:

./configure --enable-memcached --enable-memcached-igbinary --with-php-config=
/usr/local/bin/php-config

但是很不幸,并没有如期待的那样编译成功,遇到如下错误:

"./php_memcached.h:23:10: fatal error: 'Zend/zend_smart_str.h' file not found
#include "Zend/zend_smart_str.h""

搜索了整个电脑硬盘,也没有找到这个头文件。打开php-memcached在github上的项目地址,发现它在readme里面说3.x版本是支持php7的,而php5.2-5.6需要使用2.x版本,所以就从github上的release历史里面下载了php-memcached2.2版本,当然从php官方地址也是可以下载到相应的版本的。我特地下载了php7.1.11的源码查看了一下,果然有缺失的头文件。

接下来安装上面的编译参数再次进行编译,就成功了。

分类: Linux, PHP 标签:

redis批量删除key

2017年10月23日 没有评论

最近生产环境的redis服务器由于key过期不及时,现在发现时key的个数已经暴增到5000多万了。然后运维同学那边就报警了,最大内存12G,已经用了9G多了,正好下面快要双11了,让我们快些解决。

redis服务器里面堆积大量的队列状态相关的key,其实这些key可以设置有效期,或者任务完成以后删除或者过期,但是由于我们使用类库的问题,这些key既没有删除也没有过期,堆积到redis里面去了,现在我们要做的就是删除这些无用key。在删除这些keys的过程中,走了不少弯路,这里说一下我最终采用的方案。

redis的del函数可以删除单个key,也可以删除多个key,del函数官方文档可以看这里。在google之后看到目前网络上很多文章的思路是使用keys匹配返回要删除的key,然后调用del函数去删除。这种方案在数据量较小时无可厚非,但如果像我这样面临的处理的数据有5千W时,keys的阻塞问题可能会给线上生产环境带来致命的问题。所以我们需要对这种方案作出一些修改。

可喜的是自从2.8.0以后redis提供scan来遍历key,而且这个过程是非阻塞,不会影响线上生产环境。最终经过修改的方案是用scan遍历要删除的key,然后调用del删除。

下面是我用python写的用来删除key的脚本。

import sys,redis

r = redis.Redis(host="127.0.0.1", port=6379,db=0)

if  len(sys.argv) <= 1:
    print("必须指明匹配key字符串")
    exit(1)
pattern = sys.argv[1]

cursor = 0
num = 1
while 1 :
    resut = r.scan(cursor, pattern, 10000)
    del_keys = []
    for i in resut[1]:
        key = i.decode()
        del_keys.append(key)
    #print("del keys len :%d" % len(result))
    if len(del_keys) == 0:
        break
    r.delete(*del_keys)
    cursor = resut[0]
    print("delete keys num : %dw" % (num))
    num +=1

print("done\n")

如何利用我这个脚本删除符合某个规则的key哪,如以king开头的key?

下面的命令即可完成上面的问题。

python3 main.py "king*"

期间我看到网上利用keys+del的lua脚本的方案,花了一段时间把scan+del改成lua脚本来删除。但是可惜的是目前redis并不支持这么做,由于scan返回的结果是不确定的,所以禁止在其后直接调用del操作。

参考资料:《How to atomically delete keys matching a pattern using Redis》

分类: Linux, Python 标签:

centos7防火墙firewalld

2017年10月19日 没有评论

centos7防火墙管理工具由我们以前熟知的iptables转变为了firewall。那么firewall是什么哪?firewall的服务是firewalld (防火墙守护)服务,引入了一个信任级别的概念来管理与之相关联的连接与接口。它支持 ipv4 与 ipv6,并支持网桥,采用 firewall-cmd (command) 或 firewall-config (gui) 来动态的管理 kernel netfilter 的临时或永久的接口规则,并实时生效而无需重启服务。

区域(zone)

Firewall 能将不同的网络连接归类到不同的信任级别.

区域 默认规则策略
trusted 允许所有的数据包。
home 拒绝流入的数据包,除非与输出流量数据包相关或是ssh,mdns,ipp-client,samba-client与dhcpv6-client服务则允许。
internal 等同于home区域
work 拒绝流入的数据包,除非与输出流量数据包相关或是ssh,ipp-client与dhcpv6-client服务则允许。
public 拒绝流入的数据包,除非与输出流量数据包相关或是ssh,dhcpv6-client服务则允许。
external 拒绝流入的数据包,除非与输出流量数据包相关或是ssh服务则允许。
dmz 拒绝流入的数据包,除非与输出流量数据包相关或是ssh服务则允许。
block 拒绝流入的数据包,除非与输出流量数据包相关。
drop 拒绝流入的数据包,除非与输出流量数据包相关。

过滤规则

source 根据源地址过滤
interface 根据网卡过滤
service 根据服务名过滤
port 根据端口过滤
icmp-block icmp 报文过滤,按照 icmp 类型配置
masquerade ip 地址伪装
forward-port 端口转发
rule 自定义规则

管理firewalld服务

# systemctl start firewalld         # 启动,
# systemctl enable firewalld        # 开机启动
# systemctl stop firewalld          # 关闭
# systemctl disable firewalld       # 取消开机启动

接下来我们会重点来看一下firewall-cmd命令,它是我们配置firewall的核心命令。

firewall-cmd

我们可以通过”firewall-cmd –help”来查看完整的命令帮助文档。

参数 作用
–get-default-zone 查询默认的区域名称。
–set-default-zone=<区域名称> 设置默认的区域,永久生效。
–get-zones 显示可用的区域。
–get-services 显示预先定义的服务。
–get-active-zones 显示当前正在使用的区域与网卡名称。
–add-source= 将来源于此IP或子网的流量导向指定的区域。
–remove-source= 不再将此IP或子网的流量导向某个指定区域。
–add-interface=<网卡名称> 将来自于该网卡的所有流量都导向某个指定区域。
–change-interface=<网卡名称> 将某个网卡与区域做关联。
–list-all 显示当前区域的网卡配置参数,资源,端口以及服务等信息。
–list-all-zones 显示所有区域的网卡配置参数,资源,端口以及服务等信息。
–add-service=<服务名> 设置默认区域允许该服务的流量。
–add-port=<端口号/协议> 允许默认区域允许该端口的流量。
–remove-service=<服务名> 设置默认区域不再允许该服务的流量。
–remove-port=<端口号/协议> 允许默认区域不再允许该端口的流量。
–reload 让“永久生效”的配置规则立即生效,覆盖当前的。

查看运行状态:

[root:~]# firewall-cmd –state
running

查看当前的区域:

[root:~]# firewall-cmd –get-default-zone
public

查看已被激活的区域信息:

[root:~]# firewall-cmd –get-active-zones
public
interfaces: eth0

查询eth0网卡的区域:

[root:~]# firewall-cmd –get-zone-of-interface=eth0
public

在public中分别查询ssh与http服务是否被允许:


[root:~]# firewall-cmd --zone=public --query-service=ssh
yes
[root:~]# firewall-cmd --zone=public --query-service=http
no

查看指定级别的接口:

[root:~]# firewall-cmd –zone=public –list-interfaces
ens33

查看指定级别的所有信息:


[root:~]# firewall-cmd --zone=public --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: ens33
sources:
services: dhcpv6-client ssh
ports:
protocols:
masquerade: no
forward-ports:
sourceports:
icmp-blocks:
rich rules:

查看所有级别被允许的信息:

[root:~]# firewall-cmd –get-service

RH-Satellite-6 amanda-client … xmpp-server

管理规则:


# firewall-cmd --panic-on # 丢弃
# firewall-cmd --panic-off # 取消丢弃
# firewall-cmd --query-panic # 查看丢弃状态
# firewall-cmd --reload # 更新规则,不重启服务
# firewall-cmd --complete-reload # 更新规则,重启服务

添加某接口至某信任等级,譬如添加 eth0 至 public,永久修改:

# firewall-cmd –zone=public –add-interface=eth0 –permanent

设置默认的信任级别:

[root:~]# firewall-cmd –set-default-zone=public
success

允许https服务流量通过public区域,要求立即生效且永久有效:

[root:~]# firewall-cmd –zone=public –add-service=https –permanent
success

不再允许http服务流量通过public区域,要求立即生效且永久生效:

[root:~]# firewall-cmd –zone=public –remove-service=http –permanent
success

允许 tcp 端口 8080 至 dmz 级别:

[root:~]# firewall-cmd –zone=dmz –add-port=8080/tcp
success

列出 dmz 级别的被允许的进入端口:

[root:~]# firewall-cmd –zone=dmz –list-ports

8080/tcp

允许某范围的 udp 端口至 public 级别,并永久生效:

[root:~]# firewall-cmd –zone=public –add-port=5000-6000/udp –permanent
success

改变ens33接口的区域

[root:~]# firewall-cmd –zone=work –change-interface=ens33 –permanent
success

删除 public zone 中的 eth0:

[root:~]# firewall-cmd –zone=public –remove-interface=eth0 –permanent
success

打开ip伪装:

[root:~]# firewall-cmd –zone=external –add-masquerade
success

关闭ip伪装:

[root:~]# firewall-cmd –zone=external –remove-masquerade

打开端口转发:

[root:~]# firewall-cmd –zone=public –add-masquerade

转发 tcp 22 端口至 3753

[root:~]#firewall-cmd –zone=public –add-forward-port=port=22:proto=tcp:toport=3753

转发22 端口数据至另一个 ip 的相同端口上:

[root:~]#firewall-cmd –zone=public –add-forward-port=port=22:proto=tcp:toaddr=192.168.1.100

转发 22 端口数据至另一 ip 的 2055 端口上:

[root:~]#firewall-cmd –zone=public –add-forward-port=port=22:proto=tcp:toport=2055:toaddr=192.168.1.100

封禁 ip:


[root:~]#firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='222.222.222.222' reject"

通过 ipset 来封禁 ip:


[root:~]#firewall-cmd --permanent --zone=public --new-ipset=blacklist --type=hash:ip

[root:~]#firewall-cmd --permanent --zone=public --ipset=blacklist --add-entry=222.222.222.222

参考文章:

《CentOS 7 下使用 Firewall》

《CentOS7-firewall防火墙使用》

分类: Linux 标签: ,

log4cpp简明教程

2017年10月13日 没有评论

log4cpp是一款c++开源的日志库,我也是刚刚使用,所以对它的了解不是很多。这是第一次在项目中使用log4cpp,当然我在c++方面的项目经验也是屈指可数。这篇文章会是一个简明的教程,方便类似我这样的新手可以快速入门,不会有太高深的内容。log4cpp相关的背景和特点这里也不再多说,感兴趣的可自行查找资料。

基本步骤

1、实例化1个appender对象

2、实例化1个layout对象,并将layout绑定到appender

3、获得Category并设置优先级和添加apprender

4、调用Category写日志

参考代码

这是1个根据日期划分日志文件的简单样例。main.cpp代码

#include <iostream>
#include <log4cpp/Category.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/DailyRollingFileAppender.hh>

using namespace std;
using namespace log4cpp;

int main() {
     DailyRollingFileAppender *appender = new DailyRollingFileAppender(
         string("default"),
         string("/Users/king/c_project/logger/build/log/data.log")
     );
     string patter = "%d[%p] %m%n";
     PatternLayout *layout = new PatternLayout();
     layout->setConversionPattern(patter);
     appender->setLayout(layout);
     Category& root = Category::getRoot();
     root.addAppender(appender);
     root.info("This is test.");
     root.error("sql error.");

     cout << "done!" << endl;
     return 0;
}

这里保存目录如果要指定日志保存目录,请使用绝对路径。

编译链接


c++ main.cpp -o logger -llog4cpp

./logger

分类: C/C++, Linux 标签:

php-fpm配置unixsock引发问题

2017年10月11日 没有评论

今天把博客从原来的阿里云迁移出来了,在新环境搭建环境时,nginx和php-fpm都已经配好的时候(其实还是有问题的),访问首页提示403错误。nginx和fpm的用户都配置为www-data,按道理说同一用户不应该没有访问文件的权限。以前nginx和fpm一直都是使用socket通信的方式,第一次使用unixsock方式配置,有点不知所措。

查看nginx的错误日志,发现最新的错误日志信息是类似这样的:

connect() to unix:/var/run/php-fpm.sock failed (13: Permission denied) while connecting to upstream

也就说出问题的地方是/var/run/php-fpm.sock文件,不是站点目录下文件的权限。在google上面搜索了一下,在stackoverflow上面发现一篇“nginx error connect to php5-fpm.sock failed (13: Permission denied)”,也是unixsock方式配置nginx和php-fpm的问题。问题里面给说的方案是需要设置一下unixsock中listen.user、listen.group、listen.mode这几个参数,按照默认的值将其前面的注释去掉即可,类似如下。


listen.owner = www-data
listen.group = www-data
listen.mode = 0660

然后重启php-fpm,重新访问页面,一切正常了。

分类: Linux, PHP 标签:

git reflog恢复git reset删除数据

2017年5月11日 没有评论

我经常用git reset来恢复自己的工作区,但是偶尔也会失误把错误的分支的commit记录给删除掉了。今天工作中也有遇到一次,本来要删除测试分支的commit记录,但是在操作时没有注意所在的分支,就把工作分支的内容误删除掉了。那么我们如何恢复这些commit记录哪?

当你 (在一个仓库下) 工作时,Git 会在你每次修改了 HEAD 时悄悄地将改动记录下来。当你提交或修改分支时,reflog 就会更新。因此我们就可以用reflog的记录来恢复我们的工作区。

查看reflog记录


git reflog

你会看到如下的内容:

229e8d31 HEAD@{1}: pull origin xx: Fast-forward
fd54ce35 HEAD@{2}: checkout: moving from xxx to xxxx
66010f88 HEAD@{3}: merge xxxxx8: Merge made by the 'recursive' strategy.
085b2dba HEAD@{4}: reset: moving to HEAD~1
0f0bfb7d HEAD@{5}: checkout: moving from xxxx to xxxxx
73e400ba HEAD@{6}: commit: xxxxxx
5e9d0305 HEAD@{7}: reset: moving to HEAD~1
2ef40139 HEAD@{8}: reset: moving to 2ef40139
5e9d0305 HEAD@{9}: reset: moving to HEAD~1
2ef40139 HEAD@{10}: checkout: moving from sit to xxx
0f0bfb7d HEAD@{11}: merge xxx: Merge made by the 'recursive' strategy.

恢复工作区
我们可以根据commit的SHA来用git reset恢复。

git reset --hard fd54ce35

这时我们被我们误操作的记录就已经被恢复了,可以用git log来查看git提交记录。

分类: git, Linux 标签:

centos7安装redis3.2

2016年9月27日 没有评论

最近在学习laravel框架,打算在虚拟机里面装个redis,使用yum安装时发现提供的版本是2.8。目前最新的版本是3.2,而3.0以后redis提供了cluster,对集群有很好的支持。在google了一番以后也没有找到redis3.2的源,于是就开始编译安装了。

redis官网下载最新版本的redis源码,然后开始编译安装,可以参考源码里面的README。


wget http://download.redis.io/releases/redis-3.2.4.tar.gz

tar -xvf redis-3.2.4.tar.gz

cd redis-3.2.4

cat README.md

make

make install

mkdir /etc/redis

cp utils/redis.conf /etc/redis/

redis-server /etc/redis/redis.conf

这时候用安装基本完成了,但是上面安装基本上按照默认的方式安装,但是有些地方可以自定义。比如redis安装位置,可以使用`make PREFIX=/some/other/directory install`,其中的“/some/other/directory”就是redis安装位置。

为了方面我们管理redis,我们可以写一个redis.service配置文件来方便我们管理redis。

这里我就给一个很简单的service配置文件例子:


[Unit]
Description=redis service file
Wants=network.target

[Service]
Type=forking
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
[Install]
WantedBy=multi-user.target

将上面的配置信息放入/lib/systemd/system/redis.service文件中,然后重新载入配置文件即可。还有一点就是需要修改/etc/redis/redis.conf中,将damonize改为yes,默认为no,即以守护进程的模式启动redis。


systemctl daemon-reload

#开机启动

systemctl enable redis.service

#启动redis

systemctl start redis.service

#关闭redis

systemctl stop redis.service

到此,redis的安装就完成了,可以使用redis-cli链接server了!

分类: Linux 标签: