编程导航部署话题讨论

部署

42 参与
分享

快来分享你的内容吧~

点击登录,快来和大家讨论吧~
表情
图片
话题
打卡
综合
交流
文章
问答

服务器购买 网站部署 SSL证书

记录一下上线服务器的过程,可以给第一次接触过的学友们一些参考。 ## 一、购买服务器 像阿里云、华为云、腾讯云,都有**100/年**以内的**2核2G**的服务器,作为个人学习,给面试官浏览,都足够了。 个人也推荐整一台服务器自己玩,在上面学习linux命令、装点稀奇古怪的东西都是可以的,重置系统也很方便,所以不用担心会玩坏服务器。 各个云服务商是差不多的,这边我用腾讯云举例。 登录腾讯云后,找到轻量云服务器,可以看到这个配置的服务器 **购买和续费**都是79/年,几顿饭钱的事,买! ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/qbbhO5CHcqZQfVFq.webp) 有境外需求的(代理服务器等),可以买这个(续费不同价)。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/kqkt5x5gzVpjdNK4.webp) 直接购买就行了,这里我买的是境外的,国内的步骤也一样。 都买服务器了,还是推荐linux,性能和方便程度都大于windows。而且windows各位应该都精通了。 这个宝塔面板是基于OpenCloudOS 9操作系统,腾讯云自己做了一个带一些功能的镜像。这个可选可不选,后边可以随便换其他的镜像。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/LMPf3Gj3sXDXfCtT.webp) 下一步 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/yUkuhQOisu4JPPqx.webp) 付款完后就算购买完成了、点查看实例。(可以自己看看实例有哪些信息) ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/TYr0bIxPijaIBVbT.webp) ## 二、使用服务器 ### 1. 重装系统 购买完之后,点击实例,可以看见服务器的详情。 往下翻,可以看到重装系统,这个可以无限重装,我这边换个干净一点的系统。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/mXdAWYFlGbSETaRx.webp) 我这边选择ubuntu24.04版本,输完密码后点确认。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/WOu4JEUzajZP5gYW.webp) ### 2. xshell 连接服务器 官网下载免费版本xshell,安装。 https://www.xshell.com/zh/free-for-home-school/ 新建会话 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/FlBHTLbyKQdcsOqK.webp) 输入服务器IP ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/lWfSGS6qYUhUwuRt.webp) 输入登录用户和密码、点连接 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/kJAommCNWAuvy1Sy.webp) 保存密码 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/sHqKwF5J5tPXNFjN.webp) 成功连接 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/3VbgsSt9Wa3YF8mJ.webp) 之后可以通过xshell操作服务器了。 腾讯云也有类似操作服务器的方式,但是腾讯云需要先登录,才能操作,xshell可以直接连。 ## 三、部署服务器 ### 1. 宝塔 部署网站 #### 安装宝塔 https://www.bt.cn/new/download.html 直接复制**对应系统**的安装命令,到xshell中执行。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/6GDe9VXX6hPUIJ78.webp) 下一步 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/njTN25vzzZZH5UoJ.png) 安装完成后,会显示访问宝塔面板的地址和用户密码 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/yRnihACGKzI5OErs.png) 不小心忘了也没事,输入`sudo bt`,再输入`14`,就能看见了。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/nyqqNcn66hYMhy8P.webp) #### 登录宝塔 访问宝塔面板的外网面板,我这边访问失败了,因为访问的是12020端口,云服务商这边的端口防火墙没有打开。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/wWHdj66eQrs1FGjj.webp) 这边防火墙开放的端口有这些 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/WthmKgMquyM1HZce.webp) 可以选择在这里放行12020端口,也可以更改宝塔的面板端口,这里我把bt的端口改成8888了。修改命令是 ``` sudo bt 8 8888 ``` ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/oW7ay4tOYv9p3iWz.webp) 再次访问面板8888端口 安全模式会变更访问地址,普通模式不会变更。选哪个都无所谓 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/MSMgIedbb54YcD1Q.webp) 进去选LNMP 一键安装 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/pxafLzLIgEcml7Vl.webp) 安装完成 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/1NmNENfq8nUsWwJg.webp) #### 创建站点 点击添加站点 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/IK3Uv4gnl2vLimcf.webp) 输入完域名、点击确定 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/GYBJXLceOPCyVLTZ.webp) 点击设置 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/dMTh80wLKm6LlBbG.webp) 点击网址 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/SwlfcLHK01hp6rJ4.webp) 简单的网点就创好了 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/X4WN4yuBkUSX4EdM.webp) 在网站根目录 上传自己打包后的前端文件 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/gHXeyJfuAc1zx4te.webp) ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/7qbaj69VZRIrzN62.webp) 再刷新刚刚的网址,可以看到网址能正常跑了 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/iTDxANMC2keUvBQD.webp) #### 域名 去腾讯云官网 输入想要的域名,和后缀(字数越多、越冷门越便宜)。一般来说,10多块钱就能拿到自己名字相关的域名。长期使用的话,建议买.cn后缀的,续费便宜。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/drebP81gqt1AyeDQ.webp) 购买和备案一套流程有点繁琐,这边就不演示了。 备案结束后,域名解析一下服务器的ip,这样所有写ip的地方都可以替换为域名。比如上面写的网站地址可以改成域名。 ## 四、SSL证书 目前的网站是http协议的,在某些网络下会被认定为不安全导致无法访问。另外,https网站在SEO搜索引擎的权重更高。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/BRkhUHkopeo5gOkH.webp) 想要换成更安全的https协议,需要**SSL证书**才行。因为SSL证书是针对**域名**的,所以域名也要有。我这里用阿里云申请发的域名(腾讯云更方便)。 #### 申请SSL证书 腾讯云搜索SSL,进入SSL证书页面,点击申请免费证书。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/66rnqIhMQ9PqYzJg.webp) ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/ODAjp1b8cvTc7LJh.webp) 输入对应域名后,直接点确认 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/ESSaP9K8rCzJGTHk.webp) 去购买域名的服务商那里,域名解析处添加一条解析 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/Ey7WnrnR5Gx7SchR.webp) 我这边用的阿里云域名,红框中是重点 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/IVzAoQfLzvWkCMZr.webp) 解析完成后,回到腾讯云,点击验证,会显示成功。这里可以点击自动续费证书,如果域名是腾讯云的,会完全自己续期。非腾讯云域名,需要手动填解析值。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/mE7xhfKY3T57OUGF.webp) #### 下载证书 证书需要上传到服务器文件,先下载,这里选择nginx,因为刚刚部署方式就是nginx ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/ACMsNQhBqddAxHhP.webp) ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/EvFn0RnGa3rv4Igz.webp) 下载完解压,得到pem和key文件 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/Qv3WG3r2BShHAmNv.png) #### 上传证书 点开宝塔站点,将pem和key文件中的内容完整的copy进去。点保存。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/oB9x4EwveDyaoDHf.webp) 现在这个SSL证书已经绑定了这个域名,现在来测试一下域名访问。 #### 使用SSL证书 **域名要先绑定IP!!** 想要输入域名访问服务器,首先要让域名和服务器IP绑定,也就是域名解析。 阿里云域名为例 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/nZrwWnKGnyDOh8kI.webp) 在上传完后,宝塔其实已经帮我们配置好了SSL证书。 我们只要在站点中添加刚刚设置的域名 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/rraJxMehMwKdXHX9.webp) 现在访问以下两个网址,都是能够访问当前站点的。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/bx6nFwJxUnaXxnBy.webp) 在**无网络限制的环境**下,没有SSL证书,不管是IP或者是域名都是可以直接访问的。 在**有网络的限制**下,比如公司环境,IP就不能直接访问。 ![image.png](https://pic.code-nav.cn/post_picture/1622413154447278081/VM7aMXP68V6m9oyA.webp)

宝塔部署的前后端项目从IP访问改成自定义域名访问

## 首先去给域名添加解析 因为我们是部署在服务器上,以IP的形式去访问的,所以 - 添加的类型是A ![](https://pic.code-nav.cn/post_picture/1808364793110532098/KZL0ZldiTkMzjM5s.png) - 主机记录就是你想要访问的二级域名的头部 比如你买了`bbb.com`,这个是主域名(也叫一级域名),然后你想要以`aaa.bbb.com`的形式去访问你的项目,那么你的主机记录就是`aaa`。如果想要直接以`bbb.com`去访问,主机记录填*@*即可,详细解释如下 ![](https://pic.code-nav.cn/post_picture/1808364793110532098/QHBgdf6dCRQurYIZ.webp) - 记录值就是你的服务器的**公网IP**地址 ## oss配置 腾讯云的CORS记得把自己的域名添加上去`http://你的域名`,这里http即可 ![](https://pic.code-nav.cn/post_picture/1808364793110532098/upk0KZ9v6A1DHhPD.webp) ## 添加域名 宝塔面板,前端中 ![](https://pic.code-nav.cn/post_picture/1808364793110532098/pIbgXeOgvHfIDoi2.webp) - 这里添加域名即可,然后配置文件略微改一下,http不改成https是因为后端就是http服务, ![](https://pic.code-nav.cn/post_picture/1808364793110532098/Ui12lLzkthun3u42.webp) **location /** 的需要放在下面 ## 然后配置SSL 1. 点击 Let's Encrypt 去申请免费90天的证书,然后下载 ![image.png](https://pic.code-nav.cn/post_picture/1808364793110532098/lEkpPXciRmtDeOc5.webp) 2. 之后来到当前证书,填写下载的压缩包里key文件和pem文件里的内容,点击保存 ![image.png](https://pic.code-nav.cn/post_picture/1808364793110532098/OwsmQG0Dgj4iBSO7.webp) - 后续想要安全**可以打开强制HTTPS** ![image.png](https://pic.code-nav.cn/post_picture/1808364793110532098/J4wAhc0470pblK6k.png) 3. 验证 ![image4.png](https://pic.code-nav.cn/post_picture/1808364793110532098/davIL8lq7DA5DVcP.png) 首先,如上图,首先认证域名得是我们填的,如果是guoziyang.com,那么你的SSL证书必须得是泛证书,关于申请方法可参考leikoo大佬的: [https://www.codefather.cn/post/1831983737277050881#heading-1](https://www.codefather.cn/post/1831983737277050881#heading-1) 然后看剩余日期是否出现,说明SSL部署成功且生效了 ## 前端更改 生产环境那里需要改成自己的域名,然后由于前面开了**强制HTTPS**,所以这里也要改成https ![](https://pic.code-nav.cn/post_picture/1808364793110532098/gkXnxAVsTnoB57hr.webp) 同样的ws这里也需要改成域名,不需要加端口号 ![](https://pic.code-nav.cn/post_picture/1808364793110532098/AtgUmWUUccknGpWt.webp) 之后正常打包 ``` npm run pure-build ``` 之后把`dist`目录里的都上传到宝塔面板,把原来的文件覆盖掉 ### 优化 - 当然这里可以改成根据环境变量来访问不同的接口 新建一个`.env`文件。然后填写 ```.env VITE_WS_BASE_URL=ws://localhost:8123 VITE_API_BASE_URL=http://localhost:8123 ``` 然后新建一个测试的,一个生产的,比如`.env.dev`、`.env.prod`,当然我们项目都上线了,暂且不像企业那样区分测试环境和生产环境。 我以`.env.prod`为例 ```.env VITE_WS_BASE_URL=ws://你的真实域名 VITE_API_BASE_URL=https://你的真实域名 ``` *VITE_API_BASE_URL* 是 https 是因为我强制打开了 https 然后代码里改成通过根据不同环境变量去读取 ```ts const API_BASE_URL = import.meta.env.VITE_API_BASE_URL // 创建 Axios 实例 const myAxios = axios.create({ baseURL: API_BASE_URL, timeout: 60000, withCredentials: true, // 是否携带凭证 }) ``` > 这里提一点,可能有人说咋不是`process.env.xxx`,因为我是 Vite 项目所以是`import.meta.xxx`,对于vue-cli创建的项目是`process.env.xxx`。更简单一点,你看下你项目里是`vue.config.js`还是vite.config.js,`vue.config.js`就是`process.env.xxx`,`vite.config.js`就是`import.meta.xxx` 之后记得把`.env.prod`加入到`.gitignore`中,**别提交到仓库上** 然后到package.json改下打包命令 ![image.png](https://pic.code-nav.cn/post_picture/1808364793110532098/OC9xJ4d6KqGqw3Ma.webp) 就改下之前鱼皮写的`pure-build`的后面添加`--mode prod`,意思就是打包的时候加载生产环境,即`.env.prod` > **注意哦,**如果你是`.env.producement`,那么这里就是`--mode producement`,打包和文件名得对上,不然找不到 之后我们到控制台输入`npm run pure-build`来打生产包即可,如果你想要测试下,或者像企业那样打测试环境的包,那我门再添加一条 ```json "pure-build:dev": "vite build --mode dev", ``` 之后我们在控制台输入`pure-build:dev`就意味着打的是测试环境的包了 估计有人有个疑问了,那本地呢?本地打啥包哦,我们日常开发前后端联调就是本地,没必要,真想要本地打包那就本地添加`.env.local`,同理 `package.json` 添加上`"pure-build:local":"vite build --mode local"`这个打包命令就可以用了。但是企业不一样,企业你拉项目可能会看到`.env`、`.env.local`、.`env.dev`、`.env.prod`,甚至还有个uat环境的`.env.uat`,uat环境一般是指客户公司真正使用的线上环境,甲方公司由于有定制的需求,跟我们做的产品有些方向略不一样所以就有了这个区分,这时候正式环境就是指公司内部研发产品运行的环境 ## 后端注意 后端并没有需要改的地方,只是要注意下数据库以及分库分表的位置,*localhost*是否改成了服务器的ip地址 ![](https://pic.code-nav.cn/post_picture/1808364793110532098/kOQ3WN59bOXlnQG3.webp) 宝塔面板的配置按照之前的即可 可以再浏览器输入`https://你的域名/api/doc.html`,访问成功说明没问题 > 最后就可以通过你的域名去访问前端了,当你去查看浏览器的时候,完整地址也是https 然后点击那个**锁**,会显示连接安全,毕竟配置了SSL证书 ![](https://pic.code-nav.cn/post_picture/1808364793110532098/DWNQQ1V9aDyhUEKc.webp) > 感觉 **SSL** 这玩意一定要在服务器上把 **SSL** 证书上传了才行,否则如果你的前端是部署在`vercel`上,然后添加了自定义域名(哪怕备案了),虽然能正常访问,但还是显示不安全。

后端服务线上部署

本文主要记录一次 基于 Docker + API 网关(Kong) 的后端服务线上部署实践,个人觉得还有很多细节需要完善。 整体目标是: ```bash 后端服务容器化部署 通过 API 网关统一入口 对外仅暴露 Nginx 的 HTTP 端口 ``` ## 整体请求链路说明 一次接口请求的完整流程如下: ```bash 客户端(Apifox / 浏览器) ↓ Nginx(宿主机,仅暴露 80 端口) ↓ Kong API Gateway(Docker 容器) ↓ 后端服务容器(user-service / order-service) ``` 具体到请求示例: ```bash 访问:http://域名或者IP地址/api/user/health ↓ Nginx 将请求转发至: http://127.0.0.1:8000/api/user/health (8000 端口由 Kong 使用) ↓ Kong 根据路由规则转发至: http://user-service:30122/health ``` 其中: 8000 端口 仅在宿主机本地监听 30122 / 30222 等端口 仅存在于 Docker 内部网络 ## 部署前准备 在开始部署前,需要准备: 1、已完成开发的后端服务(我这里是user-service和order-service) ,有一个/health接口 返回{"status":"ok"} 表示服务正常启动 2、一台服务器:已安装 Docker 与 Docker Compose、Nginx 常用的docker compose命令 ```bash docker compose up -d --build #强制重新构建所有镜像并启动 docker compose up -d # 若本地已有镜像,仅启动容器 docker compose up -d --build order-service # 仅构建并启动指定服务 ``` 服务器目录结构: ![在这里插入图片描述](https://pic.code-nav.cn/post_picture/1904155932949557250/m12SLmlI4W4M12Yr.webp) ## docker-compose.yml 配置说明 ```bash version: "3.9" networks: backend: driver: bridge services: kong: image: kong:3.6 container_name: kong restart: unless-stopped #自动重启 environment: KONG_DATABASE: "off" KONG_DECLARATIVE_CONFIG: /kong/kong.yml KONG_PROXY_ACCESS_LOG: /dev/stdout KONG_ADMIN_ACCESS_LOG: /dev/stdout KONG_PROXY_ERROR_LOG: /dev/stderr KONG_ADMIN_ERROR_LOG: /dev/stderr KONG_LOG_LEVEL: info volumes: - ./kong/kong.yml:/kong/kong.yml ports: - "127.0.0.1:8000:8000" # 仅宿主机可访问 - "127.0.0.1:8001:8001" # Kong Admin(本地管理) networks: - backend user-service: build: context: ./user-service dockerfile: Dockerfile image: user-service:latest container_name: user-service restart: unless-stopped expose: - "30122" # 仅 Docker 网络内可见 - "31122" networks: - backend order-service: build: context: ./order-service dockerfile: Dockerfile image: order-service:latest container_name: order-service restart: unless-stopped expose: - "30222" - "31222" networks: - backend ``` 关键点说明: expose 不会占用宿主机端口 后端服务只能被 Kong 或同一 Docker 网络内的容器访问 外部流量必须经过 Nginx → Kong ## 后端服务镜像构建(多阶段构建) 我的后端服务是使用kratos写的,如果是springboot项目,可以让ai去给你生成一个 Dockerfile文件 Dockerfile内容如下 ```bash FROM golang:1.22 AS builder COPY . /src WORKDIR /src RUN GOPROXY=https://goproxy.cn make build FROM debian:stable-slim RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ netbase \ tzdata \ && rm -rf /var/lib/apt/lists/* COPY --from=builder /src/bin /app COPY ./configs /data/conf VOLUME /logs WORKDIR /app EXPOSE 30122 EXPOSE 31122 #运行服务 CMD ["./user-service", "-conf", "/data/conf", "-env", ""] ``` ## Kong 配置(声明式) 修改 kong.yml 后,需要重启 Kong 容器: docker compose restart kong kong.yml 内容如下: ```bash _format_version: "3.0" #定义apikey的值,所有服务只要使用下面某个apikey的值,都可以鉴权成功 consumers: - username: user-service-consumer keyauth_credentials: - key: test1 - username: order-service-consumer keyauth_credentials: - key: test2 services: - name: user-service # 因为 Kong 和 user-service 在同一个 Docker 网络里 url: http://user-service:30122 routes: - name: user-route paths: - /api/user strip_path: true #把 /api/user 从路径中去掉,再转发给后端,因为我后端写的api地址是/health,前面没有/api/user plugins: - name: key-auth # 使用Kong 官方的 API Key 鉴权插件 config: key_names: - apikey hide_credentials: true # apikey不转发给后端接口,只给kong鉴权用 - name: order-service url: http://order-service:30222 routes: - name: order-route paths: - /api/order strip_path: true plugins: - name: key-auth config: key_names: - apikey hide_credentials: true ``` ## Nginx 配置(宿主机) ```bash server { listen 80; # 监听80端口 server_name <填写域名或者ip地址>; #匹配并处理所有以 /api/ 开头的请求路径 location /api/ { proxy_pass http://127.0.0.1:8000; 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; proxy_connect_timeout 3s; proxy_send_timeout 10s; proxy_read_timeout 10s; } } ``` 避坑点:location 与 proxy_pass 末尾的 / 在使用 Nginx 反向代理时,location 与 proxy_pass 末尾是否带 /,会直接影响请求路径的转发结果,这是一个非常容易被忽略但影响极大的问题。 ## 测试 携带正确的apikey ![在这里插入图片描述](https://pic.code-nav.cn/post_picture/1904155932949557250/FN2OvUkqRNCwDyjg.webp) 携带错误的apikey ![在这里插入图片描述](https://pic.code-nav.cn/post_picture/1904155932949557250/89VRTKd2pm0MvMfI.webp) ## 整体方案总结 后端服务全部运行在 Docker 容器中,服务端口仅在 Docker 内部网络暴露 外部访问统一经由 Nginx + Kong,并且访问接口时,需要在headler中携带apikey

前端部署项目又有新活【PinMe】

## 故事背景 对大多数前端开发者来说,在公司里,“部署”这件事通常由运维或 DevOps 团队负责,很少需要自己动手。可一旦回到个人项目,情况就完全不同了。 不管是写个小博客、搭个文档站,还是做个 demo 想分享给朋友,部署往往会成为最大的“拦路虎”。 常见的平台如 Vercel、Netlify 或 GitHub Pages,表面上支持“一键部署”,但实际操作起来并不轻松:你需要注册平台账号、配置域名,还得接受各类平台限制。国内一些云服务商(如阿里云、腾讯云)管控更严,操作门槛也更高。更令人担忧的是稳定性问题。一旦平台出现宕机,或是由于地区网络波动导致访问不稳定,你的项目可能随时“消失”在用户面前。虽然这类情况并不频繁,但始终让人心里不踏实。 很多时候,我们只不过想***快速上线一个小页面***,并不希望被繁琐的部署流程所困。有没有更简单、更安心的方式呢? ![0042A324.jpg](https://pic.code-nav.cn/post_picture/1643218270658023426/9Qr8A4z2PMZaExVw.webp) ## 有的有的兄弟 前段时间,我偶然发现了一个叫 PinMe 的开源工具,主打的就是「极简部署」。 PinMe 并不是要取代 Vercel 这类成熟平台,但它带来了一种新的选择:更简单、更自由、更去中心化。 如果你只是想快速上线一个小项目,或者对去中心化部署感兴趣,PinMe 值得一试。 官网:https://pinme.eth.limo/ Github:https://github.com/glitternetwork/pinme 它的使用体验非常直接: - 不需要服务器 - 不用注册账号 - 只需在项目目录下执行一条命令,项目就会被打包上传到 IPFS 网络 - 稍等片刻,就能拿到一个可访问的在线地址 实际用下来,整个流程几乎没有任何繁琐配置,不用绑定平台账号,也不用担心流量限制或隐藏收费——体验就一个字:爽。 有了它,很多场景变得异常顺手: - 临时要展示一个 demo,再也不用折腾服务器 - 写了个静态博客,不必配置复杂的 CI/CD 流程 - 做了活动页或 Landing Page,想上线就随时上线 以前遇到这类需求,可能还得纠结“用 GitHub Pages 还是 Vercel”;而现在有了 PinMe,直接一条命令,立马上链可访问。 ## 简单使用 PinMe 提供了两种方式:命令行 和 可视化界面。 ### 可视化界面 ![image.png](https://pic.code-nav.cn/post_picture/1643218270658023426/Z4hUURLQ7S05cOPL.webp) 直接上传个简单界面 OK ![image.png](https://pic.code-nav.cn/post_picture/1643218270658023426/N8Y4JGfdGcy14l13.webp) 非常简单 ## 总结 可玩性还是有的,怎么说呢,我说白了我白说了,这个玩意儿很简单就能上手。在部署一些简单界面都是ok的,毕竟开源免费还要什么自行车呢,至于其他的一些功能细节就需要大家自行探索了,快去探索吧。 ![004AC192.jpg](https://pic.code-nav.cn/post_picture/1643218270658023426/UEycxwTXAwXQfdCK.jpg)

一个域名就够了:部署多个项目的终极指南 (5分钟上手)

## 一、需求背景 + 作为独立开发者,秉持”能省则省“的原则,可以通过一些手段实现同样的效果; + 在实际的业务开发过程中,确实涉及到这样的场景,如在门户网站开发完成部署测试时给金主爸爸预览的时候,有时候带域名部署,若有修改这时候我们就会将项目划分成多个,这时候xxx.com/v1、xxx.com/v2、xxx.com/v3等等。这样既保留了工作记录,又会给甲方提供一定的情绪价值(讲个笑话,别当真); + <font style="color:rgb(33, 37, 41);">公司没钱,资源紧张,域名少,域名临时没有申请下来,不够用。这个时候,我们需要把子项目给做相应的修改。</font> <font style="color:rgb(33, 37, 41);"></font> ![008CBF30.jpg](https://pic.code-nav.cn/post_picture/1643218270658023426/0kBSafaNNZr32Ss0.jpg) ## <font style="color:rgb(33, 37, 41);">二、最终效果</font> 示例 + 个人博客网站:[https://zhydoc.com](https://zhydoc.com/) + 鱼总的云图库网站:[https://zhydoc.com/picture](https://zhydoc.com/picture) ## 三、实现步骤 ### 1、此处默认认为读者已经掌握Nginx部署单个项目的能力 ![](https://pic.code-nav.cn/post_picture/1643218270658023426/8atCQFwr54dCrKZ6.webp) ### 2、<font style="color:rgb(33, 37, 41);">子项目的vite.config.js文件的base添加区分其他项目的前缀,比如/picture/,同时在路由文件中也进行相应的修改</font> ![](https://pic.code-nav.cn/post_picture/1643218270658023426/aJVBBPzqIy3TvaJo.webp) ![](https://pic.code-nav.cn/post_picture/1643218270658023426/D8HFTxEke335fdZ6.webp) ### 3、我说白了,我白说了,其实就是达成的效果就是将‘/’变成‘/picture/’,至于怎么实现,需要根据对应的前端框架的版本以及打包工具进行确定 ### 4、修改nginx配置,以下为关键配置信息 ```xml location / { root html/main/dist/; index index.html index.htm; try_files $uri $uri/ /index.html; } location /picture { alias html/picture/dist/; try_files $uri $uri/ /picture/index.html; } ``` ### 5、<font style="color:rgb(33, 37, 41);">检查子项目中,是否有未能够添加到/picture/前缀的需要手动修改一下,添加/picture/前缀</font> <font style="color:rgb(33, 37, 41);">至此,恭喜你学会了:同一个域名下,部署多个项目...</font> ![](https://pic.code-nav.cn/post_picture/1643218270658023426/xRlG7L7HuwLB4eJN.jpg)

AI 零代码应用生成平台上线笔记

必要环境 ---- ### 后端 * JDK 21 * MySQL 数据库 * Redis * Prometheus 监控 * Grafana 可视化 ### 前端 * Nginx * Node.js * Chrome 浏览器 环境安装 ---- ### 后端 #### JDK 先安装必要依赖 ```shell sudo apt install zip unzip -y ``` 使用 [SDKMAN](https://sdkman.io/) 管理 JDK ![](https://pic.code-nav.cn/post_picture/1703323293366480898/GiHTfRZ3q3kkYgbz.webp) 输入命令安装 ```shell curl -s "https://get.sdkman.io" | bash ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/JYRLiTILOl2GfZCK.webp) ![](https://pic.code-nav.cn/post_picture/1703323293366480898/FwlU5aUysfHIVim6.webp) 安装完成后,需要手动执行命令加载配置 ```shell source "/home/motoori/.sdkman/bin/sdkman-init.sh" ``` 查看可用的 Java 版本 ```shell sdk list java ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/xEJhr3GwrRFKh3oz.webp) 安装 Java 21 并设置为默认版本 ```shell # 安装 sdk install java 21.0.8-amzn # 设置为默认版本 sdk default java 21.0.8-amzn ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/1rHn6bwi1P7j3lFO.webp) #### MySQL 进入到 `1Panel 控制台 - 应用商店`,找到 MySQL 数据库 按照图中配置,注意版本选择 8.x,并勾选允许端口外部访问,需要在服务器控制台开放 3306 端口 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/LqytbwsvmxSjGF9m.webp) 安装完成后创建数据库 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/MmCf3ICc4A8qGfT5.webp) 创建成功后使用连接工具(如 Navicat)测试连接 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/ais5c2207ikSZVUE.webp) 创建系统需要的表 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/oXJ4HqYZz1MqBlse.png) #### Redis 由于 1Panel 安装 Redis 一直超时报错,这里提供两种安装方式 1. 手动安装 进入 [Redis 官网](https://download.redis.io/releases/),选择安装版本,这里选择 7.4.4 上传到服务器,输入命令解压安装包 ```shell tar -zxvf redis-7.4.4.tar.gz ``` 编译安装 ```shell cd redis-7.4.4 make make install ``` 编译安装默认安装路径为:/usr/local/bin,如果指定路径则为: make PREFIX=/soft/redis make install PREFIX=/soft/redis 安装完成后,在任意目录输入 `redis-server` 命令即可启动 Redis 如果要以后台方式启动,则必须修改 Redis 配置文件 ```shell cp redis.conf redis.conf.bck vim redis.conf # 允许访问的地址,默认是127.0.0.1,会导致只能在本地访问。修改为0.0.0.0则可以在任意IP访问,生产环境不要设置为0.0.0.0 bind 0.0.0.0 # 守护进程,修改为yes后即可后台运行 daemonize yes # 密码,设置后访问Redis必须输入密码 requirepass 123456 ``` 启动 Redis ```shell cd /opt/redis-7.4.4 # 启动 redis-server redis.conf # 停止 # 利用redis-cli来执行 shutdown 命令,即可停止 Redis 服务, # 因为之前配置了密码,因此需要通过 -u 来指定密码 redis-cli -h localhost -p 6379 -a 123456 shutdown ``` 配置开机自启,首先,新建一个系统服务文件 ```shell vim /etc/systemd/system/redis.service [Unit] Description=redis-server After=network.target [Service] Type=forking ExecStart=/usr/local/bin/redis-server /opt/redis-7.4.4/redis.conf PrivateTmp=true [Install] WantedBy=multi-user.target ``` ```shell systemctl daemon-reload # 启动 systemctl start redis # 停止 systemctl stop redis # 重启 systemctl restart redis # 查看状态 systemctl status redis # 开机自启 systemctl enable redis ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/DbNke70X76KDAmYR.webp) 2. docker 安装 由于各种因素可能导致直接使用 `docker pull redis:7.4.4`命令可能拉取镜像失败,这里提供一个下载镜像的工作流,非常好用![https://github.com/wukongdaily/DockerTarBuilder](https://github.com/wukongdaily/DockerTarBuilder) 1Panel 自带 docker,所以无需安装,可以直接使用 导入下载的 dockers 镜像 ```shell docker load -i redis_7.4.4-amd64.tar.gz ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/jAO46UOtfSEXeOdy.webp) 查看导入的镜像 ```shell docker images ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/zCgVdLHJtVQLknUa.png) 输入命令运行 redis ```shell docker run -d --name redis -p 6379:6379 redis:7.4.4 ``` 启动时设置密码: ```shell docker run -d --name redis -p 6379:6379 redis:7.4.4 redis-server --requirepass your_password ``` 运行后,检查容器日志 ```shell docker ps docker logs ${CONTAINER_ID} ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/JiEbHmuAZwLljedD.webp) 也可以进入到容器中使用命令行验证 ```shell docker exec -it redis /bin/bash redis-cli ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/4eZ6GiRP4nxS9eRT.png) 最后,使用工具测试连接 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/Owzk5aAP434d2AhT.webp) #### Prometheus 监控 访问 [Prometheus 官网](https://prometheus.io/download/),下载对应的版本,这里选择稳定版本 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/LugRUkmGnDD78KME.webp) 下载完成后上传到服务器并解压 ```shell tar -zxvf prometheus-3.5.0.linux-amd64.tar.gz mv prometheus-3.5.0.linux-amd64 prometheus cd prometheus ``` 修改配置文件 ```shell cp prometheus.yml prometheus.yml.bak vim prometheus.yml ``` ```yaml # Prometheus 配置文件 global: scrape_interval: 15s # 全局抓取间隔 evaluation_interval: 15s # 规则评估间隔 # 告警管理器配置 (可选) alerting: alertmanagers: - static_configs: - targets: # - alertmanager:9093 # 规则文件配置 rule_files: # - "alert_rules.yml" # 可以添加告警规则 # 抓取配置 scrape_configs: # Prometheus 自身监控 - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] # Spring Boot 应用监控 - job_name: 'ai-code' metrics_path: '/example/actuator/prometheus' # Spring Boot Actuator 端点 static_configs: - targets: ['localhost:8101'] # 应用服务器地址 scrape_interval: 10s # 每 10 秒抓取一次 scrape_timeout: 10s # 抓取超时时间 ``` 启动监控 ```shell ./prometheus --config.file=prometheus.yml & ``` 服务器防火墙放开 9090 端口,浏览器访问,开启本地时间 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/T3eStV8V8Oh5YtHb.webp) #### Grafana 可视化 访问 [Grafana 官网](https://grafana.com/grafana/download),下载对应的版本 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/MAMsiuF6ytjwxGkd.webp) 解压安装包 ```shell tar -zxvf grafana-enterprise_12.1.1_16903967602_linux_amd64.tar.gz ``` 启动 grafana ```shell cd /opt/grafana-12.1.1/bin/ ./grafana-server ``` 当前启动方式为前台启动,需要配置自启动 输入如下命令 ```shell vim /usr/lib/systemd/system/grafana.service ``` 将以下配置内容写入 grafana.service ```properties [Unit] Description=Grafana After=network.target [Service] Type=notify ExecStart=/opt/grafana-12.1.1/bin/grafana-server -homepath /opt/grafana-12.1.1 Restart=on-failure [Install] WantedBy=multi-user.target ``` 设置开机启动 ```shell # 重载配置文件 systemctl daemon-reload # 设置开机自启 systemctl enable grafana # 查看 grafana状态 systemctl status grafana # 重启 grafana systemctl restart grafana # 启动 grafana systemctl start grafana # 停止 grafana systemctl stop grafana ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/mZWZnFMZ4OGfjrHC.webp) 测试页面访问,初始账号密码都是 admin,默认端口 3000 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/Oy42XObasvHhoyI6.webp) 配置数据源 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/iwfzRZSy2MiwiXlh.webp) 导入面板查看效果 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/pS2E0JLT6k12vGjv.webp) 由于目前还没有部署后端,所以都是 No data ### 前端 #### Nginx 这里使用源码编译安装,觉得麻烦的话也可以通过 `apt install -y nginx` 或 `yum install -y nginx`的方式安装 前往 [Nginx 官网](https://nginx.org/en/download.html)下载安装包,这里选择稳定版本 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/oWy94ChjIoi6PshT.webp) 安装前置依赖 centos 服务器执行如下命令安装 ```shell sudo yum install -y gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel ``` ubuntu 使用如下命令 ```shell sudo apt update sudo apt install -y build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev ``` 上传安装包到服务器 解压安装包 ```shell tar -zxvf nginx-1.28.0.tar.gz nginx-1.28.0.tar.gz ``` 得到如下结果 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/S0gV3YEgiuS9RbaG.png) 进入`nginx-1.28.0`目录,编译安装 ```shell cd nginx-1.28.0 ./configure --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_gzip_static_module \ --with-pcre ``` 出现如下提示即为安装成功,可以执行下一步 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/NZbl15a2UWIKX2Aa.webp) ```shell sudo make && make install ``` 出现如下提示,没有报错即为成功 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/5Ma8Slp159gzLidU.webp) 系统默认会把 nginx 安装在`/usr/local/nginx/`目录下 测试安装结果 进入 `nginx` 的 `conf` 目录下,修改配置文件,指定端口 这一步可以不执行,默认使用 80 端口,要注意在服务器控制台的防火墙中开放对应端口 ```shell cd /usr/local/nginx/conf vim nginx.conf ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/hiOrxSI2TUUcY2zQ.webp) 修改完成后按 esc, 输入`:wq` 保存退出 检查配置文件是否有语法错误 ```shell cd /usr/local/nginx/sbin ./nginx -t ``` 出现如下输出即为成功 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/oGECM1Ko2AmPRxAN.png) 输入命令启动 nginx ```shell ./nginx ``` 浏览器输入 `ip:port` 测试访问,出现如下输出即为成功 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/7hmJRpn8F8YcdKDz.webp) 至此,nginx 安装完成 #### Node.js 使用 [nvm 工具](https://nodejs.org/zh-cn/download)管理 Node.js ![](https://pic.code-nav.cn/post_picture/1703323293366480898/9DLHeMojllGolPcb.webp) 复制命令到服务器执行,检查安装情况 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/JQT6JOH5oJtoJrWB.png) 设置 npm 国内镜像源 ```shell npm config set registry https://registry.npmmirror.com ``` 全局安装 mermaid 图片生成工具 ```shell npm install -g @mermaid-js/mermaid-cli ``` #### Chrome 浏览器 执行命令安装 chrome 浏览器 ```shell curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/google-chrome.gpg && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list && sudo apt update && sudo apt install -y google-chrome-stable ``` 检查安装情况 ```shell google-chrome -version ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/xBKAdHYDcnVo2htb.png) 安装中文字体,否则网页无法显示中文 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/sKPMZ20Cgr9FUbe5.webp) ```shell sudo apt install -y fonts-wqy-zenhei fonts-noto-cjk && sudo fc-cache -fv ``` 后端部署 ---- 修改后端配置文件,关闭 Mybatis-Plus 日志,AI 日志,设置 Knife4j 用户名和密码 `application.yml` 中只指定加载的配置文件 ```yaml spring: profiles: active: prd ``` `application-prd.yml` 参考配置如下 ```yaml spring: application: name: ai-code-backend datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ai_code username: example password: example data: redis: host: localhost port: 6379 password: database: 0 ttl: 3600 # 连接超时时间 timeout: 5000ms # 客户端类型 client-type: jedis # Jedis连接池配置 jedis: pool: # 连接池最大连接数 max-active: 8 # 连接池最大阻塞等待时间 max-wait: 5000ms # 连接池中的最大空闲连接 max-idle: 4 # 连接池中的最小空闲连接,启动时不预创建连接 min-idle: 0 # 空闲连接检测周期(毫秒) time-between-eviction-runs: -1 # 空闲连接最小空闲时间 min-evictable-idle-time: 60000ms # 连接池耗尽时是否阻塞 block-when-exhausted: false # 是否启用池的jmx管理功能 jmx-enabled: false # 在获取连接时检查有效性 test-on-borrow: false # 在空闲时检查有效性 test-while-idle: false # 邮箱配置 mail: # host: smtp.qq.com host: smtp.163.com username: example@163.com # 邮箱授权码 password: <Your Email Password> emailFrom: example@163.com properties: mail: smtp: ssl: enable: true # session 配置 session: store-type: redis # session 30 天过期 timeout: 2592000 server: port: 8101 servlet: context-path: /example # cookie 30 天过期 session: cookie: max-age: 2592000 mybatis-plus: configuration: map-underscore-to-camel-case: true # 开启 SQL 日志(本地调试开启,上线建议关掉) # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: del_flag logic-delete-value: 1 logic-not-delete-value: 0 # springdoc-openapi项目配置 springdoc: group-configs: - group: "default" paths-to-match: "/**" packages-to-scan: com.example.aicode.controller # knife4j的增强配置,不需要增强可以不配 knife4j: setting: language: zh_cn basic: enable: true username: example password: example # 开启 actuator 监控 management: endpoints: web: exposure: include: health,info,prometheus endpoint: health: show-details: always # AI langchain4j: open-ai: chat-model: base-url: https://api.deepseek.com api-key: <Your API Key> model-name: deepseek-chat log-requests: false log-responses: false max-retries: 3 streaming-chat-model: base-url: https://api.deepseek.com api-key: <Your API Key> model-name: deepseek-chat log-requests: false log-responses: false # 推理 AI 模型配置(用于复杂的推理任务) reasoning-streaming-chat-model: base-url: https://api.deepseek.com api-key: <Your API Key> model-name: deepseek-reasoner max-tokens: 32768 temperature: 0.1 log-requests: false log-responses: false # 智能路由 AI 模型配置(用于简单的分类任务) routing-chat-model: base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 api-key: <Your API Key> model-name: qwen-turbo max-tokens: 100 log-requests: false log-responses: false # 腾讯云 COS 对象存储配置 cos: client: host: https://example.cos.ap-nanjing.myqcloud.com secretId: <Your Secret Id> secretKey: <Your Secret Key> region: ap-nanjing bucket: <Your Bucket> # Pexels 图片搜索配置 pexels: api-key: <Your API Key> # 阿里云 DashScope 配置 dashscope: api-key: <Your API Key> image-model: wan2.2-t2i-flash code: deploy: host: http://localhost:9010 ``` 还需要修改 AI 生成项目的部署路径,修改 `AppServiceImpl` 的 `deployApp` 方法 ```java @Value("${code.deploy.host:http://localhost:9010}") private String deployHost; String deployUrl = String.format("%s/%s/%s/", deployHost, "dist", deployKey); ``` 修改 `pom.xml`打包配置 ```xml <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.36</version> </path> </annotationProcessorPaths> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> ``` 在 maven 中忽略测试并打包 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/qpS9i0NacDUEBoXE.png) ![](https://pic.code-nav.cn/post_picture/1703323293366480898/4i2Yo6pO3WwHfZw4.webp) 生成后的 jar 包在`target` 目录下 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/ueV7ttYiDA3l8lOW.webp) 本地通过命令测试 jar 包启动 ```shell java -jar ai-code.jar --spring.profiles.active=prd ``` 其实在 application.yml 中制定了加载的配置文件,启动时可以不添加--spring.profiles.active=prd 可以看到应用成功启动 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/DUN6A3hjAAlQ8A8b.webp) 上传 jar 包至服务器,这里提供一个启动脚本方便管理应用 `ai-code.sh` 使用时修改相关路径,如果不使用 ARMS 则相关配置填空字符串 使用方法 * sh app.sh status -- 查看应用状态 * sh app.sh start -- 启动应用 * sh app.sh restart -- 重启应用 * sh app.sh quit -- 停止应用 * sh app.sh stop -- 强制停止应用 ```shell #!/bin/bash # 环境变量配置(不使用则填空字符串) AGENT="/app/agent/aliyun-java-agent.jar" KEY="xxx" APP_NAME="ai-code" #使用说明,提示输入参数 usage(){ echo "Usage: sh ai-code.sh [start|quit|stop|restart|status]" exit 1 } #检查程序是否在运行 is_exist(){ pid=$( ps -ef | grep ai-code.jar | grep -v grep | awk '{print $2}') #不存在返回1,存在返回0 if [ -z "${pid}" ]; then return 1 else return 0 fi } #状态 status(){ is_exist if [ $? -eq "0" ]; then echo "ai-code is running. Pid is ${pid} " else echo "ai-code is NOT running. " fi } #安全退出 quit(){ is_exist if [ $? -eq "0" ]; then echo "kill process ------>" $pid kill $pid else echo "ai-code is NOT running. " fi } #强制退出 stop(){ is_exist if [ $? -eq "0" ]; then echo "kill process ------>" $pid kill -9 $pid else echo "ai-code is NOT running. " fi } #启动 start(){ is_exist if [ $? -eq "0" ]; then echo "ai-code is already running. Pid is ${pid} " else cd /app/backend # 构建 ARMS 命令参数 - 如果不使用 ARMS 则相关配置填空字符串 JAVA_OPTS="" if [ -n "${AGENT}" ] && [ -n "${KEY}" ] && [ -n "${APP_NAME}" ]; then JAVA_OPTS="-javaagent:${AGENT} -Darms.licenseKey=${KEY} -Darms.appName=${APP_NAME}" echo "Using ARMS agent configuration" else echo "Skipping ARMS agent configuration" fi nohup java ${JAVA_OPTS} -jar /app/backend/ai-code.jar --spring.profiles.active=prd > /app/backend/logs/app.log 2>&1 & fi } #重启 restart(){ stop sleep 3 echo "restart time is ------>"`date +'%Y%m%d'` start } #根据输入参数,选择执行对应的方法,无参数则执行使用说明 case "$1" in "start") start ;; "quit") quit ;; "stop") stop ;; "status") status ;; "restart") restart ;; *) usage ;; esac ``` 执行命令启动项目 ```shell sh app.sh start ``` 查看启动日志 ```shell cd /app/backend/logs tail -200f app.log ``` ![](https://pic.code-nav.cn/post_picture/1703323293366480898/GWdGnk11UwQYiQ71.webp) 前端部署 ---- 前端由于我自定义了项目前缀,所以修改的配置比较多,仅供参考 修改`.env.production`,localhost 改为实际 ip ```nginx # 前端应用配置 # 服务器配置 VITE_SERVER_HOST=localhost VITE_FRONTEND_PORT=9010 VITE_BACKEND_PORT=8101 VITE_API_PREFIX=/sprinkle # 后端API基础地址 VITE_API_BASE_URL=/codeLoomApi # 应用部署域名 VITE_DEPLOY_BASE_URL=http://localhost:9010 # 应用预览静态文件域名 VITE_PREVIEW_BASE_URL=/codeLoomApi/static ``` 修改 vite.config.ts,设置全局前缀 ```typescript import { fileURLToPath, URL } from 'node:url' import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue' import vueDevTools from 'vite-plugin-vue-devtools' // https://vite.dev/config/ export default defineConfig(({ mode }) => { // 加载环境变量 const env = loadEnv(mode, process.cwd(), '') // 服务器配置 const serverHost = env.VITE_SERVER_HOST || 'localhost' const backendPort = env.VITE_BACKEND_PORT || '8101' const apiPrefix = env.VITE_API_PREFIX || '/sprinkle' return { base: mode === 'production' ? '/CodeLoom/' : '/', plugins: [vue(), vueDevTools()], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)), }, }, build: { outDir: 'CodeLoom', }, server: { proxy: { [apiPrefix]: { target: `http://${serverHost}:${backendPort}`, changeOrigin: true, secure: false, }, }, }, } }) ``` 修改 `env.ts` 中获取部署 url 的方法 ```typescript /** * 获取部署URL * @param deployKey 部署密钥 * @returns 完整的部署URL */ export const getDeployUrl = (deployKey: string): string => { return `${DEPLOY_BASE_URL}/dist/${deployKey}` } ``` 修改全局响应拦截器,匹配前缀 ```typescript myAxios.interceptors.response.use( function (response) { const { data } = response // 未登录 if (data.code === 40100) { const basePath = import.meta.env.BASE_URL || '/' const currentPath = window.location.pathname // 移除base路径前缀来获取实际的路由路径 const routePath = currentPath.startsWith(basePath) ? currentPath.slice(basePath.length - 1) : currentPath const publicPaths = [ '/', '/user/login', '/user/register', '/help/docs', '/help/about', '/legal/terms', '/legal/privacy', ] // 不是获取用户信息的请求,并且用户目前不在公开页面,则跳转到登录页面 if ( !response.request.responseURL.includes('user/get/login') && !publicPaths.some((path) => routePath === path || (path === '/' && routePath === '/')) ) { message.warning('请先登录') window.location.href = basePath + 'user/login' } } return response }, function (error) { return Promise.reject(error) }, ) ``` 修改 `package.json`,自定义构建命令 ```json "pure-build": "vite build" ``` 最后贴出 Nginx 配置 ```nginx map $http_origin $cors_origin { default ""; "http://1.15.243.228:9010" $http_origin; } server { listen 9010; server_name localhost; proxy_headers_hash_max_size 1024; gzip on; gzip_min_length 1k; gzip_comp_level 6; gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/json; gzip_vary on; gzip_disable "MSIE [1-6]\."; # CodeLoom应用路径 location ^~/CodeLoom { alias html/CodeLoom; index index.html index.htm; try_files $uri $uri/ /CodeLoom/index.html; } # 根路径默认处理 location / { root /usr/local/nginx/html; index index.html index.htm; try_files $uri $uri/ =404; } # 为生成的网站提供部署访问能力 location /dist/ { alias /app/backend/tmp/code_deploy/; try_files $uri $uri/ /dist/index.html =404; } location /codeLoomApi/ { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,Cookie'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'application/json; charset=utf-8'; add_header 'Content-Length' 0; add_header 'Access-Control-Allow-Origin' $cors_origin; add_header 'Access-Control-Allow-Credentials' 'true'; return 204; } # 代理到后端服务 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; proxy_set_header X-Original-URI $request_uri; proxy_set_header Origin $http_origin; proxy_read_timeout 900s; # 确保cookie正确传递 proxy_cookie_path ~^/CodeLoom(.*)$ /$1; proxy_pass http://localhost:8101/sprinkle/; # CORS头部支持 add_header 'Access-Control-Allow-Origin' $cors_origin always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Expose-Headers' 'Set-Cookie' always; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } ``` 打包后生成 CodeLoom 目录,放到 nginx 的 html 目录下,并替换 Nginx 配置文件,执行命令重启 ```shell nginx -s reload ``` 访问网页测试效果 ![](https://pic.code-nav.cn/post_picture/1703323293366480898/kJmKWx8ytGx4JJMG.webp)

让 AI 帮我部署网站,太方便了!

大家好,我是程序员鱼皮,今天分享一个用 AI 提升效率的神技巧~ 以前,我们开发一个网站,需要先提出需求、再设计方案、再写代码开发、最后部署上线。我们都知道 AI 现在写代码越来越溜了,慢慢地替代了我们程序员写代码的部分工作;但其实,AI 的能力不止于此,利用 MCP,它甚至可以直接帮我们把网站部署上线! 好好好,合着我 **只要提个一句话需求,写代码和部署都不用我来干了**,让我退化是吧? ![](https://pic.code-nav.cn/post_picture/1601072287388278786/FW9ozvtwj9FEWhzt.webp) 下面就来带大家实操一下,让 AI 帮我生成并部署个人博客网站,1 分钟学会~ ## 利用 MCP,让 AI 部署网站 ### 准备工具 我们需要用到的工具包括: - Cursor:AI 编程工具,负责调用 AI 生成代码 - EdgeOne Pages MCP:能够将网站快速部署到 CDN 并生成公开访问链接的服务 什么是 EdgeOne Pages MCP 呢? 拆解一下这几个单词: EdgeOne 是腾讯云提供的 CDN 加速服务,可以把用户的网站资源缓存到离用户最近的边缘节点,提升网站性能。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/xfyzShmeF9CivQzZ.webp) EdgeOne Pages 是基于这个 CDN 的网站部署服务,可以让你轻松地将网站部署到 CDN 上,并且得到公开访问地址,**完全不需要自己搭建服务器**。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/kUzFISXxky5Qk803.webp) MCP 则是目前很火的模型上下文协议,让 AI 模型能够轻松地使用各种工具来增强能力,完成更复杂的任务。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/iococm7OLtH2WGzI.webp) EdgeOne Pages MCP 的作用就显而易见了 —— 给 AI 提供网站部署工具,这也是一个比较热门的 MCP: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/pfdeEt9t8MLwzPAY.webp) ### 快速实战 #### 1、开通 Pages 服务 首先到 [EdgeOne 控制台](https://console.cloud.tencent.com/edgeone/pages) 开通 Pages 服务: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/h26roND9fMpfmO77.webp) 开通服务后,默认进入了项目管理页面,我们先不急着创建项目: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/fCbPAy73Cj2EAJlo.webp) 由于等下要通过 MCP 完成网站部署,所以要先获取 API Token,作为调用服务的凭证: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/TTkG0zDHguG3YUu4.webp) #### 2、配置 MCP 新建一个项目文件夹 `yupi-blog`,在 Cursor 中打开,然后进入设置,添加 MCP 服务: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/8kkXvPycvG51bQEI.webp) 将这段配置复制粘贴到 MCP 配置文件中: ```json { "mcpServers": { "edgeone-pages-mcp-server": { "command": "npx", "args": ["edgeone-pages-mcp"], "env": { // 可选,如需部署文件夹或 ZIP 压缩包,则 API Token 必填 "EDGEONE_PAGES_API_TOKEN": "", // 可选,置空将会创建一个新的 Pages 项目,填入已有的项目名则会更新该项目 "EDGEONE_PAGES_PROJECT_NAME": "" } } } } ``` 注意要把 API Token 改成你自己的,并且把注释删除掉,否则会报错: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/RuhbjqV7KaVyTLjV.webp) 正常情况下,你会看到 MCP 服务成功加载,绿了绿了! ![](https://pic.code-nav.cn/post_picture/1601072287388278786/1xGNtrloCJkpHCym.webp) 这个服务提供了 2 个工具: - deploy_html:部署 HTML 内容到 EdgeOne Pages,返回公开访问 URL - deploy_folder_or_zip:部署文件夹或 ZIP 文件到EdgeOne Pages,返回公开访问 URL 注意,这个 MCP 服务需要 NPX 工具才能在本地成功启动。NPX 可以直接运行 NPM 包中的命令而无需全局安装,常用于执行脚手架工具和一次性命令。 如果你没有 NPX 命令、或者 Node.js 版本过低(最好不要低于 20),都会导致工具无法加载。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/SygmEfkDYKqk5o05.webp) 这时,你只需要到官网安装 Node.js,会自动帮你安装 NPM 和 NPX 工具: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/WgttLoteBd5msR4t.webp) 如果没有自动安装 NPX 工具,那就用 NPM 包管理工具安装 NPX: ```shell npm i -g npx ``` #### 3、生成并部署网站 准备好 MCP 服务后,下面来生成网站,输入下列提示词,让 AI 帮我生成个人博客网站: ```markdown 帮我根据程序员鱼皮的 GitHub 生成个人博客网站,极客风格,简洁大气;生成完成后部署网站 @https://github.com/liyupi ``` 查看 AI 的思考过程,它已经想到要使用 EdgeOne Pages 去部署网站了: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/EyrEWRKRdP0oeDS2.webp) 很快网站就生成并部署完成,可以看到 AI 调用了 MCP 部署 HTML 的工具,得到了访问地址: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/onvZhuq6DbWL2646.webp) 直接打开网址就看到效果了,不要太方便! ![](https://pic.code-nav.cn/post_picture/1601072287388278786/WXQ8Xp4UrQpeDlSZ.webp) 不过目前生成的网站比较简单,就一个 HTML 页面,甚至没有在本地创建代码文件。 #### 4、部署网站目录 再来尝试一个更复杂的项目吧,使用下面的提示词,让 AI 利用前端框架开发多页面网站: ```markdown 帮我根据程序员鱼皮的 GitHub 生成个人博客网站,极客风格,简洁大气; 需要包含多个页面,要求使用 Vue 框架模块化开发; 生成完成后部署网站 @https://github.com/liyupi/ ``` ![](https://pic.code-nav.cn/post_picture/1601072287388278786/LJSjc8jGvsaopjKr.webp) 这次要等待的时间会比较久,鱼皮建议大家趁这个时间接杯水,起来活动活动。最近久坐不动,我感觉自己的肩膀已经硬如磐石了。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/62BMOVGkTikLNuLK.webp) 我们会发现,虽然生成了一大堆代码,但是并没有自动部署,只是给出了部署建议: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/WHIpTgqEWL6KvKNu.webp) 看一下 AI 的思考过程,原来是使用部署工具失败了: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/H12D0ARYLbXBjUxe.webp) 经过我的测试发现,如果想部署网站目录或压缩包,最好先在 Pages 网页版创建一个项目,然后让 MCP 把网站文件传到这个项目内。 那就先利用官方提供的例子,随便部署一个网站: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/4A51Bz41yOOLKX5s.webp) 修改项目的名称为 `yupi-blog`,直接点击 “开始部署” 就好: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/bBCAP4NXAa4WGqMC.webp) 等待部署中,30 秒左右就好了: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/x3djWsAfJLvSIYUx.webp) 项目部署成功后,我们修改 Cursor MCP 的配置,填入刚刚创建的项目名称: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/Y0IYcqngY98AQnYu.webp) 然后再跟 AI 对话,让它帮我部署网站目录: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/cfoPSZQXbut3jTQ4.webp) 可以看到这次 AI 成功执行了部署工具,并且得到了访问地址: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/h6RiJUtxOHZzXdwk.webp) 看下网站效果,还不错吧,很有科技感! ![](https://pic.code-nav.cn/post_picture/1601072287388278786/gQUYfIyZRcuS73yH.webp) 不过要注意,生成的网站默认使用 **临时域名**,有效期比较短: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/H7r61lg0Ei6pAnC5.webp) 如果你有域名的话,建议配置一下自定义域名,就可以无限期访问啦~ ![](https://pic.code-nav.cn/post_picture/1601072287388278786/w3bapX8dl3LTUZH3.webp) 怎么样,是不是很简单? 等能够轻松在手机上使用 MCP 的时候,试想一下,你走在路上跟朋友聊天,朋友向你推荐了一位博主 —— 程序员鱼皮,你只需要跟 AI 说一句话,2 分钟后,就能给朋友访问介绍这个博主的网站,跟变魔术似的。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/Pa5geHkVtvh6iLP3.webp) 值得一提的是,EdgeOne Pages 目前应该是免费的,真香了。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/hLqBctvobBWdQvfa.webp) 不过即使有一天不免费了、或者增加了限制,我们也有替代方案,提前收藏一下,说不定以后会用得上~ ### 其他替代方案 替代方案就是使用 `Vercel` 这样一个网站部署工具,作用和 Pages 类似,也能一键部署网站并得到访问地址。不过国内访问它的速度可能比较慢,你懂的。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/kowhCH8Wu2C4AJie.webp) Vercel 提供了命令行工具,可以让我们通过一行命令把自己的项目部署到平台。先用 NPM 安装 Vercel CLI 工具: ```shell npm i -g vercel@latest ``` 然后,直接在想部署的项目文件夹下输入 `vercel` 命令,就能部署当前项目了: ![](https://pic.code-nav.cn/post_picture/1601072287388278786/ddgiYFmr7DUDzqa0.webp) 让 AI 完成自动部署的方法也很简单,你只需要在提示词中告诉 AI “你可以使用 vercel 命令行工具完成网站部署”,聪明如它,一定能帮你完成任务。 ------ OK,以上就是本期分享,学会的话记得给鱼皮点赞哦~ ![](https://pic.code-nav.cn/post_picture/1601072287388278786/MlSFgGRVc2ngf4VX.webp) ## 更多 💻 编程学习交流:编程导航:https://www.codefather.cn/ 📃 简历快速制作:老鱼简历:https://laoyujianli.com ✏️ 面试刷题神器:面试鸭:https://mianshiya.com 📖 AI 学习指南:AI知识库:https://ai.codefather.cn/

关于智能协同云图库部署的问题

### 问题描述 智能协同云图库部署问题,在使用宝塔面板创建站点时使用鱼皮的nginx配置仍然无法访问8123端口 ### 服务器和宝塔防火墙配置 ![image.png](https://pic.code-nav.cn/post_picture/1853685223433097218/NRmBdERkgay4ltZZ.webp) ![image.png](https://pic.code-nav.cn/post_picture/1853685223433097218/TKnUsvJPWnRY1RQL.webp) 求助怎么解决这个问题

伙伴匹配系统后端部署失败,端口问题

# Bug描述 ## 关于伙伴匹配系统后端部署的问题: 使用微信云托管平台部署后端部署失败, 这是报错:好像是拒绝连接 ![2.png](https://pic.code-nav.cn/post_picture/1644600592934424577/X5sz8yCyUCLysvlq.webp) 这是后端配置信息: ![微信截图_20250615224936.png](https://pic.code-nav.cn/post_picture/1644600592934424577/L00AjmHHMLSe6Ebn.webp) 经测试数据库和redis都可以连接成功的 # 期望结果 后端部署成功

nginx 简单配置:

b. nginx 配置详解: -------------- <img src="https://pic.code-nav.cn/post_picture/1608648175386624001/zHxLLYdQ9KoioV9U.webp" alt="AvSDZYoWcw0WxbZ.jpeg" width="100%" /> 跳转[:](https://blog.csdn.net/sheep_fur/article/details/148034942?spm=1011.2415.3001.5331) https://blog.csdn.net/sheep_fur/article/details/148034942?spm=1011.2415.3001.5331 ### ⅰ. http 块 这里我一般只配置个 gzip 原因: 当图片资源多时 会导致加载缓慢 解决: 使用gzip 压缩资源 可以减少加载耗时 ```xml http{ gzip on #开启gzip .....其他配置 } ``` ### ⅱ. sever 块 #### 1. 作用 定义一个虚拟机 可以在支持多个域名 #### 2. listen 指定nginx要监听的端口 就是浏览器访问哪个端口可以到 nginx 上面 #### 3. server_name 指定服务器的名称 localhost 或者 你的域名 #### 4. root(可选) 指定网页文件的根目录在哪 后面跟你的前端dist文件的路径 (可选) 可以在location里面详细指定 也可以在server块全局指定 #### 5. index(可选) 指定默认的首页文件 一般都是 index.html (可选) 可以在location里面详细指定 也可以在server块全局指定 #### 6. 配好后的server 效果 这一part配好后应该是这样: ```xml server{ listen 8083 server_name localhost(或者是你的域名 xx.xx.xx.xx) root /路径/路径/dist (可选) index index.html (可选) } ``` ### ⅲ. location 块 #### 1. 作用 实现URL 到 文件系统的映射 可以根据URL 来匹配相应的配置 #### 2. location 后面的 / ```xml location /{ ......剩余配置 } eg: 比如不管是 localhost:8083/xxxxx/xxxx/xxxx 还是localhost:8083/xxxxx/xxxx/xxxx/xxx/xxxx 都会走这个路径 ``` / 表示: 只要是/开头的 路径从端口号起后面的所有URL 都会被配到这个 location 上面 #### 3. root 可以进一步指定该location下的文件路径 #### 4. index 指定该location下的首页文件 index.html #### 5. proxy_pass 反向代理 指定反向代理的转发方向 **后面跟后端接口的地址** **反向代理**: **不知道后端服务器的存在** 如发给前端服务器的请求被反向代理到后端服务器后端的端口 **正向代理**: **知道后端服务器的存在** 如用魔法 将给服务器的消息由代理服务器转发 ```xml location /api { proxy_pass 你的后端地址 #这里还有一些其他的配置 很简单 proxy_redirect default; proxy_http_version 1.1; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 90s; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } ``` #### 6. try_files (解决nginx 路由匹配不到) **问题: 当部署路由项目时 跳转时会出现找不到路由页面的情况** try_files 尝试匹配文件目录 \ try_files 后面跟 $uri $uri/ /index.html; 匹配不到跳转到 /index.html 也可以 $uri $uri/ = 404 匹配不到返回404 #### 7. 配好后的 location 效果 ```xml location /{ root 你的资源路径; index index.html; #如果解决路由访问问题 #try_files $uri $uri/ /index.html; } location /api{ proxy_pass 你的后端地址; #这里还有一些其他的配置 很简单 proxy_redirect default; proxy_http_version 1.1; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 90s; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } ```

下载 APP