树莓派微型web服务器——阶段设计报告

news2024/9/29 7:24:35

文章目录

    • 1. 需求分析
      • 1.1 功能需求
        • 1.1.1 访问需求
        • 1.1.2 自定义域名需求
        • 1.1.3 下载公共文件需求
        • 1.1.4 用户体验需求
      • 1.2 技术需求
        • 1.2.1 操作系统指令
        • 1.2.2 技术栈
        • 1.2.3 内网穿透
      • 1.3 性能需求
        • 1.3.1 处理能力
        • 1.3.2 内存
        • 1.3.3 存储空间
    • 2. 可行性分析
      • 2.1 硬件方面
      • 2.2 软件方面
    • 3. 项目计划
      • 3.1 前期
      • 3.2 中期
      • 3.3 后期
    • 4. 初级阶段设计记录
      • 4.1 了解树莓派的硬件配置
      • 4.2 将各个配件连接至树莓派
        • 整体连接的实物图如下
        • 树莓派硬件情况如下
      • 4.3 学习**Linux**命令
      • 4.3 所遇到的问题
        • 4.3.1树莓派开启ssh服务
        • 4.3.2使用Windows自带的远程桌面连接失败
    • 5. 中级阶段设计记录
      • 5.1熟悉并使用相关软件
        • 5.1.1 PuTTY
        • 5.1.2 FileZilla
      • 5.2 安装相关的依赖以及软件包
      • 5.3 开启树莓派ssh服务
      • 5.4 简单的部署
      • 5.5 所遇到的问题
        • 5.5.1 FileZilla传输文件时权限不够
        • 5.5.2 访问受限
    • 6. 高级阶段设计记录
      • 6.1 使用ngrok进行内网穿透
      • 6.2 优化ngrok
      • 6.3 用**vue2**搭建一个网站
        • 6.3.1 pi-website项目层次结构
        • 6.3.2 chatgpt-web简单说明
      • 6.4 部署到树莓派上
      • 6.5 展示
      • 6.6 所遇到的问题
        • 6.6.1 nginx显示无法定位软件包
        • 6.6.2 国内ngrok服务ngrok-ittun不能使用
        • 6.6.3 80端口被占用
    • 7. 附录
      • 7.1 App.vue
      • 7.2 main.js
      • 7.3 ImageModule.vue
      • 7.4 FileModule.vue
      • 7.5 ChatingModule.vue
      • 7.6 DrawingModule.vue
      • 7.7 树莓派服务器网址
    • 8. REFERENCE

1. 需求分析

本项目是用树莓派制作一个轻量级的web服务器,提供一个公网地址供所有用户(也可限定账号登录)来进行下载图片、文件、与gpt3.5进行聊天、与midjourney进行绘画交互。简单来说,制作一个集图片、文件、聊天、绘画四个功能模块的web,用树莓派作为其web服务器,利用apache2生成内网网址,再使用ngrok进行内网穿透,使得其在公网中也可访问。

1.1 功能需求

1.1.1 访问需求

  • 普通用户访问需求:

普通用户可能有时候需要某一个特定的地方下载文件,比如学生从mystu上下载学习资料或者到ftp里面下载一些共享的文件,亦或者从邮箱上下载某些文件。在下载的时候会遇到种种问题,其中比较特别的就是离开了该局域网后就不能下载某个网站下的图片或者文件了,因此树莓派可以用作公网的微服务器来用于web的搭建、文件的传输、图片的下载…等等。

  • web开发者访问需求:

对于web开发者,假如做出了一个vue\ react 或者其他简单的html的静态页面,想让公网的全部人都看到并且能够输入网站进入该页面,而不是只有localhost或者局域网内的用户能看到,那么树莓派+apache2+ngrok+内网穿透+vue build就能实现这一点。

1.1.2 自定义域名需求

其实对于静态网站的部署有很多办法,其中免费且稳定的方法就有GitHub Page,下图就是一个使用Github Page部署一个用Slidev构建的线上ppt的例子,使用https://hiddensharp429.github.io/slidev/1就可以访问这个部署在Github上的项目了。html项目、vue打包后的项目、react打包后的项目等等都可以直接部署在Github上面,但是这个<authorname>.github.io这个二级域名你是不可以修改的,只有你购买的域名才有修改这个二级域名的权利。

由此就凸显了树莓派+ngrok的威力了,使用ngrok部署的项目可以自定义二级域名例如可以使用https://hiddensharppi.ap.ngrok.io \ https://hiddensharppi.in.ngrok.io/\ https://hiddensharppi.ngrok.com/等等域名,并且hiddensharppi这个字段是可以任意编辑的(例如我改成**https://ilovestudy.ap.ngrok.io/**完全可以)。

image-20230628224103247

image1 Github Page静态页面部署

image-20230628224141497

image2 Github Page部署Slidev项目

1.1.3 下载公共文件需求

假如有多个人需要相互之间传输下载文件,但是又不想使用微信等通讯工具来满足其需求,这时候树莓派就可以充当一个小型的文件服务器了,如果这几个人在同一个局域网内进行通讯就可以直接通过访问树莓派内存里面的文件夹share来进行文件的传输,该项目的注重的是在公网内用户如何达到这样的一个目的:“管理员上传相关的文件,来自不同局域网的用户通过输入网址来访问树莓派服务器,点击相关文件的url链接来下载他们所需要的文件”。

1.1.4 用户体验需求

用户使用树莓派的web服务器主要要求服务器具有如下特征:

  1. 域名友好的
  2. 服务稳定的
  3. 延迟较低的

对于第一点域名友好的,树莓派web服务器可以使用ngrok来进行二级域名和最大程度的域名自定义,由此可以实现第一点;

对于第二点服务稳定的,树莓派相对于电脑作为web服务器,树莓派本身机身小,不需要关机,连接简单,操作易上手等等特性使得其可以称得上是微型web服务器的最优选;

对于第三点延迟较低的,树莓派web服务器原本是用apache2进行局域网内的网址部署,但是利用了ngrok进行了内网穿透,使得本来只能局域网内访问的网址变成了在联网的情况上均可以访问的网址。

1.2 技术需求

1.2.1 操作系统指令

树莓派通常使用Raspbian作为默认操作系统,它是基于Linux的。同时也可以选择使用其他的操作系统,例如Ubuntu等,若想要完成这个项目,要求对Linux系统操作命令拥有一定的熟练度。

1.2.2 技术栈

本项目主要的涉及的技术栈有RaspbianApacheNginxhttp\tcp\ip协议ngroksshvue.jsnode.jshtmlcss等,由于该项目的树莓派使用的内存是16G的,故没有涉及到后端开发,因此之前所搭建的个人Chatgpt网站和Midjourney网站就没有上传至树莓派服务器。

1.2.3 内网穿透

本项目主要选择方向是想使用的ngrok来进行树莓派的内网穿透,主要使用过内网穿透有:国内之前比较好用的ngrok.ttun\ frp \ ngrok.ciqiuwl \ ngrok等,该项目的最后选择的是ngrok

1.3 性能需求

1.3.1 处理能力

根据项目的预期负载和网站的性质,应该选择适当的树莓派型号。不同型号的树莓派具有不同的处理器和内存规格,较高规格的型号可以处理更多的并发请求和复杂的任务。

1.3.2 内存

树莓派的内存(RAM)对于同时处理多个请求和运行内存密集型应用程序非常重要。较大的内存容量可以提高服务器的响应速度和性能。

1.3.3 存储空间

存储空间:考虑您需要存储的网站内容和相关文件的大小。选择合适的存储介质,如SD卡或外部硬盘驱动器,以满足您的存储需求。

2. 可行性分析

在命令行中使用cat /proc/cpuinfo后输出

renegadew@raspberrypi:~ $ cat /proc/cpuinfo
processor       : 0
model name      : ARMv7 Processor rev 3 (v7l)
BogoMIPS        : 108.00
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstr                                                                                                                                           m crc32
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xd08
CPU revision    : 3

processor       : 1
model name      : ARMv7 Processor rev 3 (v7l)
BogoMIPS        : 108.00
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstr                                                                                                                                           m crc32
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xd08
CPU revision    : 3

processor       : 2
model name      : ARMv7 Processor rev 3 (v7l)
BogoMIPS        : 108.00
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstr                                                                                                                                           m crc32
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xd08
CPU revision    : 3

processor       : 3
model name      : ARMv7 Processor rev 3 (v7l)
BogoMIPS        : 108.00
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstr                                                                                                                                           m crc32
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xd08
CPU revision    : 3

Hardware        : BCM2711
Revision        : c03111
Serial          : 100000002b61e311
Model           : Raspberry Pi 4 Model B Rev 1.1

image3 cat /proc/cpuinfo的输出

由于里面没有MemTotal相关字段,故需要安装lshw来查看内存情况。

### lshw通常没有默认安装的,需要手动安装。
### 第一步先更新
sudo apt update
### 第二部安装lshw
sudo apt install lshw
### 第三步执行lshw命令
sudo lshw -short | grep memory

输入该命令后输出了/0/5 memory 3838MiB System memory即内存存量为3838MiB(3.8G)。

2.1 硬件方面

使用的树莓派的型号是Raspberry Pi 4 Model B Rev 1.1,并且配备了ARMv7架构的处理器,它具有相对较强的处理能力和内存支持,通常可以胜任轻量级的Web服务器任务。

  • 处理器:BCM2711,四核ARM Cortex-A72,时钟速度1.5 GHz
  • 内存:树莓派配置了3838MiB(约3.8GB)的系统内存。
  • 网络:支持千兆以太网接口,可提供稳定的网络连接。
  • 存储:通过MicroSD卡扩展存储容量,并连接外部存储设备,如USB驱动器。
  • GPU:集成的VideoCore VI图形处理器,可提供硬件加速和视频解码支持。
  • USB接口:具有多个USB 3.0和USB 2.0接口,可连接外部设备。
  • HDMI接口:支持连接显示器或电视以显示图形界面。
  • GPIO引脚:提供了多个GPIO引脚,可用于与外部设备的交互。

综上所示对于一般的Web服务器需求,树莓派4 Model B是一个经济实惠且功能强大的选择。

2.2 软件方面

  • 操作系统:树莓派常用的操作系统是基于LinuxRaspberry Pi OS(以前称为Raspbian)。它是专门为树莓派设计的操作系统,内置了许多优化和适配。可以从树莓派官方网站下载并安装Raspberry Pi OS

  • Web服务器软件:您可以选择安装常见的Web服务器软件,如ApacheNginxLighttpd。这些软件在树莓派上都有相应的版本,并且支持常见的Web技术和协议,如HTTP和HTTPS。

  • 文件传输:使用FileZilla已经ssh通讯来完成树莓派和本地电脑之间的文件传输,从而达到不需要在树莓派中写web开发的相关代码,直接在本地windows电脑上写好后传到树莓派上即可。

  • 内网穿透:订阅了ngrok的personal类型的账号,从而可以达到自定义域名的目的。

    image-20230629013402528

image4 FileZilla软件UI

3. 项目计划

整个项目大致分为三个阶段:前期、中期和后期。

3.1 前期

  1. 了解树莓派的硬件配置
  2. 将各个配件连接至树莓派
  3. 学习Linux命令
  4. 选择项目大致的方向。

3.2 中期

  1. 熟悉并使用PuTTYFileZilla等软件将树莓派和本地电脑连接起来
  2. 在树莓派电脑上安装相关的依赖以及软件包
  3. 开启树莓派ssh服务
  4. 在本地电脑上简单设计一个html静态页面通过apache2部署到树莓派中使得其在局域网中可以访问

3.3 后期

  1. 使用ngrok进行内网穿透以及域名的自定义,将静态页面仅被局域网中的用户可见拓展到在公网可见。
  2. 使用vue 2技术搭建一个网站的首页,使用node.js调用chatgpt接口部署自己的chatgpt网站,midjourney同理。
  3. 使用vue build打包将获得的dist上传到树莓派服务器上。

4. 初级阶段设计记录

4.1 了解树莓派的硬件配置

Raspberry Pi 4 Model B Rev 1.1拥有如下配置

  • BCM2711芯片

  • 搭载四核ARM Cortex-A72处理器

  • 内存是4GB的

  • 内置了VideoCore VI图形处理器,支持OpenGL ES 3.x和硬件加速的视频解码

  • 提供了两个特殊的HDMI接口

  • 它支持千兆以太网接口

  • 并且具有两个USB 3.0接口和两个USB 2.0接口

  • 具有双频(2.4 GHz和5 GHz)802.11ac无线局域网(Wi-Fi)和蓝牙5.0,可以无线连接到网络和外部设备。

微信截图_20230629100503

image5 Raspberry Pi 4 Model B Rev 1.1硬件图

4.2 将各个配件连接至树莓派

该项目将要用到的硬件设施如下

  • 一台显示器
  • usb接口的鼠标
  • usb接口的键盘
  • 千兆网线
  • 特殊的HDMI线

整体连接的实物图如下

微信图片_20230629102211

image6 整体连接的实物图

树莓派硬件情况如下

微信图片_20230629102217

image7 树莓派硬件连接情况1

image7 树莓派硬件连接情况2

微信图片_20230629102226

image7 树莓派硬件连接情况3

4.3 学习Linux命令

以下将列出在做项目过程中学习并使用到的所有命令

sudo apt-get update //更新Ubuntu系统软件包列表
sudo apt upgrade //升级 Ubuntu 系统中已安装软件包

sudo apt install nodejs //安装nodejs
sudo apt install npm //安装npm
sudo apt-get install <packageName> //用于在 Ubuntu 系统中安装软件包
sudo apt-get install raspi2png //安装raspi2png

sudo raspi-config//打开Raspberry Pi 配置工具

sudo raspi2png -p screenshot.png //使用raspi2png进行页面截图

ifconfig //显示ip地址 
ip addr show //显示ip地址
whoami //显示当前登录用户的用户名
sudo passwd <username> //更改用户的密码
sudo nft list ruleset //查看防火墙规则
sudo service ssh status //查看ssh服务是否在运行
sudo service ssh start //开启ssh服务

ls //当前文件夹中的所有文件和子文件夹的列表
ls -l //长格式列出文件和文件夹,并包括它们的权限、所有者、大小、修改日期
ls -a //括以点开头的隐藏文件和文件夹。

sudo tar xvzf /ngrok-v3-stable-linux-amd64.tgz -C /user/local/bin //n解压grok文件到/user/local/bin目录中
sudo nautilus //以管理员身份运行文件管理器


sudo unzip /path/to/ngrok.zip //解压某个文件
sudo ngrok config add-authtoken <your authoken> //为ngrok配置token
sudo ./ngrok http 80 //使用ngrok启动树莓派服务器的80端口

cd /etc/apache2/ //跳转到指定的文件目录下
sudo vim ports.conf //用管理员的身份进入ports.conf文件进行修改

sudo service apache2 restart //重启apache2服务

4.3 所遇到的问题

4.3.1树莓派开启ssh服务

简述:
本地电脑连接树莓派需要树莓派开启ssh服务,先前一直连接不上树莓派有个原因就是树莓派的ssh服务没有开启。

解决方法:

(这里我就不在树莓派上演示了,用远程的windows电脑操控它,这样好截图)

  1. 输入sudo raspi-config进入配置树莓派配置页面

    image-20230629123036754

image8 输入sudo raspi-config命令示意图
  1. 选择第三个Interface Options选项

    image-20230629123047707

image9 sudo raspi-config后示意图

  1. 选择第二个SSH选项

    image-20230629123158040

image10 Interface Options示意图

  1. 选择选项

    image-20230629123238293

image11 SSH示意图

这样就开启了ssh服务了,值得注意的是树莓派初始的ssh管理是比较松的。

  1. 使用sudo service ssh status查看ssh服务是否开启

    image-20230629123401204

image12 验证ssh是否开启
  1. Active显示绿色的active(running)即为开启成功

    image-20230629123515918

image13 验证ssh是否开启结果图

4.3.2使用Windows自带的远程桌面连接失败

前提:

  • 在开启了树莓派的ssh连接

    image-20230629123515918

image14 验证ssh是否开启结果图

  • 查看了其ip地址

    image-20230629120344673

image15 查看树莓派ip地址结果图
  • 拥有了树莓派用户的账号密码

    image-20230629120425863

image16 树莓派账号和密码

  • 在同一个局域网内

结果:

使用该软件远程连接树莓派失败,显示异常

image-20230629115954051

image17 远程桌面链接失败

分析:

  • 树莓派的操作系统不是windows

  • 操作系统版本早于兼容版本

    image-20230629120557339

image18 可能原因

解决办法:

使用PuTTY来进行远程连接(仅命令行)

  • 本地电脑下载并安装`PuTTY**

  • 输入树莓派ip地址并填写端口号(默认22)

    image-20230629121124930

image19 PuTTY软件示意图
  • 输入树莓派账号密码

    image-20230629121200551

image20 连接后输入账号密码

显示如下页面即为连接成功

image-20230629121248179

image21 连接成功截图

注意:请确保本机与树莓派在同一局域网内,并且树莓派开启了ssh

5. 中级阶段设计记录

5.1熟悉并使用相关软件

5.1.1 PuTTY

  1. 简单介绍

PuTTY是一款集成虚拟终端、系统控制台和网络文件传输为一体的自由及开放源代码的程序。它支持多种网络协议,包括SCP,SSH,Telnet,rlogin和原始的套接字连接。——wikipedia

  1. 操作

PuTTY软件的使用在初级阶段记录中有相关描述在此就不再赘述

  1. 下载地址

https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html

5.1.2 FileZilla

  1. 简单介绍

FileZilla是一种免费的FTP客户端以及服务器端开放源代码程序,具有多种平台的软件包,可以在Windows,Linux和macOS平台上运行。服务器和客户端都支持FTP和FTPS,而客户端还可以连接到SFTP服务器。

  1. 操作
  • 在本机电脑下载并安装合适的版本

  • 打开FileZilla并填写相关字段

    image-20230629125248598

image22 FileZilla软件示意图
  • 建立连接后右边会显示出树莓派相关文件

    image-20230629125400416

image23 连接成功示意图
  • 可右键点击文件选择**上传(U)**来传输文件

    image-20230629132425331

image24 上传文件示意图

如图例,点击上传了后将会将左边全部所选文件传输到右边文件夹里面。

5.2 安装相关的依赖以及软件包

使用下列命令来给树莓派进行安装相关的软件包

sudo apt install nodejs 
sudo apt install npm 
sudo apt-get install raspi2png 
sudo apt-get install apache2

可以使用node -vnpm -v来查看npm和node是否安装成功

image-20230629130346287

image25 查看npm和node版本

5.3 开启树莓派ssh服务

该部分在4.4.1树莓派开启ssh服务中有具体的阐述,在此不再赘述。

5.4 简单的部署

在执行了5.2中的sudo apt-get install apache2命令后会在树莓派的/var/www/html生成一个apache的初始页面index.html文件。

放置在这里面的html文件都会被部署到树莓派服务器上。(前提是你的apach在运行中),下面这张图是我部署了打包后的vue项目,并非初始的index.html,一开始只有一个index.html文件。

image-20230629131410001

image26 安装apache2后index.html文件存放位置示意图

在浏览器上输入你的树莓派ip地址,这里我的树莓派ip地址是10.141.42.21,后会看到下面这个页面。

image-20230629131831896

image27 输入树莓派ip地址后页面示意图

至此简单的部署就完成了,在你所属的局域网的所有用户均可以通过使用浏览器访问树莓派的ip地址来看树莓派这个web服务器上面部署了什么页面。

值得注意的是仅限于局域网内,并非公网可访问的。

5.5 所遇到的问题

5.5.1 FileZilla传输文件时权限不够

问题背景:
想要部署自己的页面到树莓派服务器上主要有两步

  1. 删除原本的index.html相关文件
  2. 将新的index.html相关文件通过FileZilla上传到/var/www/html

在使用FileZilla进行上传和删除操作的时候会报错,显示权限不过。

解决方法:

在树莓派图形界面或直接在FileZilla中将html文件的修改权限从user->all,开放html文件夹里面的所有文件的更改权限

image-20230629134140917

image28 解决权限不够的方法示意图

5.5.2 访问受限

问题描述:

该web仅有在用户所用网络与树莓派在同一局域网下才可访问部署在树莓派上的web,假如用户使用别的网络去浏览器访问树莓派的ip地址10.141.42.21,会显示连接不上

解决办法:

使用内网穿透技术使得部署在树莓派上的web项目暴露在公网中供用户访问,将考虑使用ngrokngrok-ittunnginx等工具

6. 高级阶段设计记录

6.1 使用ngrok进行内网穿透

  1. 进入ngrok官网https://ngrok.com/

  2. 登录或者注册一个账号,这里我用Github注册了一个账号

    image-20230629134844716

image29 ngrok官网
  1. 为树莓派下载 Linux(ARM) 版本的ngrok

    image-20230629134957596

image30 ngrok下载
  1. 下载完毕后通过FileZilla将压缩包传到树莓派上

    image-20230629135326042

image31 传输ngrok压缩包
  1. 使用unzip /path/to/ngrok.zip为ngrok-v3-stable-linux-arm .tgz解压

  2. 在命令行中使用ngrok config add-authtoken <your authoken>为ngrok配置账号token

  3. 使用./ngrok http 80来启动ngrok,默认端口是80端口

    image-20230629140154397

image32 启动ngrok成功页面

启动后可以访问Forwarding后面的网址https://f4916595f05a.ngrok.app来访问树莓派上部署的web,不需要在跟树莓派同一局域网中就可以访问到该web了。

6.2 优化ngrok

单独只是这样还不够优雅,ngrok除了支持最基本的内网穿透还提供很多增值服务,其中选定服务器地区Region和二级域名subdomain功能都可以应用

  1. 登录ngrok官网进入仪表盘中的Cloud Edge选项卡中的Domains里,在这里你可以提前预定一个或者多个专属二级域名

    image-20230629141223151

image33 设置二级域名
  1. 点击右边的New Domain选项并输入你喜欢的二级域名

    image-20230629141403809

image34 设置二级域名
  1. 设置完成后,你可以使用./ngrok http --region=ap --domain=hiddensharppi.ap.ngrok.io 9000来部署你的网址

    image-20230629141921208

image35 启动带有二级域名的ngrok

这条指令有些参数是可选的,比如--region --domain以及后面的9000这个端口,具体的参数列表可参考官方中文文档http://ngrok.cn/docs.html#subdomain

6.3 用vue2搭建一个网站

该网站是用vue2 + node.js + js + vue cil来构建的,源代码会打包在一个名为pi-website的压缩包里面,同时在附录部分也会列出来。注意,由于考虑到树莓派的性能问题,故只完成了文件图片两个模块,聊天模块被单独分离出来,详情请看chatgpt-web,聊天模块暂时还没有开发出来。

6.3.1 pi-website项目层次结构

  • dist:build生成的文件

  • src:源代码目录

    • assets:静态资源目录
    • components:组件目录
      • ChatingModule.vue:聊天模块
      • DrawingModule.vue:绘画模块
      • FileModule.vue:文件模块
      • ImageModule.vue:图片模块
    • views:视图目录
      • Home
    • App.vue:根组件
    • main.js:入口文件
  • babel.config.js:Babel配置文件

  • package.json:项目配置文件

  • vue.config.js:Vue配置文件

6.3.2 chatgpt-web简单说明

​ 原本是想将chatgpt和midjourney部署到树莓派服务器的,但是由于后端开发的经验较少,并且树莓派的硬件承受不起这两个模块的并发运行,故只能将本地部署chatgpt的vue项目打包成一个rar放到服务器上了。若想要在本地部署chatgpt可按照下方这个简易的操作步骤来,也可参考压缩吗里面的README文件。

  1. 安装node和npm
  2. 安装pnmp: npm install pnpm -g
  3. 在终端打开chatgpt-web,输入命令pnpm bootstrap
  4. 添加一个新的终端CD进入services文件夹,输入pnpm install
  5. 在OPENAI_API_KEY后面填写密钥
  6. 启动魔法,尽量使用chatgpt支持的地区
  7. 在SOCKS_PROXY_HOST填写服务器的ip地址,可以使用本地主机
  8. 在SOCKS_PROXY_PORT填写魔法的端口号
  9. 配置完后在services的终端输入pnpm start启动后端
  10. 不要关闭后端的命令行,重新打开前端目录chatgpt-web,输入命令pnpm dev即可运行

image-20230629162256621

image36 成功部署本地chatgpt网站

6.4 部署到树莓派上

  1. 进入pi-website目录使用npm run build对vue项目进行打包

    image-20230629162407995

image37 vue项目打包
  1. 使用FileZilla与树莓派建立通信,并将pi-website/dist里面的所有文件上传到树莓派的www/html目录下

    image-20230629162518253

image38 将打包的vue项目上传到树莓派
  1. 打开PuTTY,进入树莓派命令行页面使用sudo service apache2 restart重启apache2服务

    image-20230629162852505

image39 重启apache2
  1. 使用./ngrok http --region=ap --domain=hiddensharppi.ap.ngrok.io 9000启动ngrok服务,将本地9000端口(apache2所启动的端口)进行内网穿透,使得在外网的用户也可访问。

    image-20230629163052303

image40 启动ngrok内网穿透
  1. 在浏览器输入Forwarding后面的网址 https://hiddensharppi.ap.ngrok.io访问web,稍等片刻页面就展示出来了。

    image-20230629163236350

image41 访问带有二级域名的网址

6.5 展示

树莓派网址:https://hiddensharppi.ap.ngrok.io/#/drawing

image-20230629163349712

image42 网站截图1

image-20230629163404795

image43 网站截图2

image-20230629163414424

image44 网站截图3

image-20230629163420941

image45 网站截图4

6.6 所遇到的问题

6.6.1 nginx显示无法定位软件包

问题背景:

使用sudo apt-get install nginx显示无法定位软件包

解决办法:

  1. 先更新软件包列表sudo apt-get update
  2. apt-cache search nginx搜索相关可用软件包
  3. 随后再使用sudo apt-get install nginx

注:该项目最后没有使用nginx,还是无法正常安装。

6.6.2 国内ngrok服务ngrok-ittun不能使用

说明从网上了解ngrok-ittun内网穿透支持二级域名的修改,并且延迟较低,但是好像从2018年开始启用ngrok-ittun就会一直显示reconnecting资料来自于腾讯云开发者社区https://cloud.tencent.com/developer/article/1093830?areaSource=106002.12

6.6.3 80端口被占用

问题背景:

许多软件启动的进程均在80端口,因此在进行web的部署的时候可能会发生冲突。

解决方法:

将apache2服务默认端口设置成9000,启动ngrok时也启动9000端口

  1. 在树莓派命令行使用cd /etc/apache2/
  2. 使用sudo vim ports.conf,对ports.conf文件进行修改。
# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default.conf

Listen 9000 //这里填写你想要它默认启动的窗口,原本是80

<IfModule ssl_module>
        Listen 443
</IfModule>

<IfModule mod_gnutls.c>
        Listen 443
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
  1. 使用sudo service apache2 restart重启apache2

7. 附录

7.1 App.vue

<!--
 * @Author: hiddenSharp429 z404878860@163.com
 * @Date: 2023-06-28 14:56:45
 * @LastEditors: hiddenSharp429 z404878860@163.com
 * @LastEditTime: 2023-06-28 18:10:54
 * @FilePath: \pi-website\src\App.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
  <body>
    <div class="main_page">
      <div
        class="page_header floating_element"
        style="display: flex; flex-direction: column; align-items: center"
      >
        <img
          src="./assets/img/bg.png"
          alt="Debian Logo"
          class="floating_element"
          style="
            width: 100px;
            height: 50px;
            position: absolute;
            top: 0;
            left: 0;
          "
        />
        <span class="floating_element" style="margin-left: 0px">
          PI website
        </span>
        <div
          class="module-container"
          style="
            width: auto;
            display: flex;
            flex-direction: row;
            margin-top: 10px;
          "
        >
          <router-link to="/image" class="module-link">
            <div class="module">
              <span>图片</span>
            </div>
          </router-link>
          <router-link to="/file" class="module-link">
            <div class="module">
              <span>文件</span>
            </div>
          </router-link>
          <router-link to="/chat" class="module-link">
            <div class="module">
              <span>聊天</span>
            </div>
          </router-link>
          <router-link to="/drawing" class="module-link">
            <div class="module">
              <span>绘画</span>
            </div>
          </router-link>
        </div>
        <router-view></router-view>
      </div>
    </div>
    <div class="validator"></div>
    <div class="tip" v-if="flag">
      <div class="first">welcome to my pi website</div>
      <div class="first">@author:hiddensharp</div>
      <div class="first">欢迎来到我的树莓派web服务器</div>
      <div class="close" @click="flag = false">×</div>
    </div>
  </body>
</template>

<script>
export default {
  name: "App",
  created() {
    setTimeout(() => {
      this.flag = false;
    }, 5000);
  },
  data() {
    return {
      flag: true,
    };
  },
};
</script>

<style scoped>
* {
  margin: 0px 0px 0px 0px;
  padding: 0px 0px 0px 0px;
}
body,
html {
  padding: 3px 3px 3px 3px;

  background-color: #d8dbe2;

  font-family: Verdana, sans-serif;
  font-size: 11pt;
  text-align: center;
}

div.main_page {
  position: relative;
  display: table;

  width: 800px;

  margin-bottom: 3px;
  margin-left: auto;
  margin-right: auto;
  padding: 0px 0px 0px 0px;

  border-width: 2px;
  border-color: #212738;
  border-style: solid;

  background-color: #ffffff;

  text-align: center;
}

div.page_header {
  height: 99px;
  width: 100%;

  background-color: #f5f6f7;
}

div.page_header span {
  margin: 15px 0px 0px 50px;

  font-size: 180%;
  font-weight: bold;
}

div.page_header img {
  margin: 3px 0px 0px 40px;

  border: 0px 0px 0px;
}

div.table_of_contents {
  clear: left;

  min-width: 200px;

  margin: 3px 3px 3px 3px;

  background-color: #ffffff;

  text-align: left;
}

div.table_of_contents_item {
  clear: left;

  width: 100%;

  margin: 4px 0px 0px 0px;

  background-color: #ffffff;

  color: #000000;
  text-align: left;
}

div.table_of_contents_item a {
  margin: 6px 0px 0px 6px;
}

div.content_section {
  margin: 3px 3px 3px 3px;

  background-color: #ffffff;

  text-align: left;
}

div.content_section_text {
  padding: 4px 8px 4px 8px;

  color: #000000;
  font-size: 100%;
}

div.content_section_text pre {
  margin: 8px 0px 8px 0px;
  padding: 8px 8px 8px 8px;

  border-width: 1px;
  border-style: dotted;
  border-color: #000000;

  background-color: #f5f6f7;

  font-style: italic;
}

div.content_section_text p {
  margin-bottom: 6px;
}

div.content_section_text ul,
div.content_section_text li {
  padding: 4px 8px 4px 16px;
}

div.section_header {
  padding: 3px 6px 3px 6px;

  background-color: #8e9cb2;

  color: #ffffff;
  font-weight: bold;
  font-size: 112%;
  text-align: center;
}

div.section_header_red {
  background-color: #cd214f;
}

div.section_header_grey {
  background-color: #9f9386;
}

.floating_element {
  position: relative;
  float: left;
}

div.table_of_contents_item a,
div.content_section_text a {
  text-decoration: none;
  font-weight: bold;
}

div.table_of_contents_item a:link,
div.table_of_contents_item a:visited,
div.table_of_contents_item a:active {
  color: #000000;
}

div.table_of_contents_item a:hover {
  background-color: #000000;

  color: #ffffff;
}

div.content_section_text a:link,
div.content_section_text a:visited,
div.content_section_text a:active {
  background-color: #dcdfe6;

  color: #000000;
}

div.content_section_text a:hover {
  background-color: #000000;

  color: #dcdfe6;
}

div.validator {
}

.tip {
  z-index: 10;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translateY(-50%) translateX(-50%);
  width: 800px;
  height: auto;
  background-color: rgba(126, 126, 126, 0.6);
  border-radius: 20px;
  color: #fff;
  text-align: center;
  font-size: 40px;

  .first {
    margin-top: 40px;
  }

  .close {
    font-size: 60px;
    position: absolute;
    top: 0;
    right: 20px;
    cursor: pointer;
  }
}
.module-link {
  text-decoration: none;
  color: #9f9386;
}
</style>

7.2 main.js

/*
 * @Author: hiddenSharp429 z404878860@163.com
 * @Date: 2023-06-28 14:56:45
 * @LastEditors: hiddenSharp429 z404878860@163.com
 * @LastEditTime: 2023-06-28 18:52:19
 * @FilePath: \pi-website\src\main.js
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import ImageModule from './components/ImageModule.vue'
import FileModule from './components/FileModule.vue'
import ChatModule from './components/ChatingModule.vue'
import DrawingModule from './components/DrawingModule.vue'

Vue.config.productionTip = false
Vue.use(VueRouter)

const routes = [
  { path: '/image', component: ImageModule },
  { path: '/file', component: FileModule },
  { path: '/chat', component: ChatModule },
  { path: '/drawing', component: DrawingModule }
]
const router = new VueRouter({
  routes
})

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

7.3 ImageModule.vue

<!--
 * @Author: hiddenSharp429 z404878860@163.com
 * @Date: 2023-06-28 14:58:44
 * @LastEditors: hiddenSharp429 z404878860@163.com
 * @LastEditTime: 2023-06-28 22:21:58
 * @FilePath: \pi-website\src\components\imageModule.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
  <div class="main_page">
    <div class="content_section floating_element">
      <div class="section_header section_header_red">
        <div id="about"></div>
        README FIRST
      </div>
      <div class="content_section_text">
        <p>
          <tt>PHOTO LIST</tt>里面是一些图片,可以点击<tt>download</tt>进行下载。也可以右击选择<tt>在新标签页中打开链接</tt>来查看图片。现在一共有六个样例图片,后期可进行添加或者删除。
        </p>
        <p></p>
      </div>
      <div class="section_header">
        <div id="changes"></div>
        PHOTO LIST
      </div>
      <div class="content_section_text">
        <div class="image-list" style="display: flex; flex-direction: column">
          <div v-for="image in images" :key="image.name" class="image-item">
            <p style="display: flex; flex-direction: column-reverse">
              {{ image.name }}
              {{ image.size }}
              <a :href="image.downloadUrl" download>Download</a>
            </p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "ImageModule",
  data() {
    return {
      images: [
        {
          name: "image1.png",
          size: "350 KB",
          downloadUrl: require("../assets/img/image1.png"),
        },
        {
          name: "image2.png",
          size: "46 KB",
          downloadUrl: require("../assets/img/image2.png"),
        },
        {
          name: "image3.png",
          size: "78 KB",
          downloadUrl: require("../assets/img/image3.png"),
        },
        {
          name: "image4.png",
          size: "419 KB",
          downloadUrl: require("../assets/img/image4.png"),
        },
        {
          name: "image5.png",
          size: "351 KB",
          downloadUrl: require("../assets/img/image5.png"),
        },
        {
          name: "image6.png",
          size: "449 KB",
          downloadUrl: require("../assets/img/image6.png"),
        },
      ],
    };
  },
};
</script>

<style scoped>
* {
  margin: 10px 0px 0px 0px;
  padding: 0px 0px 0px 0px;
}
body,
html {
  background-color: #d8dbe2;
  font-family: Verdana, sans-serif;
  font-size: 11pt;
  text-align: center;
}
div.main_page {
  position: relative;
  display: table;

  width: 800px;

  margin-bottom: 3px;
  margin-left: auto;
  margin-right: auto;
  padding: 0px 0px 0px 0px;

  border-width: 2px;
  border-color: #212738;
  border-style: solid;

  background-color: #ffffff;

  text-align: center;
}

div.table_of_contents {
  clear: left;

  min-width: 200px;

  margin: 3px 3px 3px 3px;

  background-color: #ffffff;

  text-align: left;
}

div.table_of_contents_item {
  clear: left;

  width: 100%;

  margin: 4px 0px 0px 0px;

  background-color: #ffffff;

  color: #000000;
  text-align: left;
}

div.table_of_contents_item a {
  margin: 6px 0px 0px 6px;
}

div.content_section {
  margin: 3px 3px 3px 3px;

  background-color: #ffffff;

  text-align: left;
}

div.content_section_text {
  padding: 4px 8px 4px 8px;

  color: #000000;
  font-size: 100%;
}

div.content_section_text pre {
  margin: 8px 0px 8px 0px;
  padding: 8px 8px 8px 8px;

  border-width: 1px;
  border-style: dotted;
  border-color: #000000;

  background-color: #f5f6f7;

  font-style: italic;
}

div.content_section_text p {
  margin-bottom: 6px;
}

div.content_section_text ul,
div.content_section_text li {
  padding: 4px 8px 4px 16px;
}

div.section_header {
  padding: 3px 6px 3px 6px;

  background-color: #8e9cb2;

  color: #ffffff;
  font-weight: bold;
  font-size: 112%;
  text-align: center;
}

div.section_header_red {
  background-color: #cd214f;
}

div.section_header_grey {
  background-color: #9f9386;
}

.floating_element {
  position: relative;
  float: left;
}

div.table_of_contents_item a,
div.content_section_text a {
  text-decoration: none;
  font-weight: bold;
}

div.table_of_contents_item a:link,
div.table_of_contents_item a:visited,
div.table_of_contents_item a:active {
  color: #000000;
}

div.table_of_contents_item a:hover {
  background-color: #000000;

  color: #ffffff;
}

div.content_section_text a:link,
div.content_section_text a:visited,
div.content_section_text a:active {
  background-color: #dcdfe6;

  color: #000000;
}

div.content_section_text a:hover {
  background-color: #000000;

  color: #dcdfe6;
}

div.validator {
}
</style>

7.4 FileModule.vue

<!--
 * @Author: hiddenSharp429 z404878860@163.com
 * @Date: 2023-06-28 14:59:08
 * @LastEditors: hiddenSharp429 z404878860@163.com
 * @LastEditTime: 2023-06-29 15:27:03
 * @FilePath: \pi-website\src\components\FileModule.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
  <div class="main_page">
    <div class="content_section floating_element">
      <div class="section_header section_header_red">
        <div id="about"></div>
        README FIRST
      </div>
      <div class="content_section_text">
        <p>
          <tt>PHOTO LIST</tt>里面是一些文件,可以点击<tt>download</tt>进行下载。也可以右击选择<tt>在新标签页中打开链接</tt>来查看文件。现在一共有六个样例文件,后期可进行添加或者删除。
        </p>
        <p></p>
      </div>
      <div class="section_header">
        <div id="changes"></div>
        File LIST
      </div>
      <div class="content_section_text">
        <div class="file-list" style="display: flex; flex-direction: column">
          <div v-for="file in files" :key="file.name" class="file-item">
            <p style="display: flex; flex-direction: column-reverse">
              {{ file.name }}
              {{ file.size }}
              <a :href="file.downloadUrl" download>Download</a>
            </p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "fileModule",
  data() {
    return {
      files: [
        {
          name: "file1.doc",
          size: "0 KB",
          downloadUrl: "/file/file1.doc",
        },
        {
          name: "file2.txt",
          size: "0 KB",
          downloadUrl: "/file/file2.txt",
        },
        {
          name: "file3.zip",
          size: "0 KB",
          downloadUrl: "/file/file3.zip",
        },
        {
          name: "file4.ppt",
          size: "0 KB",
          downloadUrl: "/file/file4.ppt",
        },
        {
          name: "file5.md",
          size: "0 KB",
          downloadUrl: "/file/file5.md",
        },
      ],
    };
  },
};
</script>

<style scoped>
* {
  margin: 10px 0px 0px 0px;
  padding: 0px 0px 0px 0px;
}
body,
html {
  background-color: #d8dbe2;
  font-family: Verdana, sans-serif;
  font-size: 11pt;
  text-align: center;
}
div.main_page {
  position: relative;
  display: table;

  width: 800px;

  margin-bottom: 3px;
  margin-left: auto;
  margin-right: auto;
  padding: 0px 0px 0px 0px;

  border-width: 2px;
  border-color: #212738;
  border-style: solid;

  background-color: #ffffff;

  text-align: center;
}

div.table_of_contents {
  clear: left;

  min-width: 200px;

  margin: 3px 3px 3px 3px;

  background-color: #ffffff;

  text-align: left;
}

div.table_of_contents_item {
  clear: left;

  width: 100%;

  margin: 4px 0px 0px 0px;

  background-color: #ffffff;

  color: #000000;
  text-align: left;
}

div.table_of_contents_item a {
  margin: 6px 0px 0px 6px;
}

div.content_section {
  margin: 3px 3px 3px 3px;

  background-color: #ffffff;

  text-align: left;
}

div.content_section_text {
  padding: 4px 8px 4px 8px;

  color: #000000;
  font-size: 100%;
}

div.content_section_text pre {
  margin: 8px 0px 8px 0px;
  padding: 8px 8px 8px 8px;

  border-width: 1px;
  border-style: dotted;
  border-color: #000000;

  background-color: #f5f6f7;

  font-style: italic;
}

div.content_section_text p {
  margin-bottom: 6px;
}

div.content_section_text ul,
div.content_section_text li {
  padding: 4px 8px 4px 16px;
}

div.section_header {
  padding: 3px 6px 3px 6px;

  background-color: #8e9cb2;

  color: #ffffff;
  font-weight: bold;
  font-size: 112%;
  text-align: center;
}

div.section_header_red {
  background-color: #cd214f;
}

div.section_header_grey {
  background-color: #9f9386;
}

.floating_element {
  position: relative;
  float: left;
}

div.table_of_contents_item a,
div.content_section_text a {
  text-decoration: none;
  font-weight: bold;
}

div.table_of_contents_item a:link,
div.table_of_contents_item a:visited,
div.table_of_contents_item a:active {
  color: #000000;
}

div.table_of_contents_item a:hover {
  background-color: #000000;

  color: #ffffff;
}

div.content_section_text a:link,
div.content_section_text a:visited,
div.content_section_text a:active {
  background-color: #dcdfe6;

  color: #000000;
}

div.content_section_text a:hover {
  background-color: #000000;

  color: #dcdfe6;
}

div.validator {
}
</style>

7.5 ChatingModule.vue

<!--
 * @Author: hiddenSharp429 z404878860@163.com
 * @Date: 2023-06-28 14:59:08
 * @LastEditors: hiddenSharp429 z404878860@163.com
 * @LastEditTime: 2023-06-29 16:07:08
 * @FilePath: \pi-website\src\components\FileModule.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
  <div class="main_page">
    <div class="content_section floating_element">
      <div class="section_header section_header_red">
        <div id="about"></div>
        README FIRST
      </div>
      <div class="content_section_text">
        <p>
          由于树莓派的硬件设施问题,暂不支持聊天模块,后期会可能会进行添加,下面是一个部署好了本地chatgpt的网站,详情请下载下面这个压缩包。
        </p>
        <p>简易教程</p>
        <p>1.安装node和npm</p>
        <p>2.安装pnmp: <code>npm install pnpm -g</code></p>
        <p>3.在终端打开chatgpt-web,输入命令<code>pnpm bootstrap</code></p>
        <p>4.添加一个新的终端CD进入services文件夹,输入<code>pnpm install</code></p>
        <p>5.在OPENAI_API_KEY后面填写密钥 若没有可以使用我的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</p>
        <p>6.启动魔法,尽量使用chatgpt支持的地区</p>
        <p>7.在SOCKS_PROXY_HOST填写服务器的ip地址,可以使用本地主机</p>
        <p>8.在SOCKS_PROXY_PORT填写魔法的端口号</p>
        <p>9.配置完后在services的终端输入<code>pnpm start</code>启动后端</p>
        <p>10.运行起来后若不确定是否启动成功可以访问ip:3002,若显示Cannot GET则说明成功</p>
        <p>11.不要关闭后端的命令行,重新打开前端目录chatgpt-web,输入命令<code>pnpm dev</code>即可运行  </p>
      </div>

      <div class="section_header">
        <div id="changes"></div>
        Source code
      </div>
      <div class="content_section_text">
        <div class="file-list" style="display: flex; flex-direction: column">
          <div v-for="file in files" :key="file.name" class="file-item">
            <p style="display: flex; flex-direction: column-reverse">
              {{ file.name }}
              {{ file.size }}
              <a :href="file.downloadUrl" download>Download</a>
            </p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "ChatingModule",
  data() {
    return {
      files: [
        {
          name: "chatgpt-web.rar",
          size: "593957 KB",
          downloadUrl: "/file/chatgpt-web.rar",
        },
      ],
    };
  },
};
</script>

<style scoped>
* {
  margin: 10px 0px 0px 0px;
  padding: 0px 0px 0px 0px;
}
body,
html {
  background-color: #d8dbe2;
  font-family: Verdana, sans-serif;
  font-size: 11pt;
  text-align: center;
}
div.main_page {
  position: relative;
  display: table;

  width: 800px;

  margin-bottom: 3px;
  margin-left: auto;
  margin-right: auto;
  padding: 0px 0px 0px 0px;

  border-width: 2px;
  border-color: #212738;
  border-style: solid;

  background-color: #ffffff;

  text-align: center;
}

div.table_of_contents {
  clear: left;

  min-width: 200px;

  margin: 3px 3px 3px 3px;

  background-color: #ffffff;

  text-align: left;
}

div.table_of_contents_item {
  clear: left;

  width: 100%;

  margin: 4px 0px 0px 0px;

  background-color: #ffffff;

  color: #000000;
  text-align: left;
}

div.table_of_contents_item a {
  margin: 6px 0px 0px 6px;
}

div.content_section {
  margin: 3px 3px 3px 3px;

  background-color: #ffffff;

  text-align: left;
}

div.content_section_text {
  padding: 4px 8px 4px 8px;

  color: #000000;
  font-size: 100%;
}

div.content_section_text pre {
  margin: 8px 0px 8px 0px;
  padding: 8px 8px 8px 8px;

  border-width: 1px;
  border-style: dotted;
  border-color: #000000;

  background-color: #f5f6f7;

  font-style: italic;
}

div.content_section_text p {
  margin-bottom: 6px;
}

div.content_section_text ul,
div.content_section_text li {
  padding: 4px 8px 4px 16px;
}

div.section_header {
  padding: 3px 6px 3px 6px;

  background-color: #8e9cb2;

  color: #ffffff;
  font-weight: bold;
  font-size: 112%;
  text-align: center;
}

div.section_header_red {
  background-color: #cd214f;
}

div.section_header_grey {
  background-color: #9f9386;
}

.floating_element {
  position: relative;
  float: left;
}

div.table_of_contents_item a,
div.content_section_text a {
  text-decoration: none;
  font-weight: bold;
}

div.table_of_contents_item a:link,
div.table_of_contents_item a:visited,
div.table_of_contents_item a:active {
  color: #000000;
}

div.table_of_contents_item a:hover {
  background-color: #000000;

  color: #ffffff;
}

div.content_section_text a:link,
div.content_section_text a:visited,
div.content_section_text a:active {
  background-color: #dcdfe6;

  color: #000000;
}

div.content_section_text a:hover {
  background-color: #000000;

  color: #dcdfe6;
}

div.validator {
}
</style>

7.6 DrawingModule.vue

<!--
 * @Author: hiddenSharp429 z404878860@163.com
 * @Date: 2023-06-28 14:59:08
 * @LastEditors: hiddenSharp429 z404878860@163.com
 * @LastEditTime: 2023-06-29 16:02:21
 * @FilePath: \pi-website\src\components\FileModule.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
  <div class="main_page">
    <div class="content_section floating_element">
      <div class="section_header section_header_red">
        <div id="about"></div>
        README FIRST
      </div>
      <div class="content_section_text">
        <p>
          由于树莓派的硬件设施问题,暂不支持绘画模块,后期会可能会进行添加,本地draw的网站正在紧张的研发中,敬请期待。
        </p>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "DrawingModule",
  data() {
    return {
    };
  },
};
</script>

<style scoped>
* {
  margin: 10px 0px 0px 0px;
  padding: 0px 0px 0px 0px;
}
body,
html {
  background-color: #d8dbe2;
  font-family: Verdana, sans-serif;
  font-size: 11pt;
  text-align: center;
}
div.main_page {
  position: relative;
  display: table;

  width: 800px;

  margin-bottom: 3px;
  margin-left: auto;
  margin-right: auto;
  padding: 0px 0px 0px 0px;

  border-width: 2px;
  border-color: #212738;
  border-style: solid;

  background-color: #ffffff;

  text-align: center;
}

div.table_of_contents {
  clear: left;

  min-width: 200px;

  margin: 3px 3px 3px 3px;

  background-color: #ffffff;

  text-align: left;
}

div.table_of_contents_item {
  clear: left;

  width: 100%;

  margin: 4px 0px 0px 0px;

  background-color: #ffffff;

  color: #000000;
  text-align: left;
}

div.table_of_contents_item a {
  margin: 6px 0px 0px 6px;
}

div.content_section {
  margin: 3px 3px 3px 3px;

  background-color: #ffffff;

  text-align: left;
}

div.content_section_text {
  padding: 4px 8px 4px 8px;

  color: #000000;
  font-size: 100%;
}

div.content_section_text pre {
  margin: 8px 0px 8px 0px;
  padding: 8px 8px 8px 8px;

  border-width: 1px;
  border-style: dotted;
  border-color: #000000;

  background-color: #f5f6f7;

  font-style: italic;
}

div.content_section_text p {
  margin-bottom: 6px;
}

div.content_section_text ul,
div.content_section_text li {
  padding: 4px 8px 4px 16px;
}

div.section_header {
  padding: 3px 6px 3px 6px;

  background-color: #8e9cb2;

  color: #ffffff;
  font-weight: bold;
  font-size: 112%;
  text-align: center;
}

div.section_header_red {
  background-color: #cd214f;
}

div.section_header_grey {
  background-color: #9f9386;
}

.floating_element {
  position: relative;
  float: left;
}

div.table_of_contents_item a,
div.content_section_text a {
  text-decoration: none;
  font-weight: bold;
}

div.table_of_contents_item a:link,
div.table_of_contents_item a:visited,
div.table_of_contents_item a:active {
  color: #000000;
}

div.table_of_contents_item a:hover {
  background-color: #000000;

  color: #ffffff;
}

div.content_section_text a:link,
div.content_section_text a:visited,
div.content_section_text a:active {
  background-color: #dcdfe6;

  color: #000000;
}

div.content_section_text a:hover {
  background-color: #000000;

  color: #dcdfe6;
}

div.validator {
}
</style>

7.7 树莓派服务器网址

https://hiddensharppi.ap.ngrok.io/#/drawing

8. REFERENCE

  • 【树莓派】教你用树莓派搭建简易的私人服务器!_哔哩哔哩_bilibili

  • 如何使用树莓派搞个web服务器_哔哩哔哩_bilibili

  • 【类型(教程、树莓派)】树莓派搭建Web服务器教程_哔哩哔哩_bilibili

  • liunx下,修改apache2服务器默认的80端口。_linux重定向apache2的80端口_import bugs的博客-CSDN博客

  • Ngrok配置外网域名-解决开发中所需的特定端口_ngrok指定端口端口_七夜琉璃的博客-CSDN博客

  • How to set up a custom domain | ngrok documentation

  • 五分钟实现树莓派frp内网穿透,公网访问树莓派_哔哩哔哩_bilibili

  • 5分钟学会树莓派内网穿透!树莓派FRP简单快速配置教程,不废话,就是干_哔哩哔哩_bilibili

  • 【类型(教程、树莓派)】树莓派搭建Web服务器教程_哔哩哔哩_bilibili

  • shell - 用树莓派构建一台服务器,永久运行网站 - 个人文章 - SegmentFault 思否

  • 用树莓派做一个服务器是否可行? - 知乎 (zhihu.com)

  • ChatGPT实战搭建Express与Vue3网页版chatgpt-web源码(上)_哔哩哔哩_bilibili

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/803657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux近两年高危漏洞修复过程记录

一、背景 2023年8月份&#xff0c;面对即将到来的“大运会”、“亚运会”&#xff0c;今年的例行安全护网阶段也将迎来新的挑战和时刻&#xff0c;为此相关部门发布了国家级实战攻防演练已进入紧急「备战」时刻&#xff01;这里我们主要说一下Linux OS层面的漏洞处理&#xff0…

STM32 CubeMX 定时器(普通模式和PWM模式)

STM32 CubeMX STM32 CubeMX 定时器&#xff08;普通模式和PWM模式&#xff09; STM32 CubeMXSTM32 CubeMX 普通模式一、STM32 CubeMX 设置二、代码部分STM32 CubeMX PWM模式一、STM32 CubeMX 设置二、代码部分总结 STM32 CubeMX 普通模式 一、STM32 CubeMX 设置 二、代码部分 …

数据库数据恢复-Syabse数据库存储页底层数据杂乱的数据恢复案例

数据库恢复环境&#xff1a; Sybase版本&#xff1a;SQL Anywhere 8.0。 数据库故障&#xff1a; 数据库所在的设备意外断电后&#xff0c;数据库无法启动。 错误提示&#xff1a; 使用Sybase Central连接后报错&#xff1a; 数据库故障分析&#xff1a; 经过北亚企安数据恢复…

【无标题】深圳卫视专访行云创新马洪喜:拥抱AI与云原生,深耕云智一体化创新

人工智能&#xff08;AI&#xff09;是引领新一轮科技革命和产业变革的重要驱动力。因此&#xff0c;深圳出台相关行动方案&#xff0c;统筹设立规模1,000亿元的人工智能基金群&#xff0c;引导产业集聚培育企业梯队&#xff0c;积极打造国家新一代人工智能创新发展试验区和国家…

select、epoll 的快速核心理解

一、 select 最low的就是在用户代码中自旋实现所有阻塞socket的监听。但是每次判断socket是否产生数据&#xff0c;都涉及到用户态到内核态的切换。 于是select改进&#xff1a;将fd_set传入内核态&#xff0c;由内核判断是否有数据返回&#xff1b; 然后最low的只能使用自旋…

实验室功率放大器怎么选择参数

实验室功率放大器是一种用于实验室研究和测试的电子设备&#xff0c;其主要功能是将微弱电信号放大到足够的水平以便进行研究和分析。在选择实验室功率放大器时&#xff0c;需要考虑多个参数&#xff0c;以便确保符合实验的需求。 以下是一些常见的实验室功率放大器参数和选择方…

HAL库—定时器Timer使用及PWM

文章目录 与51单片机定时对比stm32定时器工作原理&#xff1a;定时器分类&#xff1a; STM32F103C8T6定时器资源&#xff1a;定时器计数模式&#xff1a; 定时器时钟源&#xff1a;定时器溢出时间计算公式&#xff1a;PWM资源PWM输出模式&#xff1a;PWM配置&#xff08;Cube M…

多线程(Java系列6)

目录 前言&#xff1a; 1.什么是线程池 2.标准库中的线程池 3.实现线程池 结束语&#xff1a; 前言&#xff1a; 在上一节中小编带着大家了解了一下Java标准库中的定时器的使用方式并给大家实现了一下&#xff0c;那么这节中小编将分享一下多线程中的线程池。给大家讲解一…

ucore lab6 调度管理机制

练习0&#xff1a;填写已有实验 具体更改的地方如下&#xff1a; proc.c 中alloc_proc新增加内容 proc->rq NULL;list_init(&proc->run_link);//proc->run_link.next proc->run_link.prev NULL ;proc->time_slice 0;proc->lab6_run_pool.left pro…

探索网页原型设计:构建出色的用户体验

在当今数字化时代&#xff0c;用户对网页体验的要求日益提高。在网页设计过程中&#xff0c;扮演着至关重要的角色。通过网页原型设计&#xff0c;产品经理能够更好地展示和传达网页的整体布局、导航结构、元素位置和交互效果&#xff0c;从而使团队成员更清晰地了解设计意图&a…

2023年最佳咨询项目管理软件推荐,助力项目顺利进行!

咨询项目管理软件哪个好&#xff1f;用顾问的终极项目管理软件Zoho Projects的咨询软件管理知识库&#xff0c;简化流程让客户满意。 一、加强您的咨询项目管理 1、简化客户管理 通过多合一平台超越客户期望。管理客户请求、组织文件并保护机密数据。 2、跟踪您的整个投资组…

FinalShell docker容器mysql:中文显示乱码

FinalShell 中文显示乱码 在FinalShell 执行 select 语句发现表格&#xff0c;发现中文显示的问号 解决方法&#xff1a; mysql default-character-set utf8mb4 -p1234这个方法是&#xff0c;可以登录直接显示中文&#xff0c;但是在修改&#xff0c;输入中文还是不能解决。 如…

电赛培训(高频电路类赛题)学习总结

此篇文章基于全国电子设计大赛培训网的官网的高频电路类赛题总结的知识点。 高频电路赛题的相关理论知识点 &#xff08;1&#xff09;高频电路的单位 a.1kHz1000Hz不等于1KHz&#xff08;大写的K是错误的&#xff09; b.S是西门子&#xff0c;电导的单位&#xff0c;s是秒&…

5G时代的APP开发:机遇与挑战

APP开发是互联网行业中的重要组成部分&#xff0c;随着5G时代的到来&#xff0c;移动 APP开发也迎来了新的机遇和挑战。 5G时代不仅会为移动 APP开发带来新的发展机遇&#xff0c;也会给移动 APP开发带来新的挑战。对于企业和开发者而言&#xff0c;5G时代带来的机遇和挑战是并…

C语言程序设计——程序环境和预处理

一、翻译环境 &#xff08;1&#xff09;组成一个程序的每个源文件&#xff0c;通过翻译过程分布转换成对应的目标代码&#xff1b; &#xff08;2&#xff09;每个目标文件由链接器链接到一起&#xff0c;形成一个单一而完整的可执行程序&#xff1b; &#xff08;3&#xf…

基于ESP8266+网络调试助手点灯实验

文章目录 ESP8266串口wifi模块简介实验准备硬件接线程序下载注意事项总结 ESP8266串口wifi模块 简介 ESP8266 是一种低成本、高性能的 Wi-Fi 模块&#xff0c;内置了 TCP/IP 协议栈&#xff0c;它可以作为单独的无线网络控制器&#xff0c;或者与其他微控制器进行串口通信。它…

Linux之 Vim 搜索方式

方式一&#xff1a;快速搜索&#xff08;字符串完全匹配&#xff0c;区分大小写&#xff09; 格式&#xff1a; / 关键词 or &#xff1f; 关键词 /内容 #按回车键搜索 从上到下查找 ?内容 #按回车键搜索 从下到上查找 优点&#xff1a;快速定位到该关键字 回车之后&…

Spark(37):Streaming DataFrame 和 Streaming DataSet 创建

目录 0. 相关文章链接 1. 概述 2. socket source 3. file source 3.1. 读取普通文件夹内的文件 3.2. 读取自动分区的文件夹内的文件 4. kafka source 4.1. 导入依赖 4.2. 以 Streaming 模式创建 Kafka 工作流 4.3. 通过 Batch 模式创建 Kafka 工作流 5. Rate Source…

回归预测 | MATLAB实现PSO-GPR粒子群优化高斯过程回归多输入单输出回归预测

回归预测 | MATLAB实现PSO-GPR粒子群优化高斯过程回归多输入单输出回归预测 目录 回归预测 | MATLAB实现PSO-GPR粒子群优化高斯过程回归多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab基于PSO-GPR基于粒子群算法优化高斯过程回归的数据回归预…

Jmeter经过处理的变量设置全局变量

之前遇到一个问题&#xff1a;项目的某些接口是需要登录的而且登录不能多用户登录。模拟登录的时候传入请求头的其中一个参数比较复杂&#xff0c;需要登录后的某些参数拼接和加密后设置成全局变量&#xff0c;在请求头中调用这个变量&#xff0c;正常的设置全局变量的方法百度…