木须柄的时光工坊

探索技术与游戏乐趣的奇妙之旅

目录
基于 Picuang 部署本地图床,踩坑记录
/        

基于 Picuang 部署本地图床,踩坑记录

基于 Picuang 部署本地图床,踩坑记录

准备部署一个本地图床,用来存储博客文章的图片。之所以选择 Picuang 来构建,既方便又安全可控,而且都是陈辉大佬的项目,可以无缝配置进 Solo 博客系统。 Picuang 图床使用 Tomcat 部署,虽然方便,不过也有些小坑,特此记录一下。

安装 Tomcat 9

 1# 安装 Java 17
 2sudo apt install openjdk-17-jdk
 3
 4# 安装目录
 5mkdir -p /opt/tomcat9/
 6cd /opt/tomcat9/
 7
 8# 添加 tomcat 用户
 9useradd -r -d /opt/tomcat9 -s /bin/false tomcat
10
11# 下载 tomcat 9,最新版本可以去 apache 官网查看
12# https://tomcat.apache.org/download-90.cgi
13wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.84/bin/apache-tomcat-9.0.84.tar.gz
14
15# 解压,并去除默认的顶层目录
16tar -zxzf apache-tomcat-9.0.84.tar.gz -C /opt/tomcat9 --strip-components=1
17
18# 为 tomcat 用户添加目录的所有权限
19chown -R tomcat: /opt/tomcat9/{logs,temp,webapps,work}
20chown -R :tomcat /opt/tomcat9/
21chmod -R g+r /opt/tomcat9/conf
22chmod g+x /opt/tomcat9/conf
23chown -R tomcat /opt/tomcat9/logs/
24
25# 配置环境变量
26echo 'export CATALINA_HOME="/opt/tomcat9"' > /etc/profile.d/tomcat9.sh
27
28# 测试 JAVA_HOME 环境变量
29echo $JAVA_HOME
30# 如果不存在,则需要额外配置,可以使用此命令找到 Java 位置
31update-java-alternatives -l
32
33# 重启 tomcat9 环境变量
34source /etc/profile.d/tomcat9.sh
35
36# 配置 tomcat web 管理账户
37vim /opt/tomcat9/conf/tomcat-users.xml
38# 根据注释添加条目 
39<user username="admin" password="<must-be-changed>" roles="manager-gui"/>
40
41# 打开防火墙端口 8080
42ufw allow 8080
43
44# 运行 tomcat 启动脚本
45bash /opt/tomcat9/bin/startup.sh
46
47# 关闭服务
48bash /opt/tomcat9/bin/shutdown.sh
49
50# 运行成功后,可以设置 systemd 服务
51vim /etc/systemd/system/tomcat9.service

输入 tomcat9.service 内容如下:

 1[Unit]
 2Description=Apache Tomcat 9 Web Application Server
 3Documentation=https://tomcat.apache.org/tomcat-9.0-doc/index.html
 4After=network.target
 5
 6[Service]
 7Type=forking
 8User=tomcat
 9Group=tomcat
10
11Environment=JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
12Environment="CATALINA_HOME=/opt/tomcat9"
13Environment="CATALINA_BASE=/opt/tomcat9"
14Environment="JAVA_OPTS=-Djava.awt.headless=true"
15
16ExecStart=/opt/tomcat9/bin/startup.sh
17ExecStop=/opt/tomcat9/bin/shutdown.sh
18
19[Install]
20WantedBy=multi-user.target

最后启动 Tomcat 服务

1# 启动 tomcat 服务
2systemctl daemon-reload
3systemctl enable --now tomcat9

配置 frp 反向代理(可选)

注:如果你的 tomcat 服务直接部署在云端,则这一步可以忽略;

使用frp 反向代理,映射本地机器到公网访问,frp的完整配置过程略;

1# 修改 frpc 配置文件
2vim /opt/frp_0.33.0_linux_amd64/frpc.ini

添加新的代理字段,自定义 VPS 端的 Tomcat 服务端口为 58080

1# 配置 Tomcat9 服务
2[tomcat]
3type = tcp
4local_ip = 127.0.0.1
5local_port = 8080
6remote_port = 8080

然后重新配置 service 服务

1sudo cp frpc.ini /etc/frp
2sudo systemctl restart frpc

在 VPS 端开启 8080 的 ufw 防火墙和安全组,在浏览器中输入your_ip:8080,出现 Tomcat 欢迎页面即表示安装成功。

安装 Picuang 图床

 1# war 包安装路径 /opt/tomcat9/webapps/
 2
 3# 下载 war 包
 4wget https://github.com/adlered/Picuang/releases/download/V2.4/picuang2.4_v2.war
 5
 6# 复制包
 7mv picuang2.4_v2.war /opt/tomcat9/webapps/picuang.war
 8
 9# 重启 tomcat 服务
10sudo systemctl restart tomcat9

上传图片的默认位置:uploadImages

详细路径: /opt/tomcat9/webapps/picuang/WEB-INF/classes/static/uploadImages/

此时在浏览器上输入your_ip:8080,则可以看到 Picuang的服务已经启动好了。

image-20240105184144522.png

第一次启动服务管理,需要设置管理员密码。

image-20240105184527406.png

从这里开始就是比较坑的地方了,我在 Picuang 的解包目录下根本找不到这个 config.ini,也不知道这个配置文件应该是什么样的。

此时这个图床服务基本上算是启动完成,图片也可以正常上传,但是由于管理员密码设置的缺失,使得无法进行后台配置,而且任意匿名用户都能上传图片,这样肯定是不行的。

踩坑过程

使用 IDEA 导入源代码,找到 Prop.java是配置这个 config.ini 的源代码,打个记录输出控制台。在 IDEA 的执行环境下,这个配置文件的位置是项目的根目录,也即E:\projects\picture\Picuang-2.4

image-20240105184954917

在服务器端重新编译 Picuang,需要安装 Maven

1# 安装 maven
2sudo apt install maven
3
4# 克隆 Picuang 源代码并解压
5git clone https://github.com/adlered/Picuang.git
6
7# 使用 maven 编译项目
8mvn clean package

image-20240105195049898

编译好的 war 包在 target 目录下,把修改后的 war 包复制到 Tomcat 的 webapps 目录下重启服务;

作为对比,在 Tomcat 中执行项目的控制台信息,保存在 Tomcat 目录下的 logs/catalina.out日志中;

image-20240105193410959

可以看出,在 Tomcat 容器中,这里的 config.ini 文件因为权限不够,配置出现了问题;

我们修改一下 Tomcat 的服务配置,把启动服务用户临时改为 root;

1# 临时修改 systemd 服务
2vim /etc/systemd/system/tomcat9.service

修改tomcat9.service内容,修改 User 字段

1[Service]
2Type=forking
3User=root
4Group=

重启 Tomcat 服务

1systemctl daemon-reload
2systemctl restart tomcat9

重启 Tomcat 服务之后,可以看到 读取 config.ini 成功了;

image-20240105190238157

那么这个文件到底创建在哪儿了呢?没错,就在绝对路径的根目录/下:

image-20240105190348681

由于根目录/不属于 tomcat 用户,自然在 tomcat 服务中无法对其进行修改操作;

此时最简单的解决办法,我们可以在这个 config.ini 文件内输入管理员密码,然后保持使用 root 用户运行 tomcat 服务即可;

当然,最好的解决办法还是稍微修改一下 config.ini这个文件的位置,最好放在一个合适的位置,方便查询备份;

这里简单修改一下 Prop.java中所有关于 config.ini这个文件的路径,包括 del(), put(), get(), reload() 这四个方法;

 1    public static void del() {
 2        File file = new File("/opt/tomcat9/webapps/picuang/config.ini");
 3        file.delete();
 4    }
 5
 6    public static void put() {
 7
 8        System.out.println("当前 config.ini 的设置目录是:" + System.getProperty("user.dir"));
 9        try {
10            properties.load(new BufferedInputStream(new FileInputStream("/opt/tomcat9/webapps/picuang/config.ini")));
11            System.out.println("读取 config.ini 成功");
12        } catch (FileNotFoundException e) {
13            Logger.log("Generating new profile...");
14            properties.put("imageUploadedCount", "0");
15            properties.put("version", version);
16            properties.put("password", "");
17            properties.put("adminOnly", "off");
18            properties.put("uploadLimit", "1:1");
19            properties.put("cloneLimit", "3:1");
20            try {
21                properties.store(new BufferedOutputStream(new FileOutputStream("/opt/tomcat9/webapps/picuang/config.ini")), "Save Configs File.");
22                System.out.println("新建 config.ini 成功");
23            } catch (FileNotFoundException FNFE) {
24                FNFE.printStackTrace();
25            } catch (IOException IOE) {
26                IOE.printStackTrace();
27            }
28        } catch (IOException IOE) {
29            IOE.printStackTrace();
30        }
31    }
32
33    public static String get(String key) {
34        return properties.getProperty(key);
35    }
36
37    public static void set(String key, String value) {
38        try {
39            properties.setProperty(key, value);
40            Logger.log("[Prop] Set key '" + key + "' to value '" + value + "'");
41            PrintWriter printWriter = new PrintWriter(new FileWriter("/opt/tomcat9/webapps/picuang/config.ini"), true);
42            Set set = properties.keySet();
43            for (Object object : set) {
44                String k = (String) object;
45                String v = properties.getProperty(k);
46                printWriter.println(k + "=" + v);
47            }
48        } catch (Exception e) {
49            e.printStackTrace();
50        }
51        if (!key.equals("imageUploadedCount")) {
52            reload();
53        }
54    }
55
56    public static String getVersion() {
57        return version;
58    }
59
60    public static void reload() {
61        Logger.log("Reloading profile...");
62        // Reload properties
63        try {
64            properties.load(new BufferedInputStream(new FileInputStream("/opt/tomcat9/webapps/picuang/config.ini")));
65        } catch (Exception e) {}
66        // Upload limit
67        try {
68            String uploadLimitMaster = get("uploadLimit");
69            if (uploadLimitMaster.contains(":")) {
70                int uploadLimitTime = Integer.parseInt(uploadLimitMaster.split(":")[0]);
71                int uploadLimitTimes = Integer.parseInt(uploadLimitMaster.split(":")[1]);
72                UploadController.uploadLimiter = new SimpleCurrentLimiter(uploadLimitTime, uploadLimitTimes);
73                Logger.log("Upload limit custom setting loaded (" + uploadLimitTimes + " times in " + uploadLimitTime + " second) .");
74            }
75        } catch (Exception e) {}
76        // Clone limit
77        try {
78            String cloneLimitMaster = get("cloneLimit");
79            if (cloneLimitMaster.contains(":")) {
80                int cloneLimitTime = Integer.parseInt(cloneLimitMaster.split(":")[0]);
81                int cloneLimitTimes = Integer.parseInt(cloneLimitMaster.split(":")[1]);
82                UploadController.cloneLimiter = new SimpleCurrentLimiter(cloneLimitTime, cloneLimitTimes);
83                Logger.log("Clone limit custom setting loaded (" + cloneLimitTimes + " times in " + cloneLimitTime + " second) .");
84            }
85        } catch (Exception e) {}
86    }

最后用 Maven 重新编译 war 包,部署到 Tomcat,此时就能在 /opt/tomcat9/webapps/picuang/下找到自动生成的config.ini文件了,内容如下:

1#Save Configs File.
2#Fri Jan 05 13:36:54 CST 2024
3version=V2.4
4adminOnly=on
5password=
6imageUploadedCount=0
7cloneLimit=3\:1
8uploadLimit=1\:1

在 password 字段输入密码,一切完美~

image-20240105195604621

此时就可以设置非管理员账号就无法上传图片了

image-20240105195658964

评论
取消