Nginx tcp反向代理记录日志
对于Nginx访问日志,大家都很熟悉,但是对于tcp代理来说,到底能不能记录访问日志呢? 想了一下,貌似不能啊,因为毕竟访问日志里面记录的元素都是http协议的。
但是当我去搜索时,的确搜到了相关的文档,索性先试试看,测试后发现确实可以。
修改nginx配置文档/usr/local/nginx/conf/nginx.conf 设置日志格式
stream { log_format proxy '$remote_addr [$time_local] ' '$protocol $status $bytes_sent $bytes_received ' '$session_time "$upstream_addr" ' '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"'; include ./conf.d/*.tcpstream; }
修改具体的tcp配置文档
server{ error_log /opt/log/device5001_error.log; access_log /opt/log/device5001_access.log proxy; listen 5001; proxy_pass device5001; }
日志如下:
但是,需要提醒你的是:
nginx会等待session结束才会记录到日志文件;
session日志只是tcp层面的记录,包括session时间,发送接收字节数等等;
session内部发送日志(比如一个socket连接建立起来以后,多次发送心跳数据)需要在应用层面才能记录;
nginx代理过程中修改user_agent
关于User_agent是啥,就不多介绍了,简单说就是客户端的标识,比如chrome浏览器有chrome浏览器的标识,手机客户端也有手机客户端的标识。
有些特殊场景需要指定一个固定的user_agent,来模拟某个客户端。这时候,就可以借助Nginx的反向代理来实现。Nginx配置文件如下:
server {
listen 8000;
server_name localhost;
access_log log/access-8000.log;
error_log log/error-8000.log;
location / {
set $ua "lalallalalla x33xx33";
proxy_pass http://127.0.0.1:8081/;
proxy_set_header User-Agent $ua;
proxy_set_header Host $http_host;
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 $scheme;
}
}
再来看看访问日志:
127.0.0.1 - - [19/Nov/2020:11:56:55 +0800] "GET /build/framework/js/7eaf6.chunk.js HTTP/1.0" 200 42870 "http://192.168.0.62:8000/" "lalallalalla x33xx33"
127.0.0.1 - - [19/Nov/2020:11:56:55 +0800] "GET /uusafe/gloab/rest/saas/all HTTP/1.0" 200 536 "http://192.168.0.62:8000/" "lalallalalla x33xx33"
已经将user_agent修改为了自定义的了。
centos使用yum update升级到指定小版本
参考: https://www.cnblogs.com/configure/p/10918189.html
提供一个搜狐镜像的7.6的yum源:
[C7.6.1810-base] name=CentOS-7.6.1810 - Base baseurl=http://mirrors.sohu.com/centos/7.6.1810/os/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 enabled=1 [C7.6.1810-updates] name=CentOS-7.6.1810 - Updates baseurl=http://mirrors.sohu.com/centos/7.6.1810/updates/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 enabled=1 [C7.6.1810-extras] name=CentOS-7.6.1810 - Extras baseurl=http://mirrors.sohu.com/centos/7.6.1810/extras/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 enabled=1 [C7.6.1810-centosplus] name=CentOS-7.6.1810 - CentOSPlus baseurl=http://mirrors.sohu.com/centos/7.6.1810/centosplus/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 enabled=1 [C7.6.1810-fasttrack] name=CentOS-7.6.1810 - Fasttrack baseurl=http://mirrors.sohu.com/centos/7.6.1810/fasttrack/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 enabled=1
nginx反向代理时保持长连接
【场景描述】
HTTP1.1之后,HTTP协议支持持久连接,也就是长连接,优点在于在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。
如果我们使用了nginx去作为反向代理或者负载均衡,从客户端过来的长连接请求就会被转换成短连接发送给服务器端。
为了支持长连接,我们需要在nginx服务器上做一些配置。
·【要求】
使用nginx时,想要做到长连接,我们必须做到以下两点:
- 从client到nginx是长连接
- 从nginx到server是长连接
对于客户端而言,nginx其实扮演着server的角色,反之,之于server,nginx就是一个client。
·【保持和 Client 的长连接】
我们要想做到Client与Nginx之间保持长连接,需要:
- Client发送过来的请求携带“keep-alive”header。
- Nginx设置支持keep-alive
【HTTP配置】
默认情况下,nginx已经开启了对client连接的 keepalive 支持。对于特殊场景,可以调整相关参数。
http {
keepalive_timeout 120s; #客户端链接超时时间。为0的时候禁用长连接。 keepalive_requests 10000; #在一个长连接上可以服务的最大请求数目。 #当达到最大请求数目且所有已有请求结束后,连接被关闭。 #默认值为100 } |
大多数情况下,keepalive_requests = 100也够用,但是对于 QPS 较高的场景,非常有必要加大这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT。
QPS=10000 时,客户端每秒发送 10000 个请求 (通常建立有多个长连接),每个连接只能最多跑 100 次请求,意味着平均每秒钟就会有 100 个长连接因此被 nginx 关闭。
同样意味着为了保持 QPS,客户端不得不每秒中重新新建 100 个连接。
因此,如果用netstat命令看客户端机器,就会发现有大量的TIME_WAIT的socket连接 (即使此时keep alive已经在 Client 和 NGINX 之间生效)。
·【保持和Server的长连接】
想让Nginx和Server之间维持长连接,最朴素的设置如下:
http {
upstream backend { server 192.168.0.1:8080 weight=1 max_fails=2 fail_timeout=30s; server 192.168.0.2:8080 weight=1 max_fails=2 fail_timeout=30s; keepalive 300; // 这个很重要! } server { listen 8080 default_server; server_name “”;
location / { proxy_pass http://backend; proxy_http_version 1.1; # 设置http版本为1.1 proxy_set_header Connection “”; # 设置Connection为长连接(默认为no)} } } } |
【upstream配置】
upstream中,有一个参数特别的重要,就是keepalive。
这个参数和之前http里面的 keepalive_timeout 不一样。
这个参数的含义是,连接池里面最大的空闲连接数量。
不理解?没关系,我们来举个例子:
场景:
有一个HTTP服务,作为upstream服务器接收请求,响应时间为100毫秒。
要求性能达到10000 QPS,我们需要在nginx与upstream服务器之间建立大概1000条HTTP请求。(1000/0.1s=10000)
最优情况:
假设请求非常的均匀平稳,每一个请求都是100ms,请求结束会被马上放入连接池并置为idle(空闲)状态。
我们以0.1s为单位:
1. 我们现在keepalive的值设置为10,每0.1s钟有1000个连接
2. 第0.1s的时候,我们一共有1000个请求收到并释放
3. 第0.2s的时候,我们又来了1000个请求,在0.2s结束的时候释放
请求和应答都比较均匀,0.1s释放的连接正好够用,不需要建立新连接,且连接池中没有idle状态的连接。
第一种情况:
应答非常平稳,但是请求不平稳的时候
4. 第0.3s的时候,我们只有500个请求收到,有500个请求因为网络延迟等原因没有进来
这个时候,Nginx检测到连接池中有500个idle状态的连接,就直接关闭了(500-10)个连接
5. 第0.4s的时候,我们收到了1500个请求,但是现在池里面只有(500+10)个连接,所以Nginx不得不重新建立了(1500-510)个连接。
如果在第4步的时候,没有关闭那490个连接的话,只需要重新建立500个连接。
第二种情况:
请求非常平稳,但是应答不平稳的时候
4. 第0.3s的时候,我们一共有1500个请求收到
但是池里面只有1000个连接,这个时候,Nginx又创建了500个连接,一共1500个连接
5. 第0.3s的时候,第0.3s的连接全部被释放,我们收到了500个请求
Nginx检测到池里面有1000个idle状态的连接,所以不得不释放了(1000-10)个连接
造成连接数量反复震荡的一个推手,就是这个keepalive 这个最大空闲连接数。
上面的两种情况说的都是 keepalive 设置的不合理导致Nginx有多次释放与创建连接的过程,造成资源浪费。
keepalive 这个参数设置一定要小心,尤其是对于 QPS 要求比较高或者网络环境不稳定的场景,一般根据 QPS 值和 平均响应时间能大致推算出需要的长连接数量。
然后将keepalive设置为长连接数量的10%到30%。
【location配置】
http {
server { location / { proxy_pass http://backend; proxy_http_version 1.1; # 设置http版本为1.1 proxy_set_header Connection “”; # 设置Connection为长连接(默认为no) } } } |
HTTP 协议中对长连接的支持是从 1.1 版本之后才有的,因此最好通过 proxy_http_version 指令设置为 1.1。
HTTP1.0不支持keepalive特性,当没有使用HTTP1.1的时候,后端服务会返回101错误,然后断开连接。
而 “Connection” header 可以选择被清理,这样即便是 Client 和 Nginx 之间是短连接,Nginx 和 upstream 之间也是可以开启长连接的。
【另外一种高级方式】
http {
map $http_upgrade $connection_upgrade { default upgrade; ” close; } upstream backend { server 192.168.0.1:8080 weight=1 max_fails=2 fail_timeout=30s; server 192.168.0.2:8080 weight=1 max_fails=2 fail_timeout=30s; keepalive 300; } server { listen 8080 default_server; server_name “”; location / { proxy_pass http://backend;
proxy_connect_timeout 15; #与upstream server的连接超时时间(没有单位,最大不可以超过75s) proxy_read_timeout 60s; #nginx会等待多长时间来获得请求的响应 proxy_send_timeout 12s; #发送请求给upstream服务器的超时时间 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } } } |
http里面的map的作用是:
让转发到代理服务器的 “Connection” 头字段的值,取决于客户端请求头的 “Upgrade” 字段值。
如果 $http_upgrade没有匹配,那 “Connection” 头字段的值会是upgrade。
如果 $http_upgrade为空字符串的话,那 “Connection” 头字段的值会是 close。
【补充】
NGINX支持WebSocket。
对于NGINX将升级请求从客户端发送到后台服务器,必须明确设置Upgrade和Connection标题。
这也算是上面情况所非常常用的场景。
HTTP的Upgrade协议头机制用于将连接从HTTP连接升级到WebSocket连接,Upgrade机制使用了Upgrade协议头和Connection协议头。
为了让Nginx可以将来自客户端的Upgrade请求发送到后端服务器,Upgrade和Connection的头信息必须被显式的设置。
【注意】
在nginx的配置文件中,如果当前模块中没有proxy_set_header的设置,则会从上级别继承配置。
继承顺序为:http, server, location。
如果在下一层使用proxy_set_header修改了header的值,则所有的header值都可能会发生变化,之前继承的所有配置将会被丢弃。
所以,尽量在同一个地方进行proxy_set_header,否则可能会有别的问题。
·【参考】
Nginx中文官方文档: http://www.nginx.cn/doc/
测试参考文档: https://www.lijiaocn.com/问题/2019/05/08/nginx-ingress-keep-alive-not-work.html
keep-alive参考文档: https://wglee.org/2018/12/02/nginx-keepalive/
mysql命令行不再提醒警告
在Linux命令行里输入mysql 用户密码就会提示:
Warning: Using a password on the command line interface can be insecure.
即使我们用2>想给它重定向也无济于事。
有一个方法可以隐藏掉这个警告。
mysql_config_editor set --user=root --socket=/tmp/mysql.sock --password
输入密码即可,这样就可以把密码保存到一个配置文件里 ~/.mylogin.cnf, 这个文件不能直接cat查看
以后再次使用mysql时,直接敲mysql命令即可完成登录。
搭建一个局域网http的yum源
mkdir /data/yumdata
mount /dev/cdrom /mnt/ cp /mnt/Packages/*rpm /data/yumdata
createrepo /data/yumdata/
createrepo --update /data/yumdata/
yum install epel-release yum install nginx
server { listen 80 default_server; listen [::]:80 default_server; server_name _; root /data/yumdata; autoindex on; error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } }
systemctl start nginx
cd /etc/yum.repos.d mkdir bak mv *.repo bak/ //把系统自带的repo挪走 vim my.repo //内容如下
[aming] name=myserver baseurl=http://192.168.133.140 gpgcheck=0 enabled=1
rsync -av rsync://mirrors.ustc.edu.cn/centos/7/os/x86_64/Packages/ /data/yumdata/
yum clean all //删除缓存
Nginx代理tomcat https跳转到http
问题
网站采用了 Nginx 反向代理 Tomcat 的方式来负载均衡。
Nginx使用https,默认端口443。Tomcat使用http,端口8080
结果今天后台操作停留时间过长session超时后,跳转到登录页面时出现无法访问错误。如图:
分析
可以看到,出错的原因应该是跳转的时候加上了web默认80端口,而https默认的端口并不是80,所以导致无法访问。
后台无session时跳转代码:
requestURL = HttpUtils.encodeUrl(requestURL);
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path
+ "/";
return basePath + "user/login?goUrl=" + requestURL;
代码跳转的是绝对路径,包括schema和port,问题应该就在这里。
经过调试发现获取到的request.getScheme()总是http而非实际的https,相应的request.getServerPort()也就成了80。
端口是80而非Tomcat本身的8080说明获取到的确实是nginx转发过来的请求,那schema为什么得不到呢?
解决
通过查找资料,发现nginx请求转发时必须设置proxy_set_header才能让被代理的tomcat获取到正确的客户端ip等信息。
但是之前已经设置过nginx的proxy_set_header,而获取ip等也毫无问题:
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect http:// $scheme://;
proxy_pass http://localhost:8080;#转向tomcat处理
上面有一行设置了proxy_redirect,所以浏览器地址栏的schema仍然是https.
接着查找资料,发现要传递schema,在Tomcat端也需要相应配置。
<Engine>
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="X-Forwarded-For"
protocolHeader="X-Forwarded-Proto"
protocolHeaderHttpsValue="https"/>
</Engine >
加上后,重启Tomcat,一切正常了!
你不知道的vim小秘密

大家先了解一些背景知识:
1) 给文件增加了i权限,那文件不能被更改,不能删除,也不能修改名字以及权限。
2) 给文件增加a权限,文件可以追加内容,不能删除,不能修改内容,不能修改名字以及权限。
3) vim一个文件,如果不正常退出,再次编辑时是会提示一些信息的,并且有一个隐藏的文件.xxx.swp
了解以上知识后,再来看下面的现象:
1) 如果给一个文件增加a权限,用vim编辑文件,增加内容(注意是在文件末尾增加内容,不要修改其他内容),并不会成功。
2) 如果给一个目录增加i权限或者a权限,在该目录下面vim一个文件,更改文件内容可以正常保存。
既然a权限可以追加内容,那为何vim一个文件在末尾增加内容不能成功?既然i权限不能修改,那为何在目录里面变更文件内容却可以成功?
关于这两点,你有没有疑惑?下面我们来分析原因。
先不管i或者a权限,在一个没有i或者a权限的目录下,编辑一个没有i或者a权限的文件,用strace来查看其执行过程。
mkdir /tmp/test
strace vim /tmp/test/aminglinux.txt 2>/tmp/vim.log
写入一个数字1,然后保存退出。再来查看vim.log的内容。
less /tmp/vim.log
大部分内容你不用关心,只需要看这几行:
stat(“/tmp/test/aminglinux.txt”, 0x7fff072ecb10) = -1 ENOENT (No such file or directory)
access(“/tmp/test/aminglinux.txt”, W_OK) = -1 ENOENT (No such file or directory)
open(“/tmp/test/aminglinux.txt”, O_RDONLY) = -1 ENOENT (No such file or directory)
readlink(“/tmp/test/aminglinux.txt”, 0x7fff072eb360, 4095) = -1 ENOENT (No such file or directory)
open(“/tmp/test/.aminglinux.txt.swp”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/tmp/test/.aminglinux.txt.swp”, O_RDWR|O_CREAT|O_EXCL, 0600) = 3
open(“/tmp/test/.aminglinux.txt.swx”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/tmp/test/.aminglinux.txt.swx”, O_RDWR|O_CREAT|O_EXCL, 0600) = 4
unlink(“/tmp/test/.aminglinux.txt.swx”) = 0
unlink(“/tmp/test/.aminglinux.txt.swp”) = 0
stat(“/tmp/test/.aminglinux.txt.swp”, 0x7fff072ec310) = -1 ENOENT (No such file or directory)
lstat(“/tmp/test/.aminglinux.txt.swp”, 0x7fff072ec3e0) = -1 ENOENT (No such file or directory)
lstat(“/tmp/test/.aminglinux.txt.swp”, 0x7fff072ec8a0) = -1 ENOENT (No such file or directory)
open(“/tmp/test/.aminglinux.txt.swp”, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = 3
stat(“/tmp/test/aminglinux.txt”, 0x7fff072eac40) = -1 ENOENT (No such file or directory)
stat(“/tmp/test/aminglinux.txt”, 0x7fff072ebe20) = -1 ENOENT (No such file or directory)
stat(“/tmp/test/aminglinux.txt”, 0x7fff072eadf0) = -1 ENOENT (No such file or directory)
write(1, “\”/tmp/test/aminglinux.txt\””, 26) = 26
stat(“/tmp/test/aminglinux.txt”, 0x7fff072ec050) = -1 ENOENT (No such file or directory)
open(“/tmp/test/aminglinux.txt”, O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
stat(“/tmp/test/aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=2, …}) = 0
stat(“/tmp/test/aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=2, …}) = 0
unlink(“/tmp/test/.aminglinux.txt.swp”) = 0
看起来乱乱的,其实大概的过程就是vim /tmp/test/aminglinux.txt时,先看有没有.aminglinux.txt.swp以及.aminglinux.txt.swx,因为这两个文件就是vim产生的临时文件,swp先产生,如果swp存在就产生第二个swx。写入的内容先存到swp里,当保存退出vim时,再把swp的内容存到aminglinux.txt里,最后删除掉swp文件。
有了这个认识之后,我们再来分析上面提到的现象1。如果文件给了a权限,那么在编辑该文件时,会产生swp文件,当保存退出时,swp文件内容会写入该文件,这相当于更改该文件,很线上a权限是不允许的。
再来分析现象2,按照我们的推测,如果目录给了a权限,增加文件没问题,也就是说产生swp或者swx文件没有问题,当然把swp或者swx内容写入到文件里时也不会有问题,但swp或者swx文件却不会被删除了,所以再次编辑文件时就会提示临时文件已经存在了。但这并不会影响修改文件内容。
如果给目录设置了i权限的话,vim编辑文件,要产生swp或swx肯定会出错啊,但为何依然能正常编辑文件? 下面继续用strace来分析一下。
chattr +i /tmp/test
strace vim /tmp/test/aminglinux.txt 2> /tmp/vim.log
看vim.log里面和aminglinux.txt相关的信息
stat(“/tmp/test/aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=4, …}) = 0
stat(“/tmp/test/aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=4, …}) = 0
stat(“/tmp/test/aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=4, …}) = 0
stat(“/tmp/test/aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=4, …}) = 0
access(“/tmp/test/aminglinux.txt”, W_OK) = 0
open(“/tmp/test/aminglinux.txt”, O_RDONLY) = 3
readlink(“/tmp/test/aminglinux.txt”, 0x7fff49efc6f0, 4095) = -1 EINVAL (Invalid argument)
open(“/tmp/test/.aminglinux.txt.swp”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/tmp/test/.aminglinux.txt.swp”, O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied)
stat(“/tmp/test/.aminglinux.txt.swp”, 0x7fff49efd6a0) = -1 ENOENT (No such file or directory)
lstat(“/tmp/test/.aminglinux.txt.swp”, 0x7fff49efd770) = -1 ENOENT (No such file or directory)
lstat(“/tmp/test/.aminglinux.txt.swp”, 0x7fff49efdc30) = -1 ENOENT (No such file or directory)
open(“/tmp/test/.aminglinux.txt.swp”, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = -1 EACCES (Permission denied)
readlink(“/tmp/test/aminglinux.txt”, 0x7fff49efc6f0, 4095) = -1 EINVAL (Invalid argument)
open(“/root/tmp/aminglinux.txt.swp”, O_RDONLY) = -1 ENOTDIR (Not a directory)
open(“/root/tmp/aminglinux.txt.swp”, O_RDWR|O_CREAT|O_EXCL, 0600) = -1 ENOTDIR (Not a directory)
stat(“/root/tmp/aminglinux.txt.swp”, 0x7fff49efd6a0) = -1 ENOTDIR (Not a directory)
lstat(“/root/tmp/aminglinux.txt.swp”, 0x7fff49efd770) = -1 ENOTDIR (Not a directory)
lstat(“/root/tmp/aminglinux.txt.swp”, 0x7fff49efdc30) = -1 ENOTDIR (Not a directory)
open(“/root/tmp/aminglinux.txt.swp”, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = -1 ENOTDIR (Not a directory)
readlink(“/tmp/test/aminglinux.txt”, 0x7fff49efc6f0, 4095) = -1 EINVAL (Invalid argument)
open(“/var/tmp/aminglinux.txt.swp”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/var/tmp/aminglinux.txt.swp”, O_RDWR|O_CREAT|O_EXCL, 0600) = 4
open(“/var/tmp/aminglinux.txt.swx”, O_RDONLY) = -1 ENOENT (No such file or directory)
open(“/var/tmp/aminglinux.txt.swx”, O_RDWR|O_CREAT|O_EXCL, 0600) = 5
unlink(“/var/tmp/aminglinux.txt.swx”) = 0
unlink(“/var/tmp/aminglinux.txt.swp”) = 0
stat(“/var/tmp/aminglinux.txt.swp”, 0x7fff49efd6a0) = -1 ENOENT (No such file or directory)
lstat(“/var/tmp/aminglinux.txt.swp”, 0x7fff49efd770) = -1 ENOENT (No such file or directory)
lstat(“/var/tmp/aminglinux.txt.swp”, 0x7fff49efdc30) = -1 ENOENT (No such file or directory)
open(“/var/tmp/aminglinux.txt.swp”, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = 4
chmod(“/var/tmp/aminglinux.txt.swp”, 0644) = 0
open(“/tmp/test/aminglinux.txt”, O_RDONLY) = 3
stat(“/tmp/test/aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=4, …}) = 0
stat(“/tmp/test/aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=4, …}) = 0
stat(“/tmp/test/aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=4, …}) = 0
access(“/tmp/test/aminglinux.txt”, W_OK) = 0
write(1, “\”aminglinux.txt\””, 16) = 16
stat(“aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=4, …}) = 0
access(“aminglinux.txt”, W_OK) = 0
getxattr(“aminglinux.txt”, “system.posix_acl_access”, 0x7fff49efd050, 132) = -1 ENODATA (No data available)
stat(“aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=4, …}) = 0
open(“aminglinux.txt”, O_WRONLY|O_CREAT|O_TRUNC, 0644) = 3
chmod(“aminglinux.txt”, 0100644) = 0
setxattr(“aminglinux.txt”, “system.posix_acl_access”, “\x02\x00\x00\x00\x01\x00\x06\x00\xff\xff\xff\xff\x04\x00\x04\x00\xff\xff\xff\xff \x00\x04\x00\xff\xff\xff\xff”, 28, 0) = 0
stat(“/tmp/test/aminglinux.txt”, {st_mode=S_IFREG|0644, st_size=6, …}) = 0
unlink(“/var/tmp/aminglinux.txt.swp”) = 0
我相信你可以看到Permission denied的提示,这是因为当前目录有i权限,不能增加文件,也就不能在当前目录下生成临时文件。当然,vim如果遇到这样的问题,它还是会“曲线救国”的,于是先找/root/tmp/,但是并没有该目录,只好继续找/var/tmp/,这个目录存在,所以就在这个目录里生成了临时文件(并不是隐藏的)。后面的操作就不用多说了。
既然vim可以在/var/tmp/下生成临时文件,自然也可以在已经设置了i权限的目录里编辑文件的,这样现象2也解释通了。上面罗嗦了这么多,其实我就想表达如下观点:
vim编辑文件时,会在该文件所在目录生成临时隐藏文件.swp和.swx,如果那目录不可写就会到/root/tmp/下或者/var/tmp/下生成临时文件(非隐藏),当编辑的文件保存后,临时文件删除。
这个命令你看得懂么
直接上命令
history 1 | { read x cmd; echo “$cmd”; }
对于read命令的了解,仅限于在shell脚本中使用read -p,对于这种用法从来没用过,更不知道它的含义。
今天抽空琢磨了一下,终于搞明白了来龙去脉。先来写几个命令吧:
# read a b c
1 2 3
# echo $a
1
# echo $b
2
# echo $c
3
# read x y
1 2 3
# echo $x
1
# echo $y
2 3
到这,也许你似乎看出一些门道了。read命令,后面跟的是变量名,可以是1个,也可以是多个,用空格分隔。回车后,输入的字符就是在给这些变量赋值,输入的字符串也需要用空格分隔,如果和上面的变量名一个一个地对应,那么这样就一个一个地赋值了。
如果没有对应呢?通过上面的命令也可以发现,如果值比变量多,它只对应前面的。例如,变量只有x和y,而值是1 2 3,则它把x赋值1,后面的2 3一股脑赋值给最后面的变量y。
再来一个例子吧。
# echo 1 2 3 4 5|read a b c
# echo $a
1
# echo $b
2
# echo $c
3 4 5
再回头看这条命令:
history 1 | { read x cmd; echo “$cmd”; }
管道前面,history 1表示取最后一条命令。管道后面'{ }’内是一整体,相当于一个函数,函数里面可以有多条命令,用分号分割,而且最后一条命令也必须加分号。第一条命令和'{‘之间必须要有空格。
nginx 作为正向代理
2021年6月18日
未分类
No Comments
aming
nginx还是蛮强大的,不仅可以作为7层的正向代理,还可以作为4层的正向代理。
参考文档 https://zhuanlan.zhihu.com/p/70522194
7层是需要加三分模块 ngx_http_proxy_connect_module,github地址:https://github.com/chobits/ngx_http_proxy_connect_module 注意,不同的Nginx版本,还需要下载不同的patch包
具体配置 参考 https://github.com/aminglinux/nginx/blob/master/proxy/z_proxy.md
配置文件
4层的话,需要额外增加编译参数
配置文件