以软路由为基础,架设透明代理及NAS等相关服务是对家庭网络进行优化升级的主要途径,但校园网环境为软路由的搭建带来了很多问题,除了校园网的用户认证和不同网络环境下的路由优化之外,最具挑战性的莫过于突破校园网防火墙对外部连接的阻断以实现公网访问。本文将简要介绍笔者逐步搭建和升级校园网内网络服务的历程,并指出各阶段所遇到的问题及其解决方法,以供各位参考。

1. OwnCloud网盘的搭建

1.1 OwnCloud简介

OwnCloud是一款开源的个人网盘软件,适用于自建服务器的云存储服务,一般为个人使用,具有文件同步、文件分享功能,并支持WebDAV以及在线流媒体播放。OwnCloud服务端的运行依赖LAMP环境,因此我们应当先将LAMP环境配置完善后再进行OwnCloud服务端软件的安装。

1.2 OwnCloud的安装

不推荐使用OwnCloud官网提供的安装路线,在此列出两篇手动安装OwnCloud的CSDN文章:

在安装过程中有如下几个关键步骤以及需要注意的点:

  1. 安装Apache,Ubuntu包名为apache2,CentOS包名为httpd。安装结束后打开默认界面测试,注意开通防火墙相关端口。

  2. 安装版本高于5.6的PHP,若版本低于5.6则首先删除所有php相关包,然后通过添加源的方式安装更高版本的包。

  3. 为了保证大文件传输时不出错,修改php的配置文件php.ini,将其中的upload_max_filesizepost_max_size修改为一个较大的值(表示的是上传文件和通过POST方式发送数据包的最大大小,推荐写100M或更大),并修改max_execution_timemax_input_time(表示每个PHP页面运行和接收数据的最长时间,建议写600及以上的值),最后修改memory_limit(内存占用大小)为32M及以上(不能过大)。

  4. 安装并开启数据库服务(MySQL或MariaDB),并开放3306端口。

  5. 官网下载OwnCloud的安装包,并将解压后的文件夹复制到/var/www/html后,注意将文件夹所属目录的所有者更改为apache(Ubuntu为www-data)用户(chown -R apache.apache /var/www/html

  6. 配置文件路径并重启Apache服务后,通过Web界面安装OwnCloud,创建管理员账号并连接数据库后,就可以利用http://ip:端口/index.php访问OwnCloud服务了。

1.3 将OwnCloud服务进行HTTPS加密

将OwnCloud服务与域名绑定并进行https加密是很有必要的。笔者通过Nginx反向代理实现此需求。

为避免与nginx的http服务冲突,首先设置Apache的监听端口为81并将OwnCloud服务运行于其上,接着在nginx的配置文件中新建一个server块:

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
server {
listen 443 ssl;
server_name cloud.yourdomain.com; # 修改成你自己的域名
charset utf-8;

# 更改数据包大小上限避免大文件传输出错
client_max_body_size 4096M;

# SSL证书,可通过Let's Encrypt https://letsencrypt.org/ 提供的程序申请
ssl_certificate yourdomain.com/fullchain.pem;
ssl_certificate_key yourdomain.com/privkey.pem;
ssl_trusted_certificate yourdomain.com/chain.pem;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

server_tokens off;

fastcgi_param HTTPS on;
fastcgi_param HTTP_SCHEME https;

location / {
# 反向代理本机81端口的OwnCloud服务
proxy_pass http://127.0.0.1:81;
index index.php;
}
}

运行后发现OwnCloud网页上的登出链接仍然为http://127.0.0.1:81/...,这显然是OwnCloud的php配置中没有更改自定义域名导致的,于是修改OwnCloud的配置文件config.ini(位于安装目录下的config文件夹),在trusted_domains下面添加一行,并增加overwrite.cli.urloverwritehost两个字段,如下所示:

1
2
3
4
5
6
7
8
9
'trusted_domains' => 
array (
0 => '127.0.0.1:81',
1 => 'cloud.yourdomain.com',
),
...
'overwrite.cli.url' => 'http://127.0.0.1:81',
'overwritehost' => 'cloud.yourdomain.com',
...

重启apache服务后大功告成,可以通过https://cloud.yourdomain.com/index.php访问你的网盘了!

2. Jupyter notebook文件服务器的搭建

2.1 Jupyter notebook简介

Jupyter notebook是基于网页的python交互式开发环境,文件浏览器功能并不是其主要功能,但由于笔者在当时尚不了解其他Web文件管理系统,且有python开发的需要,因此选择在服务器上安装jupyter notebook服务。

最好在Anaconda环境下安装和运行jupyter notebook。可前往清华大学开源镜像站下载最新版本的Anaconda安装包。

2.2 Jupyter notebook服务的启动

若要运行jupyter notebook,需要先在终端中切换到conda环境,然后输入jupyter notebook命令即可,但此时jupyter notebook并没有向客户端开放,我们无法通过浏览器访问它,因此要更改jupyter notebook的配置文件(~/.jupyter/jupyter_notebook_config.py~为用户家目录,如果没有找到该文件,可通过jupyter notebook --generate-config命令创建。)

将如下字段取消注释后更改:

1
2
3
4
c.NotebookApp.ip = '*' # 设置访问notebook的ip来源,*表示所有,即服务对所有来源开放  
c.NotebookApp.password = u'sha1:xxxx' # 填写密码(见下文)
c.NotebookApp.open_browser = False # 禁止notebook启动时自动打开浏览器(无必要打开且多数linux服务器无图形界面)
c.NotebookApp.port = 8888 # 指定服务端口,默认是8888。e

密码通过在交互式python环境下运行如下两行python代码得到:

1
2
from notebook.auth import passwd  
passwd()

输入密码并确认后得到密码的sha1值,将其填入c.NotebookApp.password中即可。

1
>>> 'sha1:xxxx'  

2.3 将jupyter服务进行HTTPS加密

由于要使用域名访问服务,因此须在jupyter notebook的配置中将c.NotebookApp.allow_origin的值改为*以允许由域名访问(若要求严谨,可填写notebook.yourdomain.com)。否则会报Blocking Cross Origin API request for /api/sessions.错误。

另外,jupyter notebook需要nginx的websocket支持(否则会报错误Replacing stale connection),因此修改nginx配置文件如下。

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
server {
listen 443 ssl;
server_name notebook.yourdomain.com;
charset utf-8;
# 大文件传输支持
client_max_body_size 8192M;

ssl_certificate yourdomain.com/fullchain.pem;
ssl_certificate_key yourdomain.com/privkey.pem;
ssl_trusted_certificate yourdomain.com/chain.pem;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

server_tokens off;

fastcgi_param HTTPS on;
fastcgi_param HTTP_SCHEME https;

# 反向代理及websocket配置
location / {
proxy_pass http://127.0.0.1:8888;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}

对于非root用户运行的jupyter notebook,需要有访问/usr/share的权限,因此执行命令sudo chmod 777 share/,否则会报500错误:

1
PermissionError: [Errno 13] Permission denied: '/usr/share/jupyter/nbconvert/templates/conf.json' -R

以上步骤完成后,使用非root账号,在conda环境下执行

nohup jupyter notebook &

即可让jupyter notebook在后台运行,并可通过https://notebook.yourdomain.com/使用它了。

  • 若提示nohup: 打开'/home/用户名/nohup.out' 失败: 权限不够,则将命令修改为

    nohup jupyter notebook >/dev/null 2>&1 &(将nohup的日志文件和错误文件重定向到/dev/null,详见此文

  • 若希望更改jupyter notebook的根目录路径(如修改为/var/www/notebook/),则可将命令进一步修改为

    nohup jupyter notebook /var/www/notebook/ >/dev/null 2>&1 &

也可通过在jupyter_notebook_config.py中修改c.NotebookApp.base_url = '/var/www/notebook/',这样就不需在运行命令时指定根目录了。

3. 软路由网络优化

软路由(软件路由器)相比于传统的硬路由(硬件路由器)能够提供更加丰富的网络功能,对于扩展网络功能、提升网络体验是再适合不过的选择。由于房间有双WAN口,因此考虑充分利用网络资源,利用另一个WAN口连接OpenWrt软路由,再用该软路由连接上述的服务器(服务器同样为双网卡),并添加无线AP和NAS服务,构建如下图内网部分所示架构的室内网络(NAS搭建及内网穿透部分于下文详述)。

网络架构图

在添置软路由设备之前,若要访问上述服务器上的服务,则需要通过校园网网关中转,速度受到限制;而软路由可拦截DNS请求并解析至服务器的内网地址(192.168.2.3/24)进而直接建立与服务器的连接。因此,该网络可确保用户在不同网络环境下均获得最佳使用体验。使用室内局域网(内网)的用户,访问速度可达500Mbps;使用校园网WIFI的用户可达50Mbps;通过公网访问NAS服务速度可达5Mbps。

4. NAS服务的搭建

4.1 NAS简介

NAS(网络附属存储)是专用于数据存储的服务器,可将其视作大容量自建云盘。同时,多数NAS设备会挂载多个磁盘并组成磁盘阵列,通过将文件分散存储或拷贝到多个磁盘以保证某一磁盘损坏时数据不会丢失。目前市场普及率最高的家用NAS设备提供商为群晖(Synology)。笔者使用群晖的一款双盘位NAS与2块西数4T红盘组建NAS服务,总可用容量约3.6TB。

4.2 FRP内网穿透

群晖NAS的管理界面默认使用http协议和5000端口,其WebDAV服务则默认使用http协议和5005端口。在内网可以直接使用ip地址访问,但由于该NAS设备并未直接连接到校园网,因此若要求可在校园网范围内访问,则需要使用FRP软件组合进行内网穿透。笔者使用的是上述具有双网卡的服务器同时作为FRP服务端和客户端。校园网连接frps服务端口,frps和frpc连接,frpc再与NAS建立连接,则可实现内网穿透。

首先,下载FRP软件包并解压,编写frp的服务端和客户端配置文件如下(假设该FRP服务器内网地址为192.168.2.3,NAS地址为192.168.2.5)

  • frps.ini(服务端)
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
[common]
# ssh监听地址
bind_addr = 0.0.0.0
# ssh监听端口
bind_port = 5443
# kcp协议监听端口
kcp_bind_port = 5443
# frps控制面板所在端口
dashboard_port = 6443
# frps控制面板账号
dashboard_user = admin
# frps控制面板密码
dashboard_pwd = yourpassword
# 将http映射到端口
vhost_http_port = 9080
# 将https映射到端口
vhost_https_port = 9443
# 日志设置
log_file = ./frps.log
log_level = info
log_max_days = 3
# 令牌(相当于服务端与客户端连接的密钥,可自行填写,也可通过程序生成)
token = hd92hr8r017dqdqh
# 根域名,适用于web服务
subdomain_host = yourdomain.com
# 其他连接设置,非必要不更改
max_pool_count = 50
tcp_mux = true
  • frpc.ini 客户端
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
# common为服务端信息
[common]
server_addr = 127.0.0.1
server_port = 5443
# 在下面填写frps.ini里写的token
token = hd92hr8r017dqdqh

# nas Web管理界面的内网穿透
[nas]
type = http
# 连接到NAS的5000端口
local_ip = 192.168.2.5
local_port = 5000
# 开启压缩和加密
use_encryption = true
use_compression = true
# 子域名为in-nas,通过http://in-nas.yourdomain.com:9080 访问该服务
subdomain = in-nas

# nas WebDAV服务的内网穿透
[naswebdav]
type = http
local_ip = 192.168.2.5
local_port = 5005
use_encryption = true
use_compression = true
# 通过http://in-naswebdav.yourdomain.com:9080 访问该服务
subdomain = in-naswebdav

注1:选择9080端口是为了避免与此前架设的nginx服务冲突,并为之后nginx反向代理与https加密做好准备。

经此配置,运行如下两个命令在后台运行frps和frpc,即可在http://in-nas.yourdomain.com:9080进入NAS的管理界面,并可在http://in-naswebdav.yourdomain.com:9080使用WebDAV服务。

1
2
nohup ./frps -c frps.ini &
nohup ./frpc -c frpc.ini &

注2:可将配置文件放入frp默认的配置文件目录,则不需要指定-c参数。

由于校园网会阻断来自外部的连接,因此若要从公网访问NAS,则应在公网服务器上建立frps服务,而在内网网关(软路由)上建立frpc服务,具体过程类似,故不再赘述。搭建完成后,可在http://out-nas.yourdomain.com:9080http://out-naswebdav.yourdomain.com:9080访问相关服务。

4.3 将NAS服务进行HTTPS加密

使用http协议传输数据是不安全的,且输入网址时还要附带端口号,十分麻烦。若可使用nginx对内网穿透服务端进行反向代理并进行https加密,则有望通过https默认端口(443)访问NAS服务。

对NAS的Web管理界面的反向代理操作十分简单,只需在location块中添加反向代理参数即可:

1
2
3
4
5
6
7
location / {
proxy_pass http://127.0.0.1:9080;
proxy_redirect $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 Host $host;
}

但对于WebDAV服务而言,仅添加上述的反向代理参数是不够的,会出现无法上传文件和无法新建、重命名和移动文件及文件夹等一系列问题,经分析,原因如下:

  1. WebDAV的请求头存在自定义字段Destination。在反向代理时,nginx默认不会将Destination字段中https://in-naswebdav.yourdomain.com/...https替换为http,后台的NAS因而无法定位目标地址,进而出现502等一系列问题(若使用frp的https服务,则需添加https2http插件
    ,详见此文,本文不使用此方法)。
  2. WebDAV对文件夹的创建以及文件和文件夹的重命名操作,其请求路径需以/结尾,而通过nginx的uri往往缺少结尾的/,导致操作失败。

为了解决上述第一个问题,将Destination请求头中的https替换为http,我们使用nginx的第三方模块more_set_headers,具体安装方法可参考此文章
模块添加完成后,在nginx.conf配置文件的http块(注意 不是 server块)中添加map指令,将请求头Destination中的https替换为http,并解决webdav重命名中文文件夹的乱码问题:

1
2
3
4
map $http_destination $webdav_dest {
~*https://(.+) http://$1;
default $http_destination;
}

接着,在location块中添加如下语句,解决WebDAV不能复制、移动文件问题:

1
2
3
4
if ($request_method ~ (MOVE|COPY))
{
more_set_input_headers 'Destination: $webdav_dest';
}

接下来解决创建及重命名文件夹的问题,在location块中添加如下语句:

1
2
3
4
5
6
7
8
9
# 解决webdav不能创建文件夹问题
if ($request_method = MKCOL) { rewrite ^(.*[^/])$ $1/ break; }

# 解决webdav不能重命名问题
if (-d $request_filename) {
rewrite ^(.*[^/])$ $1/;
set $webdav_dest $webdav_dest/;
more_set_input_headers 'Destination: $webdav_dest';
}

然后在location块中加上反向代理设置,即完成配置。完整的server块如下:

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
44
45
server {
listen 443 ssl;
server_name in-nas.yourdomain.com;
charset utf-8;

ssl_certificate yourdomain.com/fullchain.pem;
ssl_certificate_key yourdomain.com/privkey.pem;
ssl_trusted_certificate yourdomain.com/chain.pem;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

server_tokens off;

fastcgi_param HTTPS on;
fastcgi_param HTTP_SCHEME https;

# 修改包大小上限避免上传错误
client_max_body_size 10G;

location / {

# 解决webdav不能创建文件夹问题
if ($request_method = MKCOL) { rewrite ^(.*[^/])$ $1/ break; }

# 解决webdav不能重命名问题
if (-d $request_filename) {
rewrite ^(.*[^/])$ $1/;
set $webdav_dest $webdav_dest/;
more_set_input_headers 'Destination: $webdav_dest';
}

# 解决webdav不能复制、移动文件问题
if ($request_method ~ (MOVE|COPY))
{
more_set_input_headers 'Destination: $webdav_dest';
}

proxy_pass http://127.0.0.1:9080;
proxy_redirect $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 Host $host;
}
}

重启nginx后,WebDAV功能全部正常,可在校园网范围内通过https://in-naswebdav.yourdomain.com/使用WebDAV服务,具体包括网络磁盘挂载、文件同步等。按照类似配置公网服务器上的frps和nginx,则可在公网通过https://out-naswebdav.yourdomain.com/使用WebDAV服务。

5. Q&A(常见问题解答)

  1. 为什么有了OwnCloud网盘还要建立NAS?

    答:OwnCloud网盘建立在服务器的固态硬盘上,容量较小。

  2. 为什么不使用frp和群晖自带的https服务?

    答:为了将网络配置尽可能地集中到1个文件上(即nginx的配置文件)便于管理。

  3. 为什么要将NAS的校园网内网穿透服务和公网内网穿透服务客户端搭建到两台机器上?

    答:因经OpenWrt的Web界面配置的frp客户端仅允许连接至1个服务端,这里我选择连接至公网服务端,则校园网的内网穿透只能在另一台服务器上实现(因该服务器同时连接至校园网和内网)。