nextcloud-fpm + frp + nginx + ssl

本文介绍如何在本地建立nextcloud服务并通过frp内网穿透至公网服务器,实现外网访问。这样做的理由是:自己的电脑的资源比起公网服务器的充裕得多,性能强大的本地电脑用来承载后端服务、公网服务器只做分流能够带来更好的体验。

本文会介绍以下内容:

  1. 自签证书
  2. docker镜像nextcloud:fpm与本地Nginx搭建(开启SSL)
  3. 网络路径:客户端 <=> 公网Nginx <=> frps <=> frpc <=> 本地Nginx <=> nextcloud-fpm

自签证书

根据文章 如何创建自签名SSL证书 ,使用以下命令输出一套本地使用的自签SSL证书:

1
2
3
4
5
6
7
openssl req -newkey rsa:4096 \
-x509 \
-sha256 \
-days 3650 \
-nodes \
-out nextcloud.crt \
-keyout nextcloud.key

docker compose部署nextcloud:fpm

首先安装好docker和docker compose。随后建立一个nextcloud文件夹——本文将其放置在 /opt/nextcloud ——并根据以下内容建立几个文件。

nextcloud-fpm的主体配置 /opt/nextcloud/docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
version: '3'
services:
db:
image: mysql:8.0
container_name: nextcloud-mysql
restart: always
command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
environment:
- MYSQL_ROOT_PASSWORD=<数据库root密码>
env_file:
- db.env

redis:
image: redis:6-alpine
container_name: redis
restart: always

nextcloud:
image: nextcloud:fpm
ports:
- 9000:9000
container_name: nextcloud
restart: always
links:
- db
- redis
volumes:
- /opt/nextcloud/data:/var/www/html
environment:
- MYSQL_HOST=db
- REDIS_HOST=redis
env_file:
- db.env

cron:
image: nextcloud:fpm-alpine
restart: always
volumes:
- /opt/nextcloud/data:/var/www/html
entrypoint: /cron.sh
depends_on:
- db
- redis

Read More

兄弟送了个塞尔达

今天下班的时候看到快递终于到了,这个从香港进口的带子等得我眼都直了。本来以为是放到了家里的驿站,结果因为当时给bro的地址写错了号码(写成了当时单位的门牌号),所以快递直接就放到单位附近的驿站了。只好又开车去单位附近拿。回家之后美美把玩~感谢欧阳兄弟!

这一代塞尔达开局有了播片,开局就和塞尔达公主一起“作死”。比起一代,这种传统的序章确实少了“旷野”的那种意思——开局什么都没有,直接用场景引导你,这是玩了二代开局之后才让我感觉到一代的设计所厉害的地方。而且由于二代有了拼装系统,导致切换装备的快捷界面需要兼容这个拼装功能,所以切换起来有卡顿的感觉,没有一代那种爽快。但是拼装系统厉害的地方不只是意料之中的“把刀头和棒棒拼起来就成了长枪”这种简单的“拼接”,更厉害的是能够把道具拼接到弓箭上,实现照明箭、火箭等等功能各异的道具,这是微小却巨大的突破,是让我感到惊喜的。能够在辉煌的前作的基础上百尺竿头更进一步,真的很震撼。

Read More

nextcloud与nginx的listen domain socket不可共用

由于nextcloud自带brutal force protection,是根据ip来定的。而unix domain socket传给nextcloud的永远都是unix:——准确来说,是nextcloud无法正确获取client ip,是nextcloud的问题——所以导致了会把自己锁外边。log里会显示类似如下的内容:

1
"Exception\",\"Message\":\"unpack(): Argument #2 ($string) must be of type string, null given in file '/var/www/docker/nextcloud/lib/private/Security/Normalizer/IpAddress.php'

Read More

工作再见

经过和家里人的仔细考虑之后,我在星期一(5月8号)递交了辞职通知,并在综合部填写了辞职资料;5月9日根据综合部的要求在系统内做了辞职申请。虽然系统里说的是审批通过之后才能做离行签批,但是我并不打算在通知的日期(6月7日)之后再继续上班。

这个星期还是在支行营业部度过的。带着“我快要走了,所以无所谓”的心态进行一个上班和处理同事关系,突然间觉得轻松了很多。虽然心态上有所变化,但是刁民还是让我压力很大。大概周三左右知道了我下星期一就要去GX支行,而GX支行的茵姐要上来。我在群里跟她随便说了两句,一是支行刁民超多,二是支行的人际关系水很深很容易有人背后捅刀。至于她信不信,就不是我会关心的事情了。

想起来在工行的经历,“简历”就是:

  1. 2021年7月12日入行,在分行进行了所谓的“入职培训”,为期7天
  2. 2021年7月18日下午被接去支行,知道了19日要在哪里集合;2021年7月19日被接去SD支行开始学习
  3. 2021年7月19日至2021年12月5日在SD做柜员,主要做个人业务;
  4. 2021年12月6日被调到GH支行做柜员;2022年3月中开始学对公业务
  5. 2022年5月25日被调去BJ支行接手对公业务,原本预计3个月就回去GH,结果一拖再拖到了2023年4月2日
  6. 2023年4月3日,被调往支行营业部工作

除了支行营业部之外,其他网点的人际关系都是很和谐的,人情味很浓。但是支行营业部不一样,表面上来看就已经很明显的各干各事,柜台不会帮大堂干活,大堂也不会管太多柜台的东西,柜台之间也不会互相帮忙——这主要是因为支行营业部接待的客人很多,忙完自己的事情就已经筋疲力尽,帮助别人那只能是天方夜谭。更可怕的是背地里的流言蜚语,由于工作压力大带来的心理扭曲而导致的心理敏感更是加重了谣言的离谱程度。明明是没有提前告知需要星期六值班(所以等于连续上6天),我开玩笑性质的“有没有搞错啊”,会被传成是顶撞、不服从;明明是确认必须要实体身份证,不能用电子身份证,也会被传成顶撞;明明是客人走了之后才过来说五点前后来的就帮他做吧,就会被传成不听主管的指示、当场拒绝为客户办业务。诸如此类,真的令人失望透顶。而且这个地方还充分体现了“当别人不喜欢你的时候,你连呼吸都是错的”。递交的辞职信可以说是非常客气的了,居然也会被认为是言辞犀利。你工行不仅面对客户点头哈腰毫无底线毫无尊严,而且同事之间的捅刀更是毫不手软;自上而下的官僚主义形式主义离谱至极。现在想来我都不知道为什么会在这里做这么久,明知道未来薪酬甚至到不了20万一年都曾经想过在工行摆烂一辈子。现在我就是一个想法,赶紧等够30天直接走人,给你多干一天都是亏待自己。

Read More

nginx传递真实客户端ip给后端

由于DOH服务器端需要客户端IP来更好地向upstream请求距离客户端比较近的IP地址——亦即所谓的edns,或者edns client subnet——所以需要让nginx能够在反向代理的时候传递客户端IP给后端。由于特殊需要,需要保持SNI分流即第4层分流。之前一直搞不了,直到今天看到stackoverflow的回答,在第4层分流的情况下,nginx是无法获知客户端IP的,所以给后端的IP永远都是nginx自己的IP;但是如果使用proxy protocol,那就可以知道客户端IP甚至Port。总而言之,现在需要实现的是:1. 打开proxy protocol的同时兼容不支持proxy protocol的后端;2. 在proxy protocol下传递客户端真实IP。

首先是第一方面,需要在打开proxy protocol的情况下,再由nginx本身去掉这一层protocol,然后传给后端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
stream {
log_format stream_basic '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time';

# 这里就是 SNI 识别,将域名映射成一个配置名
map $ssl_preread_server_name $backend_name {
# 为不支持proxy protocol的后端设置一个匹配规则
some.domain.com unix:/run/nginx-remove-proxy-stream.sock;
# 域名都不匹配情况下的默认值,亦即nginx提供的ssl网站们
default 127.0.0.1:48443;
}
# 去掉proxy protocol后转发给后端
server {
# 注意末端的proxy_protocol,每一个都需要有这个才能正常提供服务
# 否则虽然nginx -t通过了,但是运行起来就会显示fail to read proxy xxx的错误
listen unix:/run/nginx-remove-proxy-stream.sock proxy_protocol;
proxy_pass 127.0.0.1:8772;
}
# 监听 443 并开启 ssl_preread
server {
listen 443 reuseport;
proxy_pass $backend_name;
ssl_preread on;
proxy_protocol on;
}
}

http {
log_format proxy_main '$proxy_protocol_addr [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log proxy_main;
include /etc/nginx/sites-enabled/*;
}

需要注意的有两点:1. http部分中,log_format不再写$remote_addr了,而是$proxy_protocol_addr,这就是客户端IP;2. 注释中“注意末端的proxy_protocol,每一个都需要有这个才能正常提供服务”,在上面的配置示例中,直接用一个server块来去掉了这个proxy_protocol,从而完成了本文需要解决的第一个问题;而对于由nginx提供服务的其他网站,每一个都需要在listen那一行里有一个proxy_protocol指令才能正常工作。如果不明白,看看下面这个虚拟网站的conf就知道了——同时,这个配置也体现了怎么传递真实IP给后端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server {
listen 48443 ssl http2 proxy_protocol;
# 域名,多个以空格分开
server_name some2.domain.com;
# 这里写其他配置

# 这里是转发给DOH的示例
location /dns-query {
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
# show real IP
# 把$proxy_protocol_addr所代表的真实IP用X-Real-IP传递给后端
proxy_set_header X-Real-IP $proxy_protocol_addr;
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
proxy_pass http://127.0.0.1:8080/dns-query;
}
}

这样配置好之后,DOH服务器的日志里就显示出了客户端的IP,就能够利用起edns的好处了。

Read More

结束了在滨江的工作

今天是3月31日,一季度结束了,从明天开始我就要去支营上班了。从2022年的5月25日开始到今天,我在滨江工作了接近一年时间,体会到了在小网点工作的不易。和大网点不同,小网点不仅收入低(因为存款奖励少,开户之类的收入也少),而且各种内控指标都很难搞,受制于这些指标导致开展业务也前顾后盼。比如客户只想开个户出来,其他的都不想要,但是因为纸质对账单要扣分,所以就不能这样做,必须要开个财智卡,然后就只能正常签套餐。而小网点的主管不仅要做主管的事情,很多时候还要兼顾大堂的工作,加上现在新装修的非现金柜和现金柜分开,导致跑出跑入麻烦得很。好在红霞主管是个很好的人,让我这种对大堂经理工作完全不喜欢的也能够搞好日常。虽然如此,滨江的非现金柜还要兼顾大堂这一点我始终不太喜欢。

之前在收拾对公档案袋的时候,翻看之前的袋子,突然间有一种“啊,原来已经那么久了啊”和“我要走了”的悲伤感。虽然这种悲伤感被随后的忙碌工作暂时掩盖了,但是在离开这个网点的今天,这种感觉却盖在心头,挥之不去。也有去新地方的期盼,也有离开熟悉的地方的不安。一天的心情都乱糟糟的。晚上离开的时候有一瞬间想要跟这个网点合影一张,不过还是放弃了,或许是觉得没有必要。

想想这个网点的人和事,多少有点难以放下。其实曾经在市东调去桂海的时候,这种感觉已经有过。从桂海调去滨江,不过是因为开始时说“去三个月就回来”然后三个月又三个月所以才没来得及伤心。而从滨江调去支营这件事早就在安排了,面临这个日子自然还是会非常难过。不知道下一次见到这些同事的时候,大家会变成什么样子呢。

Read More

今天去见家长了

因为子莹的父母提出应该要见面一下,所以星期六去吉之岛准备了一些水果,再带上家里的白茶,今天下午就去她家里见家长了。子莹说她很紧张,但是我没有什么特别的感觉。去到家里是五点多,她的父母在做饭,所以我就先在客厅坐下了。一开始是不知道做什么好的,所以只能呆坐在那里。后来她妈妈把桌子上的一些零食罐子打开了,我发现有瓜子,瞬间就找到了回家的感觉。不得不说感谢瓜子,真是拯救世界的英雄。

随后就是一边嗑瓜子一边回应她妈妈问的一些问题。虽然打开了电视,但是因为他们家是有线电视,不是IPTV,所以电视台不一样,找不到熟悉的台就只能随便看看了。她妈妈问问这问问那,其实也就是一些简单的了解家庭背景的话题,关于我对她女儿的话题倒是没有怎么提到。

然后吃晚饭,是蒜蓉虾(从虾背中间切开再用蒜蓉蒸),还有6斤大母鸡。为了吃多点菜,不留剩菜(特别是虾,第二顿就会很难吃的),所以干脆没有吃饭,纯粹吃菜。可惜爸爸说不要喝酒,所以没办法只能硬吃菜。

本来想写聊了些什么的,但是由于实在是零零碎碎,而且不怎么关键,主要都是她妈妈问然后我回答这样的对话,所以就不写了。

吃完饭之后和子莹一起洗了碗,然后坐着看了一会儿电视,之后因为白天没有怎么休息导致身体开始不舒服,所以八点多就告辞了。把他们的回礼带回妈妈家,我就自己回家休息了。

Read More

nginx加Trojan保持多网站

关于保持nginx监听443端口、用stream转发流量给trojan的文章有很多,本篇只是记录一些关键点。

首先是nginx的stream的配置,map其实只需要配置专门给trojan的那一条就行,其他的(就是正常的其他网站应用)用default统一匹配就行。以下配置参考程小白

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
stream {
# TLS SNI 识别,根据域名分流
map $ssl_preread_server_name $backend_name {
trojan的域名 127.0.0.1:trojan端口;
# 域名都不匹配情况下的默认值
default 127.0.0.1:正常的其他网站应用的ssl端口;
}

# 监听 443 并开启 ssl_preread
server {
listen 443 reuseport;
listen [::]:443 reuseport;
proxy_pass $backend_name;
ssl_preread on;
}
}

但是多数文章教的都是fallback到本地80端口的一个静态网页上,没有教怎么fallback给另一个https网页。比如我想让不匹配的流量都转发给我这个服务器上的一个正常的https站来处理,其实就只需要对nginx的default server(一般监听在80端口负责重定向http的请求到https)做一个简单的更改:

1
2
3
4
5
6
location / {
if ( $host = 'trojan的域名' ) {
return 302 https://另一个域名;
}
return 301 https://$host$request_uri;
}

这个if就把trojan的fallback过来的直接重定向给https站去处理了。

Read More