全局命令 :g
在 Vim 中有着意想不到强大的功能。当想要在整个文件中对于匹配的行或者不匹配行进行一些操作时,应该第一时间想到这个 :g
命令。
:[range]global[!]/{pattern}/{command}
简写可以写成
:[range]g/pattern/command
vglobal
整个命令可以理解成,在 range 范围内匹配 patter 的行执行 Ex command。所有的 Ex command 可以使用 :help ex-cmd
来查看。
常用的 Ex command 可以参考如下例子:
比如在 20 行到 200 行之间,每一行下插入空行
:20,200g/^/pu _
最简单的使用
:g/pattern/d
会删除 pattern 批量的行,再比如
:g/^$/d
可以用来删除空白行。
匹配使用 :g
,而不匹配有两种写法:
:g!/pattern/d
:v/pattern/d
:v
是 :in(v)erse
的缩写,如果为了记忆的话,可以记住 inverse。
Vim 在删除操作时,会先把要删除的内容放到寄存器中,假如没有指定寄存器,会默认放到一个未命名的寄存器中,对于要删除大量匹配行的行为,可能导致 Vim 花一些时间处理这些拷贝,避免花费不必要的时间可以指定一个 blackhole 寄存器 _
。
:g/pattern/d_
将所有匹配的行移动到文件的末尾
:g/pattern/m$
将所有匹配的行复制到文件末尾
:g/pattern/t$
Vim 每个字母都是一个寄存器,所以使用全局命令也可以将内容复制到某一个寄存器,比如 a
qaq:g/pattern/y A
qaq
清空寄存器 a,qa
开始记录命令到a寄存器,q
停止记录y A
将匹配的行 A (append) 追加到寄存器 a 中存放到 a 寄存器之后就可以使用 "ap
来粘贴使用或者其他操作了。
just show the power of :g
:g/^/m0
:g
命令一行行匹配,匹配第一行时将第一行 m0
放到文件顶部,第二行放到文件顶部,当跑完一遍之后整个文件的每一行就反转了。
使用 s
命令可以实现,同样使用全局 g
命令也可以实现同样的效果
:g/pattern/s/$/mytext
这里使用到了 s
命令, substitute 命令,可以使用 :help :s
来查看。
Kibana 的查询语法基于 Lucene 的查询语法,他允许 boolean 值,通配符,过滤器等等操作。
通常一个查询会包含一个或者多个单词或者组合。一个简单的查询语句就是用引号包含的一组词,比如 “search demo”.
如果不包含双引号,Kibana 会单独的去匹配每一个词。
大部分正则表达式是允许匹配部分字符的,然而在 Lucene 中,正则表达式用来匹配整个字符串,比如 abcde
这个字符串
ab.*
能够匹配abcd
是不能匹配的正则表达式中,有一些保留字符
. ? + * | { } [ ] ( ) " \
这些字符如果出现在表达式中都需要进行转义,比如 \*
,或者 \\
这些符号的含义和正则表达式一致
.
用来表示任意字符?
用来表示前面的字符重复一次或零次+
表示前面的字符重复一次或多次*
表示前面的字符重复零次或多次{n}
表示重复n次{n,m}
表示重复n到m次()
表示 group, 组合其他使用|
表示 OR 或者,(http|https)
http 或者 https 匹配[]
表示括号中的任意一个更多的关于正则表达式的内容可以参考任意一本关于正则的书。
补充,在 Kibana 中如下字符都需要转义
+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /
比如查询 (1+1)=2
需要使用 \(1\+1\)\=2
Lucene 中还能够开启一些扩展操作。
Complement 模式
比如 ab~cd
可以表示字符串以 ab 开始接着跟随一个任意长度非c字符,以d结尾的字符串。
Interval
使用 <>
来匹配数字范围, 比如 foo<1-100>
可以匹配string foo90
却不能匹配 foo101
Intersection
符号 &
用来连接两个 patterns 两个正则表达式都需要匹配
Any string
符号 @
用来匹配所有,和 Intersection 联合使用可以用来表示,匹配所有除了。
比如 @&~(foo.*)
用来匹配所有字符,除了以 foo
开头的字符
范围查询用来查询一定范围的匹配,比如
ResponseTime: [10 TO *]
用来查询请求时间大于等于 10 ms 的,或者使用 ResponseTime: {10 TO *}
来匹配大于 10 ms 的。
方括号可以表示包括,花括号不包括,所以 [10 TO 50}
表示 需要 10<=value<50
。
也可以简化写成
age:(>=10 AND <50)
这样
逻辑运算 AND、OR、NOT 可以用来组合查询语句,这三个运算符必须 大写 ,更多内容可以查看 Lucene 语法。
+
搜索结果中必须包含此项-
不能含有此项比如需要查询 status
为 active
的内容,可以
status:active
在短语后面加 ~
可以搜到被隔开或者顺序不同的单词。
比如 “where select”~5, 表示 select 和 where 中间可以相隔5个单词。
ack 是一个代码搜索工具,作者 厌烦了 grep 复杂的语法,所以创造了 ack 来解决痛点。ack 使用 Perl 语言开发,使用友好,速度快。ack 在大量代码文件中的搜索效率极高。
sudo apt-get install ack-grep
默认情况下 ack-grep
会搜索当前目录下所有文件内容,只要包含关键字就会输出。
ack-grep keyword
ack-grep -l keyword # 只显示文件名
ack-grep -i keyword # 忽略大小写
ack-grep -w keyword # 强制要求 PATTERN 匹配整个单词
可以代替 find 加 grep,其实 ack 的 -f
选项表示的是打印所有将要被搜索的文件,事实上不会执行搜索,如果后面加 PATTERN ,那么就在路径中搜索文件名。-g
选项表示的是搜索当前路径下的符合 PATTERN 的文件。
ack-grep -f filename
ack-grep -g file*
可以使用 --python
选项来指定在 python 文件中搜索
ack-grep --python keyword
使用编译安装 Nginx,将 ngx_http_substitutions_filter_module
和 ngx_http_google_filter_module
两个模块编译进 Nginx。具体内容可以参考安装篇。
对于 Nginx 基本设置可以参考 配置篇 .
这篇主要演示 Nginx 作为一个反向代理服务器的基本设置。
Nginx 反向代理最重要的一个配置就是 proxy_pass
,该配置接受一个参数, URL ,也就是 Nginx 转发的目的地。Nginx 会自动将请求的 URI 替换为 proxy_pass
配置的 URI。
location /uri {
proxy_pass http://localhost:8083/newUri;
}
反向代理的常用配置选项
Directive | Explanation |
---|---|
proxy_connect_timeout |
向上游服务器请求超时时间 |
proxy_cookie_domain |
将请求头中 Set-Cookie 头内容替换成新域名 |
proxy_cookie_path |
替换 Set-Cookie 中路径 |
proxy_headers_hash_bucket_size |
请求头名最大size |
proxy_headers_hash_max_size |
从上游服务器接收到的所有 headers 总量 |
proxy_hide_header |
一组不会被传给 client 的 headers |
proxy_http_version |
和上游服务器通信使用的 HTTP 协议版本 |
proxy_ignore_client_abort |
如果设置为 on, Nginx 在client 停止请求时不会停止向上游服务器请求 |
proxy_ignore_headers |
处理上游服务器返回时设置一组不处理 headers |
proxy_intercept_errors |
设置开启, Nginx 将显示 error_page 配置的错误而不会向上游服务器请求 |
proxy_max_temp_file_size |
The maximum size of the overflow file, written when the response doesn’t fit into memory buffers. |
proxy_pass |
上游服务器 URL |
proxy_pass_header |
覆盖被 proxy_hide_header 配置禁用的 headers,允许他们发送给客户端 |
proxy_pass_request_body |
off 时阻止向上游服务器发送请求body |
proxy_pass_request_headers |
off 时阻止向上游服务器发送 headers |
proxy_read_timeout |
连接关闭前,向上游服务器两次读成功耗时 |
proxy_redirect |
Rewrites the Location and Refresh headers received from the upstream servers; useful for working around assumptions made by an application framework. |
proxy_send_timeout |
连接关闭前,向上游服务器两次写成功耗时 |
proxy_set_body |
修改请求body |
proxy_set_header |
修改请求 headers |
proxy_temp_file_write_size |
限制单个请求的临时文件大小, Nginx 不会在一个请求上被 block |
proxy_temp_path |
临时文件地址 |
Directive | Explanation |
---|---|
ip_hash |
使得客户端的请求能够均匀的分布 |
keepalive |
每一个 worker process 向上游服务器请求缓存的连接数,proxy_http_version 需要设置为 1.1 并且 proxy_set_header 设置为空 |
least_conn |
负载均衡算法,根据 active 连接数来选择下一个连接 |
server |
设置地址,域名或者 IP,或者 Unix-domain socket 一些选项 weight: 设置 server 的权重,max_fails : 重试最大次数,fail_timeout : 服务器超过该时间会被标记为 Down ,backup : 只有其他机器都 Down 情况下才会使用该服务器,down : 标记为 down 不会处理请求 |
以如下配置示例
upstream apache {
server 127.0.0.1:8080;
keepalive 32;
}
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://apache;
}
假设定义了 apache upstream ,使用 Nginx 转发到本地 8080 端口, 设置了 keepalive 为 32。每一个 Nginx worker 只会在最初始化时TCP握手建立32个连接,Nginx 会保存连接,不会发送 close
。
如果需要超过 32 个连接, Nginx 会再新建连接满足需求,如果需求降低, Nginx 会自动将超过 32 个连接的请求,按照最近使用的连接关闭,直到将连接数降到 32 。
upstream 模块会使用三种算法来选择向哪一台上游服务器建立连接—- round-robin, IP hash, 或者是 least connections.
round-robin 算法是默认值,算法根据上一次选择的服务器决定下一次选择哪一条连接,算法公平的根据 turn by turn 的方式来保持平衡。
IP hash 算法,需要通过 ip_hash
指令开启
Nginx 使用 IPv4 地址的前三个字节或者是整个 IPv6 地址作为 hashing key 。因此一组IP地址永远被map到特定的上游服务器。因此这个机制不是设计为均匀分发请求,而是被设计成将客户端和上游服务器映射到一起。
第三种负载均衡算法叫做 least connections , 通过 least_conn
开启。该算法设计成将负载均匀的打到上游服务器中,通过选择活跃连接数最小的服务器。如果上游服务器不是具有相同的处理能力,可以通过指定 weight
来人为处理。算法会将不同 weight 的服务器纳入计算活跃连接数的考虑范畴。
创建一个 Ngixn 虚拟主机,我使用 https://g.einverne.info
来演示:
# 配置 google ip 地址,使用 nslookup google.com 来获取 Google 服务器地址,避免 Google 机器人检测
upstream www.google.com {
server XXX.XXX.XXX.XXX:443 weight=1; #把XXX替换成可用 IP
server XXX.XXX.XXX.XXX:443 weight=1;
server XXX.XXX.XXX.XXX:443 weight=1;
server XXX.XXX.XXX.XXX:443 weight=1;
server XXX.XXX.XXX.XXX:443 weight=1;
server XXX.XXX.XXX.XXX:443 weight=1;
server 216.58.216.163:443 weight=1; #hk
}
server {
listen 80;
listen [::]:80;
server_name g.einverne.info;
listen 443 ssl;
ssl_certificate path_to_ssl_crt; # 证书
ssl_certificate_key path_key; # key
# 自动 http 转 https
if ($scheme != "https") {
return 301 https://$host$request_uri;
}
if ($http_user_agent ~* (baiduspider|360spider|haosouspider|googlebot|soso|bing|sogou|yahoo|sohu-search|yodao|YoudaoBot|robozilla|msnbot|MJ12bot|NHN|Twiceler)) {
return 403;
}
# 编译时加入 ngx_http_google_filter_module 模块,location 如下设置
location / {
google on;
}
access_log /var/log/nginx/g.einverne.info.access.log;
error_log /var/log/nginx/g.einverne.info.error.log;
}
如果编译时没有加入 ngx_http_google_filter_module
模块,则需要设置 location
location / {
proxy_redirect off;
proxy_cookie_domain google.com <domain.name>;
proxy_pass https://www.google.com;
proxy_connect_timeout 60s;
proxy_read_timeout 5400s;
proxy_send_timeout 5400s;
proxy_set_header Host "www.google.com";
proxy_set_header User-Agent $http_user_agent;
proxy_set_header Referer https://www.google.com;
proxy_set_header Accept-Encoding "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Accept-Language "zh-CN";
proxy_set_header Cookie "PREF=ID=047808f19f6de346:U=0f62f33dd8549d11:FF=2:LD=en-US:NW=1:TM=1325338577:LM=1332142444:GM=1:SG=2:S=rE0SyJh2W1IQ-Maw";
subs_filter https://www.google.com.hk <domain.name>;
subs_filter https://www.google.com <domain.name>;
#subs_filter_types text/css text/xml text/javascript;
sub_filter_once off;
}
proxy_redirect
设置为 off ,不需要重写 Location 的 headerproxy-cookie-domain google <domain.name>;
将cookie作用域替换成自己的域名proxy_pass https://www.google.com;
反向代理到 upstream www.google.comproxy_set_header Accept-Encoding "";
防止谷歌返回压缩的内容,否则内容无法替换proxy_set_header Cookie
这一行 禁止即时搜索,设置为新窗口打开网站subs_filter https://www.google.com <domain.name>;
把Google域名替换,需要编译时加上 --with-http_sub_module
参数Nginx 的相关介绍及安装可以参考之前的一篇文章
Nginx 相关的配置, Nginx 中的配置有两种分类,一种为单纯的指令 (directive),另一种为上下文配置块 (configuration context)。
指令 (directive),包含名称和参数名,以分号结束,比如
gzip on;
上下文通常声明一个作用域,比如 server 块
server {
listen 80;
}
在上下文中使用相同的指令时需要小心,一般子级上下文中的指令会覆盖父级中定义的值。
Nginx 的全局配置是影响整个 WEB 服务器的配置。
主要有以下几个
Directive | Explanation |
---|---|
user | worker process 在配置的 user and group 下运行 |
workr_processes | 最多的 worker processes 数量,可支持并发数,通常的做法是指定和 CPU cores 数量一致 |
error_log | log |
pid | file where the process ID of the main process is written |
use | 连接方式 |
worker_connections | 连接数 |
设置用户的配置
user user [group];
希望所有用户都可以启动 Nginx 进程,一种是直接注释该配置,或者
user nobody nobody;
Nginx 配置文件中,每一条配置都必须以分号结束。
worker process 是 Nginx 并发关键所在,理论上 worker process 值越大,可支持并发数也越多,但实际也受到软件,操作系统,硬件(CPU 和磁盘)等资源的制约。
worker_processes number | auto;
Nginx 进程作为系统守护进程运行,在文件中保存当前运行程序主进程号,支持配置 PID
pid file_path;
file_path
为存放路径和文件名全局块、http 块 和 server 块都可以对 Nginx 日志进行配置
error_log file | stderr [debug | info | notice | warn | error |crit | alert | emerg];
Nginx 日志支持输出到文件 file, 或者标准错误输出 stderr.
日志级别可选,从低到高 debug, info, notice, warn, error, crit, alert, emerg ,需要注意的是 debug 需要编译时使用 --with-debug
开启。
Nginx 提供 include 配置来引入其他文件
include file;
设置每一个 worker process 同时开启的最大连接数
worker_connections number;
只能在 events 块中配置
浏览器使用 MIME Type 来区分不同的媒体类型, Nginx 作为 Web 服务器,必须能够识别前端请求的资源类型。
默认的配置中,可以使用两种方式来配置
include mime.types;
default_type application/octet-stream
第一种方式引用外部文件。
mime.types
文件
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
image/svg+xml svg svgz;
image/webp webp;
application/font-woff woff;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.wap.wmlc wmlc;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}
文件中包含了浏览器能够识别的 MIME 类型,以及对应的文件后缀名。
第二种方式使用 default_type mime-type
直接配置。
与 error_log
不同的是,Nginx 进程运行时访问日志,由 Nginx 提供服务过程中应答前端请求的日志。
Nginx 服务器支持对服务日志的格式、大小、输出等进行配置,需要使用两个配置 access_log
和 log_format
access_log path [format [buffer=size]];
log_format
配置指定好,直接引用格式名如果要取消记录日志功能,使用
access_log off;
自定义日志格式
log_format name string ...;
示例,配置如下两行
log_format exampleLog '$remote_addr - [$time_local] $request '
'$status $body_bytes_sent '
'$http_referer $http_user_agent';
access_log /var/log/nginx/access.log exampleLog;
查看日志 tailf /var/log/nginx/access.log
47.88.236.38 - [24/Oct/2017:10:25:30 +0800] GET /post/2017/10/things-to-do-after-install-wordpress.html?ajax_load=page HTTP/1.1 200 6961 https://www.einverne.info/ Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
可以查看到上面格式的日志,IP 本地时间 请求方法 请求路径 HTTP 状态 发送数据大小 以及 HTTP refer 和 User Agent
.
用户连接会话连接后, Nginx 服务器可以保持打开一段时间
keepalive_timeout timeout [header_timeout];
header_timeout
可选,在 Response 头部 Keep-Alive
域设置超时时间示例
keepalive_timeout 120s 100s;
限制用户通过某一个连接向 Nginx 发送请求次数
keepalive_requests number;
虚拟主机配置以 server
开头,server 内的配置都认为是 虚拟主机 配置。虚拟主机定义了一套由不同 server_name
配置区分的资源。虚拟主机一般由 listen
、server_name
等一组配置决定。
监听配置方法主要有三种:
第一种配置监听 IP 地址
listen address[:port] [default_server] [setfib=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [deferred] [accept_filter=filter] [bind] [ssl];
第二种配置监听端口
listen port [default_server] [setfib=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [ssl];
第三种配置 UNIX Domain Socket
listen unix:path [default_server] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ssl];
default_server
将虚拟主机地址设置为 address:port 为默认主机是指 server 块对外提供虚拟主机
server_name name ...;
名字就是域名,用空格隔开
server_name einverne.info www.einverne.info;
Nginx 规定第一个名称作为虚拟主机的主要名
name 中可以使用通配符 *
,但通配符只能放到首尾,name 中还能使用正则表达式,使用 ~
开始
server_name ~^ww\d+\.einverne\.info$;
匹配 ww1.einverne.info
但不匹配 www.einverne.info
对于不同的匹配方式,Nginx 按照如下优先级选择虚拟主机
server_name
server_name
成功server_name
成功在以上四种匹配方式中,如果 server_name
被处于同一优先级匹配方式匹配多次成功,则首次匹配成功的虚拟主机处理请求。
不是很常用,暂时略
location 指令在 virtual server 部分使用,用来比欧式 URI 怎么处理。
语法
location [ = | ~ | ~* | ^~ ] uri { ... }
其中,uri 变量是待匹配的请求字符串,可以是不含正则表达的字符串。
方括号中为可选项,不添加可选项时, Nginx 首先在 server 块多个 location 块中搜索是否有匹配,如果有多个匹配,就记录匹配度最高的一个。然后,Nginx 再用 location 块中的正则 uri 和请求匹配,当第一个正则匹配成功,结束搜索,并使用该 location 块处理请求,如果正则全部失败,则使用刚才记录的匹配度最高的 location 块处理该请求。
了解了 location 块匹配规则,再来看一下各个可选项的含义:
=
用于非正则 uri 前,要求字符串与 uri 严格匹配,如果匹配成功,则停止向下搜索,并立即处理此请求~
表示该 uri 包含正则,并且区分大小写~*
表示 uri 包含正则,不区分大小写^~
用于非正则 uri 前,Nginx 服务器找到标示 uri 和请求字符串匹配程度最高的 location 后立即使用该 location 处理请求,不再匹配 location 块的正则 url如果 uri 包含正则,则必须使用 ~
和 ~*
。 而对于 ^~
会对 uri 中的 urlencode 内容解码, %20
会被理解为空格。
Nginx 接受到请求之后,在服务器指定目录中寻求资源
root path;
path 为 Nginx 接受到请求之后查找资源的根目录路径。 path 变量可以包含 Nginx 服务器预设的大多数变量,但要注意 $document_root
和 $realpath_root
不可用。
该配置可以再 http 块、 server 块或者 location 块中进行配置。
在 location 块中,除了使用 root 命令指明请求处理根目录,还可以使用 alias 配置来改变 location 接收到的 URI 请求
alias path;
path 就是修改后的根路径。
示例
location ~ ^/data/(.+\.(htm|html)) $ {
alias /var/www/data/$1;
}
当 location 块接收到 /data/index.html
请求时,匹配成功,根据 alias 配置, Nginx 在 /var/www/data/
目录下找到 index.html
并响应请求。
在用户发出请求时,请求地址可以不填写首页完整路径
index file ...;
指定错误页面
error_page code ... [=[response]] uri
示例
error_page 404 /404.html
Nginx 支持两种途径的基本访问控制,一种是由 HTTP 标准模块的 ngx_http_access-modele
支持,通过 IP 来判断客户端是否拥有对 Nginx 的访问权限
allow 配置用于设置 Nginx 客户端 IP 访问
allow address | CIDR | all;
deny 配置,顾名思义
deny address | CIDR | all;
参数含义同上
Nginx 对于访问控制权限是顺序匹配,如果匹配成功就不会继续向下解析。
Nginx 支持 HTTP Basic Authentication 协议的认证,该协议是一种 HTTP 性质的认证办法,需要用户名和密码,认证失败的客户端不拥有访问 Nginx 服务器的权限。
开启或者关闭
auth_basic string | off;
off 关闭该功能
auth_basic_user_file file;
其中 file 为密码文件的绝对路径
使用如下命令创建用户名密码到文件
printf "yourusername:$(openssl passwd -apr1)" > /etc/nginx/passwords
记住替换 yourusername
,该命令会在 /etc/nginx
目录下创建 passwords 文件,该文件的格式为
yourusername:passwordencrypt
也可以使用 htpasswd
命令来生成,绝大部分语言提供 crypt()
函数来对加密密码
htpasswd -c -d /etc/nginx/passwords yourusername
然后添加如下配置
server {
# ...
auth_basic "Protected";
auth_basic_user_file passwords;
# ...
}
简单配置
server
{
listen 80;
server_name g.einverne.info;
location / {
proxy_pass http://www.google.com/; #反代的域名
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Ubuntu 下,GnuPG 2.0 的支持都在 gnupg2
这个 packages 下,通过下面命令安装:
sudo apt-get install gnupg2
GitHub 要求使用 GnuPG 2.1 及以后的版本。
在 Mac 下需要安装:
brew install gnupg
brew link --overwrite gnupg
brew install pinentry-mac # 密码输入管理器
然后在 shell 配置 (.bashrc
或 ~/.zshrc
) 中添加 export GPG_TTY=$(tty)
.
添加配置
echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
killall gpg-agent
然后可以通过 echo "test" | gpg --clearsign
来验证一下。
Mac 下应该会弹出 GUI 窗口进行密码验证。
然后不要忘记配置 git config:
git config --global gpg.program gpg # 配置全局的 gpg
git config --global commit.gpgsign true # 配置每一个 commit 都需要 gpg
这里需要注意的一点是 Mac 下命令还叫做 gpg,但是在 Linux 下是 gpg2.
使用如下命令生成签名:
gpg2 --full-gen-key
如果遇到尝试卡在生成签名的步骤,提示
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
可能需要安装 rng-tools
sudo apt install rng-tools
之后在执行上面的命令。
使用以下命令查看本地密钥
gpg2 --list-keys --keyid-format LONG
结果
/home/einverne/.gnupg/pubring.gpg
---------------------------
pub rsa4096/F80B65AAAAAAAAAA 2018-01-31 [SC]
uid [ultimate] Ein Verne (co) <email@address>
sub rsa4096/B63A4CAAAAAAAAAA 2018-01-31 [E]
将其中的第三行 sec 中 rsa4096
后面的 ID 记住,拷贝出来。
然后使用
gpg2 --armor --export ID | xclip -sel c
来获取 GPG KEY,拷贝 -----BEGIN PGP PUBLIC KEY BLOCK-----
和 -----END PGP PUBLIC KEY BLOCK-----
之前,包括这两行的内容到 GitHub。
使用 | xclip -sel c
可以直接将命令输出结果拷贝到系统粘贴板。
产生 GPG,并且已经添加到 GitHub 后台,那么需要本地配置,告诉 git 本地签名。查看本地 gpg
gpg2 --list-keys --keyid-format LONG
添加配置,这里记得使用公钥
# 设置 gitconfig 配置签名的公钥 key
git config --global user.signingkey F80B65AAAAAAAAAA
# 设置签名使用的 gpg 软件
git config --global gpg.program gpg2
# 默认全部签名
git config --global commit.gpgsign true
将 GPG 添加到 bashrc
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc
在提交时使用 -S
选项
git commit -S -m your commit message
来本地签名提交
提交标签同理
git tag -s mytag
可以使用 -v
来验证
git tag -v mytag
生成 gpg key
gpg2 --full-generate-key
列出本地所有公钥
gpg2 --list-keys
查看秘钥
gpg2 --list-secret-keys
删除 uid 私钥
gpg2 --delete-secret-keys [uid]
删除 uid 公钥
gpg2 --delete-keys [uid]
使用过程中遇到的一些问题
在 git commit -S
时如果遇到:
gpg: signing failed: Operation cancelled
gpg: signing failed: Operation cancelled
error: gpg failed to sign the data
fatal: failed to write commit object
尝试
export GPG_TTY=$(tty)
git config --global commit.gpgsign true
对应如果选择关闭就直接使用 false 即可。
在一台电脑中生成的 gpg secret key 可以用于不同的电脑
gpg2 --list-secret-keys
来确认本机的私钥,需要记住私钥的 ID (在第二列)gpg2 --export-secret-keys $ID > my-private-key.asc
gpg2 --import my-private-key.asc
如果在第二台机器中已经有了公钥,私钥,那么需要分别删除 gpg2 --delete-keys
和 gpg2 --delete-secret-keys
如果熟悉 scp 可以直接将 ~/.gnupg
目录复制到新机器中:
scp -rp ~/.gnupg name@server_ip:~/
把 Spring 版本从 3.2.x 升级到了4.x ,这里记录一下。
Java 8 Support, 从 4.0 开始支持 Java 8,可以使用 lambda 表达式,等等 Java 8 的特性
Groovy DSL
新增 @RestController 注解,这样就不需要每个方法都使用 @ResponseBody
了。
更多内容可以查看: https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/htmlsingle/#spring-whats-new
加入spring-context-support,以前3的版本不用加,但是4要加上,否则就会报 ClassNotFoundException,
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
更换Spring jackson依赖,Spring MVC返回 json 的时候需要依赖jackson的jar包,以前是codehaus.jackson,现在换成了fasterxml.jackson 同时修改配置文件
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.0</version>
</dependency>
同时还要修改Spring的配置文件
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="stringHttpMessageConverter" />
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
</list>
</property>
</bean>
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
更换springxsd文件的版本,直接从 3.0 升级到 4.0 即可
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
修改quarz版本,用2以上的版本,maven依赖如下
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.2</version>
</dependency>
nodejs 安装其实非常简单,大部分情况下 Debian/Ubuntu 下只要使用包管理直接安装
sudo apt-get install nodejs
sudo apt-get install npm
即可。
可是今天网络环境太差,不是 npm package not found 就是 update 半天不动。
官网 提供的安装方式
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs
也是网络环境无法安装
所以使用 二进制 安装
在官网 https://nodejs.org/en/download/ 找到编译好的二进制文件
然后解压到 /usr/local
目录下
然后配置 vim ~/.zshrc
export NODE_HOME=/usr/local/node-v6.11.4-linux-x64/
export PATH=$NODE_HOME/bin:$PATH
使用命令检查
node -v
npm -v
输出即可。
在编写定时备份脚本时遇到一个需求,就是在 Bash 脚本中发送带附件的邮件。于是找到了 mutt。
Mutt 是一个命令行的邮件客户端,Mutt 能够轻松地在命令行发送和读取邮件。 Mutt 支持 POP 和 IMAP 协议。 尽管 Mutt 是基于命令的,但也同样有一个友好的界面。
如果不使用界面,使用 Mutt 命令发邮件也非常方便,只需要一条命令即可发送或者批量发送邮件。
E-mail 管理程序。
语法
mutt [-hnpRvxz][-a 文件][-b 地址][-c 地址][-f 邮件文件][-F 配置文件][-H 邮件草稿][-i 文件][-m 类型][-s 主题] 邮件地址
补充说明:mutt 是一个文字模式的邮件管理程序,提供了全屏幕的操作界面。
参数:
-a
文件 在邮件中加上附加文件。-b
地址 指定密件副本的收信人地址。-c
地址 指定副本的收信人地址。-f
邮件文件 指定要载入的邮件文件。-F
配置文件 指定 mutt 程序的设置文件,而不读取预设的.muttrc 文件。-h
显示帮助。-H
邮件草稿 将指定的邮件草稿送出。-i
文件 将指定文件插入邮件内文中。-m
类型 指定预设的邮件信箱类型。-n
不要去读取程序培植文件 (/etc/Muttrc)。-p
在 mutt 中编辑完邮件后,而不想将邮件立即送出,可将该邮件暂缓寄出。-R
以只读的方式开启邮件文件。-s
主题 指定邮件的主题。-v
显示 mutt 的版本信息以及当初编译此文件时所给予的参数。-x
模拟 mailx 的编辑方式。-z
与 -f 参数一并使用时,若邮件文件中没有邮件即不启动 mutt。Debian/Ubuntu/Linux Mint 安装
sudo apt-get install -y mutt
发送一封简单的邮件(可能会被主流邮箱认为垃圾邮件,垃圾箱查看一下)
echo "Email body" | mutt -s "Email Title" root@einverne.info
进入命令行交互界面之后使用如下快捷键操作
t
改变接受者邮件地址c
改变 Cc 地址a
来增加附件q
退出y
来发送邮件发送带附件的邮件
echo "body" | mutt -s "mysql backup" root@einverne.info -a /mysql.tar.gz
读取文本中的信息作为内容
mutt -s "Test" xxxx@qq.com
添加多个附件
echo "body" | mutt -s "web backup" root@einverne.info -a /mysql.tar.gz -a /web.tar.gz
抄送和密送
echo "body" | mutt -s "title" -c cc@gmail.com -b bcc@gmail.com root@einverne.info
-c
来抄送-b
来添加密送-s
来添加标题-a
来添加附件设置发件人
编辑配置文件
vi /etc/Muttrc
添加如下内容,防止被作为垃圾邮件
set from="mutt@einverne.info"
set use_from=yes
set envelope_from="yes"
set realname="Ein Verne"
mutt@einverne.info 为发信地址
mutt 发送邮件略慢,需要等待一分钟或者更长才能发送成功,作为备份工具好好利用。
Podcast 作为一种特殊的借助声音传播的媒体,有着特定的适用场景和范围。对于我来说每当我需要放空我自己,而又需要使用眼睛和手的时候,比如长时间走路,开车,再比如乘坐地铁等等情况下都会不自觉的打开一集播客。对于固定时间的上下班时间会听固定时长差不多在 1h 左右的内容,而其他时刻根据不同的时长可能会有短到 10 分钟,或者长 30 分钟的内容。
拿播客跟传统电台广播相比,播客的制作可能会更加精良,主题更加集中,信息密度更大一些,大部分往往是针对某一个话题进行介绍或者讨论。
推荐使用通用性客户端订阅收听,比如 Google Podcasts,或者 Pocket Casts 等等,后文有整理。
反派影评:个人看电影比较多,从偶然听到一期“观影风向标”开始就一直追随者波米到了“反派影评”,这些年陆陆续续也听过不少影评类节目,但只有反派让我一直坚持到现在仍然每期必听。如果你是一个观影爱好者,那就一定不能错过这一档节目。反派影评在 Podcast 上只更新长节目,短节目还是要上微信公众号的。
Self-Hosted 是一个关于如何自建各种服务,将自己的数字生活以及产生的数据自我管理的播客。
这是一个和 Python 相关的播客,但是又不止于 Python,还包括 Data Science,AI,Web development 等等话题。
This American Life is an American weekly hour-long radio program produced in collaboration with Chicago Public Media and hosted by Ira Glass. It is broadcast on numerous public radio stations in the United States and internationally, and is also available as a free weekly podcast.
学习基础韩国语的节目
从传统意义上这应该算是讲座了,因为《[[通往奴役之路]]》而在 YouTube 上得知这一个主题的演讲,所以下载之后转成音频在路上听了。演讲者是西北政法大学的副教授谌洪果,因为一些缘故辞职了。所以我们才能在 YouTube 上看到这一个系列的讲座,主讲的材料是基于《牛津人文通识》这样一套书籍,这一系列的书大多都是哲学类,或者哲学家相关的书籍,当然也有比如现代日本,美国大法官之类。这一个系列的讲座每一期围绕一本书进行一段分享,YouTube 上的内容不全,不过也陆陆续续听了 24 期,可以说每一期都非常值得听,现在依然记忆深刻的有,哈耶克的,美国最高法院,现代日本等等话题。
Acquired 是一个关注科技圈成功的收购和上市的节目,两位主持人 David 和 Ben 在投资界都有一定的经验 1, 能够听出来每一期节目都有非常充足的材料。有的时候他们也会分析一些国内的成功投资经验,比如 Tencent,Xiaomi,Alibaba 等等,也有一些非常热门的话题比如 Tesla,GitHub etc。
听“两个中老年人程序员” 聊天。
内核恐慌主持人 Rio 的另一档节目,年初刚开始听,果然质量还是不错的
这是一档由 The Verge 推出的播客节目,听的第一期是因为想要了解更多关于 Airbnb 的内容,于是搜到了创始人 Brain Chesky 的访谈,发现这档节目不错
听不同人讲自己的故事。
青岛刘伟品质旅游主播的一档节目,主播是一位从事多年日本旅游工作的导游,从日本文化,历史,饮食,等等方面对日本做出一些介绍。当时就是随心所听,节目不长,声音录制设备也不是很好,但是内容短小精湛非常不错,在主播的推荐下陆陆续续接触了日本文化,甚至看了《日本论》《静观日本》等等书籍。
主播本人是一位职业导游,从 90 十年代开始从事中日导游,翻译工作,给国人定制深度旅游,也接待日方游客。节目内容重在文化,历史,从历史文化中了解日本人的礼仪,美学等等方面。
主题不固定,主要在于媒体,投资,互联网等等
或许直接去看讲述日本的书,要比直接听这个要好很多。个人不是非常喜欢这个频道。
这是一档台湾人做的双语国际新闻平台,当然听到后期就会发现主播们打着双语的旗号,其实更多的是在“聊天”,或者用他们自己的话说,就是“讲干话”。当然继续收听他们的节目主要是主播二人非常有趣。
国际新闻,双语,读书,闲聊,台湾
每一期会分享一本图书
朋友推荐,听了多抓鱼创始人的一集,确实不错,可以选择自己喜欢的话题和主题来听。通常情况下一集大概半个小时左右,会邀请以为专业人士就某一个话题进行演讲,看成是国内复刻版的 TED 吧。
看名字就知道是和桌游相关的内容了
一档和哲学,政治,经济,平民文化相关的电台
一档英语影评节目
时政
美国政治
综合新闻
纽约时报的 The Daily 专题报道
ABC The Dropout 听深度报道
欧洲政局变化
这档节目来自 NPR,绝对的明星节目。每期不到 30 分钟,把抽象的经济理论和政治决议与日常生活的种种现象结合,或者通过一个普通的生活事例分析出里面蕴含的经济学道理。听这档节目会上瘾。
每个人都个人的喜好,网上很多 list 也不都是我最喜欢的博客,我觉得能够找到方法找到自己喜欢的某一类播客就是很好的,授人以鱼不如授人以渔,就是这样,但是这些我听过,并不是非常喜欢的播客我也列出来,喜不喜欢可以自行判断。
早之前在 Android 的时候买过 Pocket Cast 可是竟然发现这家每个平台都要收费,不管是 Web ,还是 Android/iOS 客户端,每一个都是单独收费,尽管能够同步订阅列表,但后来转用 iOS 也就放弃了这个客户端,我用过的几个还不错的
至于其他人推荐的 Castro, Overcast 如果不缺钱的话买就行了。个人觉得重要的是内容,还有同步的功能,我希望我订阅的内容跟着账号走,而不是跟着设备走。其他国内的 app 比如 喜马拉雅,蜻蜓,荔枝 FM, 听伴 就凭着个人喜好选择即可。
至于为什么不推荐国内的这些 FM,是因为本来 Podcast 是一个公开分享的渠道,发布到 Podcast 上的内容可以被全世界的人访问到,而国内的 FM 都是闭门造车,封闭自己的用户,限制用户只能在他们的平台上传,听众也只有他们平台的账号才能收听,所有的内容就像是自家花园,外人不得入内。而放到 iTunes 的 Podcast 就像是放到了博物馆,全世界的人只要觉得有用就都能够收听到。而且封闭的环境导致审查异常严格,甚至聊电影都能碰到审查,同样也就导致了低智化内容泛滥,内容越没有思考越能得到平台的推荐,自此循环往复,推荐榜单就几乎没有能听的内容了。而在 Podcast 中反而一些很小众的 Channel 内容质量异常高,在某一个专业领域分享的知识,内容足够填满整个频道。
一个关于博客统计信息的站点