树莓派搭建私有Memos备忘录并实现FRP内网穿透和HTTPS访问

本文实现了在树莓派上用Docker搭建一个Memos私有备忘录,并使用Nginx反向代理实现https访问和BasicAuth验证,以及借助公网服务器实现frp内网穿透。

前言

Memos是一个私有、轻量、开源、自托管的备忘录,适合记录各种内容。它的数据存储在本地,无需依赖第三方云服务,支持 Markdown 语法,并且可以通过 Docker 部署。Memos 还支持多平台访问,满足个人知识管理和团队协作的需求。是它在github上的页面

FRP是一款开源、高性能的内网穿透和反向代理工具,主要用于将内网服务通过公网节点安全地暴露到外网。为实现FRP,我们需要一台公网服务器作为FRPS,树莓派作为FRPC。
我购买的是阿里云一年99元的服务器,它的缺点是带宽只有3mbps,下载速度比较慢,完全不适合将其用作NAS的内网穿透,只能用作纯文字内容(memos)。

frp的传输速率其实并不一定被服务器带宽所限制。像本文中写的这种方式确实会受到服务器带宽的影响,但如果我们将服务器作为中转,在客户端上也部署frpc,使得P2P连接被建立,这样流量就不再直接通过服务器,服务器只用于UDP打洞,传输速率也就不再受到服务器带宽的限制。这是frp提供的一种新的代理类型,被称为XTCP,是官方文档,需要满足一些条件。

作为一个私有备忘录,我们不希望其他人访问,Basic Auth(基本认证)是一种在 HTTP 请求中提供用户名和密码的身份验证方式。首次访问受保护资源时,浏览器会弹出认证窗口,如果账号或密码错误,服务器会返回401。Basic Auth在HTTP协议中很常见,适合用于保护私有资源,但它有局限性,例如无法直接注销等。为保安全,BasicAuth必须和https配合使用,否则密码将以明文形式传输

本文实现的是以IP访问的,不包括域名。且均使用的是自签名证书,不向其他人开放服务的,有些步骤只适用于个人

(本文中树莓派的系统为Ubuntu)

一、安装Memos

可以通过Docker来安装memos(官方文档点我

1
2
3
4
5
docker run -d \
--name memos \
--publish 5230:5230 \
--volume ~/.memos/:/var/opt/memos \
neosmemo/memos:stable

顺利的话,你可以在http://IP:5230访问它了,会让你设置账号和密码。

二、通过Nginx反向代理配置https以及Basic Auth

二.1 Nginx反向代理配置https

Nginx反向代理是指客户端的请求并不直接到达后端服务器,而是先由Nginx接收,再将请求转发给后端应用。在这种情况下,客户端只与Nginx交互,让nginx把外部的请求转发到Docker容器里的服务,进而我们就可以实现https访问

首先,安装nginx

1
2
sudo apt update
sudo apt install nginx

首先,我们需要签发一个https证书。

(我是通过IP访问的,如果想通过域名访问那么就可能和我提供的方法有一些不一样)

先创建一个配置文件

1
sudo vim san.cnf

内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no

[req_distinguished_name]
C = CN
ST = Beijing
L = Beijing
O = MyOrg
OU = MyUnit
CN = xx.xx.xx.xx # 这里写服务器公网IP

[v3_req]
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
IP.1 = xx.xx.xx.xx # 这里填写服务器公网IP
IP.2 = 192.168.x.xx # 这里填写树莓派内网IP
DNS.1 = localhost

这里有两个alt_name同时包含树莓派内网IP和公网IP,目的是为了既可以访问内网地址也可以访问外网地址。

随后,用openssl创建自签名证书server_new.keyserver_new.crt,并把这两个文件移动到/etc/nginx/certs下面,并为其赋予权限:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cd ~ 

openssl req -x509 -nodes -newkey rsa:2048 -keyout server_new.key -out server_new.crt -days 3650 -config san.cnf -extensions v3_req
# 创建证书

sudo mv server_new.key /etc/nginx/certs/server_new.key
# 将key和crt移动到nginx的目录下面

sudo mv server_new.crt /etc/nginx/certs/server_new.crt

sudo chown root:root /etc/nginx/certs/server_new.*
# 赋予权限

sudo chmod 600 /etc/nginx/certs/server_new.*
# 赋予权限

/etc/nginx/sites-available/下创建一个文件,命名为memos

1
sudo vim /etc/nginx/sites-available/memos

并添加如下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server {
listen 5000 ssl http2; # 监听5000端口
server_name 192.168.x.xx xxx.xxx.xxx.xxx; # 填你的IP,可以填一个内网一个公网

# 这里和下面一行是证书的路径,在上面的命令中,我把它移到了这两个目录,如果你不是,则把路径换成你自己的。
ssl_certificate /etc/nginx/certs/server_new.crt;
ssl_certificate_key /etc/nginx/certs/server_new.key ;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
proxy_pass http://127.0.0.1:5230;

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

proxy_set_header Host $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;
}
}

随后,保存关闭

检查nginx配置文件是否正确

1
sudo nginx -t

重启nginx服务

1
sudo systemctl reload nginx

顺利的话,可以在内网里通过https://192.168.x.xx:5000访问你的memos服务了

二.2 启用basic auth

memos本身已经自带了登陆界面,basic auth只是为了加一个在http层面的认证,如果觉得没必要或者麻烦,可以跳过这个步骤。

首先安装apache2-utils

1
2
sudo apt update
sudo apt install apache2-utils

创建一个basic auth的账号和密码

1
2
cd ~
sudo htpasswd -c /etc/nginx/.htpasswd Your_Username

Your_Username改成你想要的用户名。执行后会让你设置密码。

我们需要修改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
sudo vim /etc/nginx/sites-available/memos


# 文件内容如下,我们只需要增加两行即可

server {
listen 5000 ssl http2;
server_name 192.168.x.xx;

ssl_certificate /path_to_your_crt;
ssl_certificate_key //path_to_your_key;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
auth_basic "basicauth"; # 新增1
auth_basic_user_file /etc/nginx/.htpasswd; # 新增2

proxy_pass http://127.0.0.1:5230;

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

proxy_set_header Host $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;
}
}

重启nginx

1
2
sudo nginx -t
sudo systemctl reload nginx

顺利的话,现在访问https://192.168.x.xx:5000会弹框让你输入用户名和密码。由于刚刚设置了https,现在basic auth的传输是加密的了。

三、配置frp

Github页面
FRP官方文档

请从https://github.com/fatedier/frp/releases/下载最新版本的frp。

这里需要注意,frps和frpc的架构可能是不同的,要分别下载不同版本的。树莓派是arm64,常见的服务器架构是amd64。我就在这里浪费了很长时间

通过wget下载

1
2
3
4
5
wget https://github.com/fatedier/frp/releases/download/v0.64.0/frp_0.64.0_linux_arm64.tar.gz
# (截至文章更新时(2025年10月),frp的最新版本为0.64.0)

tar -xzf frp_0.64.0_linux_arm64.tar.gz
# 解压

下载后有如下几个文件:frps frps.toml frpc.toml frpc。将带frps的放在公网服务器下,将带frpc的放在树莓派上。你可以分别在用户目录下面新建一个frpcfrps文件夹存放相关内容

关于frp的配置的参考文章,个人认为可以参考:
https://blog.hoshiroko.com/archives/37f497acabc8/

这是官方给的一个完整示例:
https://github.com/fatedier/frp/blob/dev/conf/frps_full_example.toml

下面是我的配置文件写法。把token改成你自己的,xxx也改成你自己的路径
(可以用openssl rand -base64 12命令生成一个强token,最后一个数字代表的是长度)

这里惟需要注意的是,网上有很多配置文件的写法已经过时,注意辨别版本

1
2
3
4
5
6
7
8
9
10
11
12
#frps.toml
bindAddr = "0.0.0.0"
bindPort = 7000
auth.token = "your_token"

transport.tls.certFile = "/xxx/server.crt"
transport.tls.keyFile = "/xxx/server.key"
transport.tls.trustedCaFile = "/xxx/ca.crt"

log.to = "/xxx/frps.log"
log.level = "info"
log.maxDays = 4
  • 这三行代表启用了双向身份验证。依据文档,从 v0.50.0 开始,transport.tls.enable 的默认值将会为 true,默认开启 TLS 协议加密。如果没有配置证书,是使用随机证书来加密的,可能有被中间人攻击的风险。因此可以进行双向身份验证,实现它需要借助本地CA,因此我们需要先生成一个CA,具体过程在此省略。你完全可以选择把这三行删除,下面frps同理。
1
2
3
transport.tls.certFile = "/xxx/server.crt"
transport.tls.keyFile = "/xxx/server.key"
transport.tls.trustedCaFile = "/xxx/ca.crt"
  • token的作用是,frps会验证只有token一样的frpc才能连接它,否则在公网不是被随便连接:
1
auth.token = “your_token”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#frpc.toml
serverAddr = "服务器公网IP"
serverPort = 7000
auth.token = "your_token"

transport.tls.certFile = "/xxx/client.crt"
transport.tls.keyFile = "/xxx/client.key"
transport.tls.trustedCaFile = "/xxx/ca.crt"

log.to = "/home/xxx/frp/frpc.log"
log.level = "info"
log.maxDays = 4

[[proxies]]
name = "memos-https" #随便起名
type = "tcp"
localIp = "127.0.0.1"
localPort = 5000
remotePort = xxxx
transport.useEncryption = true
transport.useCompression = true
  • remoteport就是你要在公网访问的端口:
1
2
localPort = 5000
remotePort = xxxx

接下来,我们通过systemd来启动它以及实现开机自启

/etc/systemd/system/下创建一个文件。

在frpc上:sudo vim /etc/systemd/system/frpc.service

添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#frpc.service

[Unit]
Description = FRP Client
After = network.target syslog.target
Wants = network.target

[Service]
Type = simple
# 启动frpc的命令,需修改为您的frpc的安装路径。例如我的frpc目录是/home/username/frpc:
ExecStart = /home/username/frpc -c /home/username/frp/frpc.toml

[Install]
WantedBy = multi-user.target

在frps上:
sudo vim /etc/systemd/system/frps.service

添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#frps.service

[Unit]
Description = FRP Server
After = network.target syslog.target
Wants = network.target

[Service]
Type = simple
# 启动frps的命令,需修改为您的frps的安装路径。例如我的frps目录是/root/frp:
ExecStart = /root/frp/frps -c /root/frp/frps.toml

[Install]
WantedBy = multi-user.target

保存退出后,分别执行:

1
2
3
4
5
6
7
8
9
10
11
在frpc上:
sudo systemctl daemon-reload
sudo systemctl start frpc # 启动
sudo systemctl enable frpc # 开启自启
sudo systemctl status frpc

在frps上:
sudo systemctl daemon-reload
sudo systemctl start frps # 启动
sudo systemctl enable frps # 开启自启
sudo systemctl status frps

最后记得在ufw和/或服务器安全组中启用相关端口,就可以啦φ( ̄∇ ̄o)!!!!

如有错误请指出#(投降)

本文使用CC BY-NC-SA 4.0协议进行许可