首页
关于
Search
1
AdGuardHome 安装及部署教程
43,057 阅读
2
关于微软Azure学生白嫖指南
10,626 阅读
3
搭建基于telegram的无限网盘
10,497 阅读
4
Oracle开放全部端口并关闭防火墙
10,418 阅读
5
最新Cloudflare免费自选IP教程(非Partner)
9,710 阅读
默认分类
技术搬砖
教学设计
故事奇谈
生活琐事
错题分析
精品软件
登录
找到
1
篇与
substore
相关的结果
2023-11-22
自建Sub-Store订阅管理转换教程
Github Peng-YM大佬的Sub-Store提供了几乎全平台的代理转换,Loon、Surge等可以安装其提供的模块直接使用,本教程是将Sub-Store搭建为网站,更方便clash等使用一、前期准备 域名,托管到 cloudflare(其它地方也行,但是 CF 相对比较方便) 证书,免费证书三个月,自动续订即可 服务器vps,配置高点,不要太低 服务器需要安装好nginx,建议小白安装好宝塔面板,部署好基本环境 二、部署过程 1、域名设置 在 cloudflare 的域名 DNS 记录里面添加两个 A 记录,一个是 substore.domain.com, 一个是 subapi.domain.com (实际 A 记录的名字随意,只要你能区分就行)见下图例子: 用 VPS架设自己的 Sub-store图片 备注:后面的代理黄云勾不勾随意,如果你用其它第三方 ssl 证书可以不勾,如果用 CF 的证书就勾上。 2、克隆项目 名称地址前端 Sub-Store-Front-Endhttps://github.com/sub-store-org/Sub-Store-Front-End.git后端 Sub-Store/backendhttps://github.com/sub-store-org/Sub-Store.git使用 git clone + 地址的方式克隆 图片 3、安装 node和pnpm环境,pm2管理器 ①下载和安装 fnm(Node.js 版本管理器) curl -fsSL https://fnm.vercel.app/install | bash用 VPS 架设自己的Sub-store图片 看上一步的提示复制粘贴 不要抄下面的②根据上一步提示执行命令:看上一步的提示复制粘贴 不要抄下面的 ③安装 node.js fnm install v16.13.2④安装 PNPM 软件包管理器 curl -fsSL https://get.pnpm.io/install.sh | sh -用 VPS 架设自己的 Sub-store图片 看上一步的提示复制粘贴 不要抄下面的⑤根据上一步提示执行命令:看上一步的提示复制粘贴 不要抄下面的 ⑥安装 pnpm npm i pnpm -g⑦安装pm2项目管理器 进入宝塔面板软件商店安装pm2项目管理器 image-20231122174553288图片 image-20231122174654449图片 4、前端修改编译 ①修改后端接口地址 宝塔自带文件管理器打开项目根目录 Sub-Store-Front-End文件夹下的.env.production文件,将文件里线上环境接口地址改为自己准备的域名,比如https://subapi.domain.com/token,token尽量复杂,下面Nginx配置需要用到,本文这里填https://subapi.domain.com/UV3yVmNYreAhkVgP image-20231122182718090图片 ②添加登录页面 由于是要部署到服务器上,即为公开的,所以还需要一个登陆页面,阻止任何人访问 在项目根目录下的src/views下新建Login.vue文件 Login.vue代码如下: <template> <div class='wrapper'> <div>欢迎使用</div> <nut-form :model-value='formData' ref='ruleForm'> <nut-form-item label='用户名' prop='name' required :rules="[{ required: true, message: '请填写用户名' }]"> <input class='nut-input-text' @blur="customBlurValidate('name')" v-model='formData.name' placeholder='请输入用户名' type='text' /> </nut-form-item> <nut-form-item label='密码' prop='pwd' required :rules="[ { required: true, message: '请填写密码' }, // { validator: customValidator, message: '必须输入数字' }, // { regex: /^(\d{1,2}|1\d{2}|200000000)$/, message: '必须输入0-200000000区间' } ]"> <input class='nut-input-text' v-model='formData.pwd' placeholder='请输入密码' type='text' /> </nut-form-item> <nut-cell> <nut-button type='primary' size='small' style='margin-right: 10px' @click='submit'>登录</nut-button> <nut-button size='small' @click='reset'>重置</nut-button> </nut-cell> </nut-form> </div> </template> <script lang='ts'> import { Notify, Toast } from '@nutui/nutui'; import { ref, reactive } from 'vue'; import { useRouter } from 'vue-router'; export default { setup() { const router = useRouter(); const formData = reactive({ name: '', pwd: '', }); const validate = (item: any) => { console.log(item); }; const ruleForm = ref<any>(null); const submit = () => { ruleForm.value.validate().then(({ valid, errors }: any) => { if (valid) { console.log('success', formData); if (formData.name == 'name') { if (formData.pwd == 'password') { Notify.success('登录成功,欢迎回来!',{ duration: 1000 }); Toast.loading('', { cover: false // 透明罩 }); sessionStorage.setItem('token', 'token') // 临时存储,关闭标签后就清除 setTimeout(() => { router.push({path: '/sub'}); // router.replace('/sub') Toast.hide(); }, 1200); } else { Notify.danger('密码错误!'); } } else { Notify.warn('用户不存在!'); } } else { console.log('error submit!!', errors); } }); }; const reset = () => { ruleForm.value.reset(); }; // 失去焦点校验 const customBlurValidate = (prop: string) => { ruleForm.value.validate(prop).then(({ valid, errors }: any) => { if (valid) { console.log('success', formData); } else { console.log('error submit!!', errors); } }); }; // 函数校验 const customValidator = (val: string) => /^\d+$/.test(val); // Promise 异步校验 const asyncValidator = (val: string) => { return new Promise((resolve) => { Toast.loading('模拟异步验证中...'); setTimeout(() => { Toast.hide(); resolve(/^400(-?)[0-9]{7}$|^1\d{10}$|^0[0-9]{2,3}-[0-9]{7,8}$/.test(val)); }, 1000); }); }; return { ruleForm, formData, validate, customValidator, asyncValidator, customBlurValidate, submit, reset }; }, }; </script> <style lang='scss' scoped> .wrapper { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; flex-direction: column; h3 { padding-bottom: 24px; } } </style>修改代码中的用户名、密码、token image-20231122183245746图片 示例: if (formData.name == 'zqzess') { if (formData.pwd == 'zqzess') { Notify.success('登录成功,欢迎回来!',{ duration: 1000 }); Toast.loading('', { cover: false // 透明罩 }); sessionStorage.setItem('token', 'code') // 临时存储,关闭标签后就清除此处sessionStorage.setItem('token', 'code')定义的token为code,一定要记住,后面路由会用到 此处formData.name == 'zqzess'定义的zqzess即为用户名 此处formData.pwd == 'zqzess'定义的zqzess即为密码 这种明文写在代码里面账号密码其实也不安全,仅作为一个简单的认证,以后有机会再改写需要后端认证的登陆 ③修改路由 接下来需要把登陆页面添加至路由里面,并加入拦截,没有token的需要跳转登陆页 项目根目录,/src/router/index.ts,添加: import Login from '@/views/Login.vue';image-20231122183720361图片 接着修改根路由,将如下代码修改为图片上的,就是将第一个path: '/'改为path: '/sub' image-20231122184529276图片 接着添加登陆路由,在path: '/:pathMatch(.*)'代码后面添加 { path: '/:pathMatch(.*)', component: NotFound, meta: { title: 'notFound', needTabBar: false, needNavBack: true, }, }, { path: '/', component: Login, meta: { title: 'login', needTabBar: false, needNavBack: false, }, }image-20231122184807929图片 在本页最后一行export default router;上面添加路由拦截 此处if (token === null || token === '' || token !== 'code') {的code即为上面登陆页填写的token router.beforeEach((to, from, next) => { // let token = window.localStorage.getItem('token') // let type = window.localStorage.getItem('type') if (to.path === '/' || to.path === '/login' || to.path === '/error') { // console.log("允许直接访问") next(); } else { // let token = window.localStorage.getItem('token') // 长期存储 let token = window.sessionStorage.getItem('token') // 临时存储,关闭标签后就清除 // console.log("需要token") if (token === null || token === '' || token !== 'code') { // console.log("无token,跳转登录") next('/'); } else { // console.log("有token") next(); } } }); export default router;image-20231122185021731图片 接着修改根目录,/src/views/SubEditor.vue,由于代码较多,可以直接搜索router.replace,会跳转到相应代码 把router.replace('/')改为router.replace('/sub') image-20231122185218430图片 ④登陆页的命名与翻译 根目录/src/locales/en.ts 可以使用搜索notFound: '404 Not Found',,再此行下面添加login: 'Login', image-20231122185424740图片 根目录/src/locales/zh.ts 搜索notFound: '地址未找到',,再此行下面添加login: '登录', image-20231122185522788图片 至此已经全部结束,接下来就是打包发布并部署服务器 ⑤前端打包 在前端 Sub-Store-Front-End文件夹下执行,安装依赖 pnpm install在前端 Sub-Store-Front-End文件夹下执行,执行打包命令 pnpm build打包好后,根目录会多出dist文件夹,此文件夹就是打包好的网站文件,也是我们需要发布服务器的 202209182143647图片 5、部署后端 进入后端项目里的backend文件夹,进入开源后端项目最新Releases下载执行文件 image-20231122190240938图片 cd /root/Sub-Store/backend wget https://github.com/sub-store-org/Sub-Store/releases/download/2.14.99/sub-store.min.js之后,执行 pnpm i完成后再执行: pm2 start sub-store.min.js完成后继续执行: pm2 save202209211913984图片 如果成功,至此后端已经成功启动 pm2常用命令 pm2 list pm2 log <name> pm2 stop id pm2 delete id6、配置网站 宝塔面板添加站点,并配置好证书 image-20231122190954530图片 将之前打包好的dist文件夹里面的所有文件剪切到substore.domain.com站点根目录,不要复制整体dist文件夹,而是里面的单个文件 subapi.domain.com域名配置反代,进入站点设置 location /UV3yVmNYreAhkVgP/{ //API-token 也要根据需要修改,尽量复杂 proxy_pass http://127.0.0.1:3000/; }image-20231122192313286图片 三、使用教程 进入网站https://substore.domain.com,输入之前设置的用户名和密码 image-20231122192447260图片 进入我的——后端设置 image-20231122192610493图片 如果后端是之前设置的线上环境地址,就不用管了,可以直接转换节点了 image-20231122182718090图片 如果不是,需要手动添加新后端并保存好,名称随意,链接填刚刚反代的地址,https://subapi.domain.com/UV3yVmNYreAhkVgP image-20231122193022455图片 参考文章: https://www.whitemoon.top/posts/e36e6bfe.html https://www.evan888.top/1974/
技术搬砖
# substore
# 订阅管理
admin
2年前
0
4,647
2