├── .gitignore ├── README.md ├── apps ├── alist │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── chatgpt-next-web │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── halo │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── happy-attack-plane │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── hedgedoc │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── homepage │ ├── config │ │ ├── bookmarks.yaml │ │ ├── docker.yaml │ │ ├── kubernetes.yaml │ │ ├── services.yaml │ │ ├── settings.yaml │ │ └── widgets.yaml │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── memos │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── mysql │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── nginx-proxy-manager │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── nginx │ ├── conf │ │ ├── conf.d │ │ │ └── default.conf │ │ ├── fastcgi_params │ │ ├── mime.types │ │ ├── nginx.conf │ │ ├── scgi_params │ │ └── uwsgi_params │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── palworld │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── plex │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── qbittorrent │ ├── config │ │ └── qBittorrent │ │ │ └── qBittorrent.conf │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── redis │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── safeline-ce │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh ├── veinmind │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ │ ├── init.sh │ │ ├── uninstall.sh │ │ └── upgrade.sh └── wordpress │ ├── docker-compose.yaml │ ├── favicon.png │ ├── manifest.yaml │ └── scripts │ ├── init.sh │ ├── uninstall.sh │ └── upgrade.sh ├── assets └── lifecycle.png └── homepage ├── .eslintrc.json ├── .gitignore ├── Makefile ├── next.config.js ├── package.json ├── pnpm-lock.yaml ├── public └── images │ ├── album │ ├── 0.png │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ └── 5.png │ ├── class.png │ ├── collie.png │ ├── feature.svg │ ├── github.png │ ├── logo.png │ ├── logo.svg │ ├── qrcode.png │ └── wechat-logo.png ├── script └── downLoadIcon.js ├── src ├── api │ └── hello.ts ├── components │ ├── Ellipsis │ │ └── index.tsx │ ├── Home │ │ ├── Features │ │ │ └── index.tsx │ │ ├── FriendlyLinks │ │ │ └── index.tsx │ │ ├── Title │ │ │ └── index.tsx │ │ └── Version │ │ │ ├── Card.tsx │ │ │ ├── Consultation.tsx │ │ │ ├── FunctionTable.tsx │ │ │ └── index.tsx │ ├── Icon │ │ └── index.tsx │ ├── MarkdownNavbar │ │ └── index.tsx │ ├── Message │ │ ├── Alert.tsx │ │ ├── Message.tsx │ │ └── index.tsx │ ├── Modal │ │ ├── ConfirmDialog.tsx │ │ ├── Modal.tsx │ │ ├── confrim.tsx │ │ └── index.tsx │ ├── ThemeProvider │ │ └── index.tsx │ └── index.tsx ├── layout │ ├── MainLayout │ │ ├── Header │ │ │ └── index.tsx │ │ └── index.tsx │ └── SideLayout │ │ └── index.tsx ├── pages │ ├── _app.tsx │ ├── _document.tsx │ ├── index.tsx │ └── posts │ │ └── [id].tsx ├── static │ ├── fonts │ │ ├── SF-Pro-Display-Bold.otf │ │ ├── SF-Pro-Display-Regular.otf │ │ ├── SF-Pro-Display-Semibold.otf │ │ └── iconfont.js │ └── md │ │ ├── about_ce.md │ │ ├── faq_other.md │ │ └── guide_introduction.md ├── styles │ ├── globals.css │ └── markdown.css ├── themes │ ├── color.ts │ ├── componentStyleOverrides.ts │ ├── index.ts │ ├── palette.ts │ ├── shadows.ts │ ├── themeContext.ts │ └── typography.ts └── utils │ ├── index.ts │ ├── posts.ts │ └── render.ts ├── tsconfig.json └── type.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | .render 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🐑 牧云主机安全平台 2 | 3 | 欢迎使用牧云主机安全平台!我们致力于帮助用户更轻松地管理他们的云主机。 4 | 5 | ## 🕹️ 使用牧云插件 6 | 7 | 我们提供了两种使用牧云插件的方式,分别是通过牧云主机管理助手和独立 CLI 工具使用。 8 | 9 | ### 🌐 通过牧云主机管理助手使用 10 | 11 | 你可以在 [官网](https://rivers.chaitin.cn/?share=34da0f89e4ff11ed94c80242c0a81705) 安装牧云主机管理助手,安装后即可使用其中的牧云插件。使用过程中遇到的问题欢迎来这里发 Issue. 12 | 13 | ### 💻 通过独立 CLI 工具使用 14 | 15 | #### 通过 cargo 安装 (🔥推荐) 16 | 17 | Arch Linux: 18 | 19 | ```shell 20 | # Install openssl-dev first 21 | sudo pacman -S pkg-config openssl 22 | cargo +nightly install collie-app-cli 23 | ``` 24 | 25 | Debian and Ubuntu: 26 | 27 | ```shell 28 | sudo apt install pkg-config libssl-dev 29 | cargo +nightly install collie-app-cli 30 | ``` 31 | 32 | CentOS: 33 | 34 | ```shell 35 | yum install pkg-config openssl-devel 36 | cargo +nightly install collie-app-cli 37 | ``` 38 | 39 | Fedora: 40 | 41 | ```shell 42 | sudo dnf install pkg-config openssl-devel 43 | cargo +nightly install collie-app-cli 44 | ``` 45 | 46 | Alpine Linux: 47 | 48 | ```shell 49 | apk add pkgconfig openssl-dev 50 | cargo +nightly install collie-app-cli 51 | ``` 52 | 53 | macOS (Homebrew): 54 | 55 | ```shell 56 | brew install openssl@3 57 | cargo +nightly install collie-app-cli 58 | ``` 59 | 60 | macOS (MacPorts): 61 | 62 | ```shell 63 | sudo port install openssl 64 | cargo +nightly install collie-app-cli 65 | ``` 66 | 67 | macOS (pkgsrc): 68 | 69 | ```shell 70 | sudo pkgin install openssl 71 | cargo +nightly install collie-app-cli 72 | ``` 73 | 74 | #### 手工安装 75 | 76 | 1. 从 [Release](https://github.com/chaitin/collie-app-cli/releases/latest) 下载 合你系统的 CLI 工具 77 | 2. 复制到你的 bin 目录 78 | 79 | ## 🔨 牧云插件快速开发指南 80 | 81 | > 首先你需要参考上一节安装 CLI 工具 82 | 83 | ### 创建模版应用 84 | 85 | ```shell 86 | collie-app-cli new 87 | ``` 88 | 89 | ### 修改你的应用 90 | 91 | ```shell 92 | cd 93 | # edit your template app 94 | ``` 95 | 96 | 详细参见: 97 | 98 | 1. [应用结构说明](#应用结构说明) 99 | 2. [manifest.yaml 说明](#manifest) 100 | 3. [应用生命周期说明](#应用生命周期说明) 101 | 102 | ### 查看渲染结果 103 | 104 | ```shell 105 | collie-app-cli up --dry 106 | ``` 107 | 108 | 渲染结果在 **.render** 109 | 110 | ### 实际测试 111 | 112 | 启动应用: 113 | 114 | ```shell 115 | collie-app-cli up 116 | ``` 117 | 118 | 停止应用: 119 | 120 | ```shell 121 | collie-app-cli down 122 | ``` 123 | 124 | ## 应用结构说明 125 | 126 | ```shell 127 | redis 128 | ├── config # 可选的自定义文件夹(嵌套文件夹,最大 10 层) 129 | │ └── redis.conf # 可选的自定义文件 130 | ├── docker-compose.yaml # 必要的 docker compose 描述文件 131 | ├── favicon.png # 必要的 应用图标 132 | ├── manifest.yaml # 必要的 应用核心 manifest 文件 133 | └── scripts # 必要的 脚本文件目录 134 | ├── init.sh # 必要的 安装后的自定义初始化脚本(无需可留空) 135 | ├── uninstall.sh # 必要的 卸载后的自定义卸载脚本(无需可留空) 136 | └── upgrade.sh # 必要的 升级后的自定义卸载脚本(无需可留空) 137 | ``` 138 | 139 | ## Manifest 140 | 141 | ```yaml 142 | metadata: 143 | name: redis # 插件名字 144 | desc: fast kv database. # 插件描述 145 | tags: # 插件标签 146 | - web 147 | version: 0.1.0 # 插件版本 148 | homepage: https://example.com # 插件主页 149 | author: # 作者信息 150 | name: your_name 151 | mail: your_name@example.com 152 | resource: # 该插件所需要的资源 153 | limit: # 最低资源限制 154 | cpu: 1 # 所需的 CPU 核心数量 155 | memory: 1024M # 所需的内存,支持后缀,如 M,G,Mib,MiB,GiB 等 156 | disk: 1G # 所需的磁盘,支持后缀,如 M,G,Mib,MiB,GiB 等 157 | recommend: 158 | cpu: 2 159 | memory: 2048M 160 | disk: 2G 161 | 162 | templates: # 需要渲染的模版列表,路径时相对于插件目录的 163 | - docker-compose.yaml 164 | - config/custom.conf 165 | 166 | ports: 167 | web: # 用于在模版中使用的名字 访问该变量的语法 {{ports.web.ip}}:{{ports.web.port}} 168 | ip: 0.0.0.0 # 端口绑定的 IP 169 | port: 80 # 端口绑定的 端口 170 | desc: web # 描述信息,会在牧云主机助手创建应用时显示 171 | 172 | variables: 173 | password: # 用于在模版中使用的名字 访问该变量的语法 {{variables.password.value}} 174 | name: 服务密码 # 描述性的名字,如 XX 密码 175 | desc: 用于访问服务时用的密码,请注意复杂度 # 提示性的描述信息,如 请注意密码复杂度 176 | value: wPMihYE # 默认的值,可以在创建应用时通过 UI 覆盖 177 | ``` 178 | 179 | ## 应用生命周期说明 180 | 181 | ![生命周期](assets/lifecycle.png) 182 | -------------------------------------------------------------------------------- /apps/alist/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.0" 2 | services: 3 | alist: 4 | image: xhofe/alist:v3.29.1 5 | container_name: alist 6 | restart: always 7 | volumes: 8 | - ./data/:/opt/alist/data 9 | - '{{variables.host_v.value}}:{{variables.container_v.value}}' 10 | ports: 11 | - '{{ports.admin.ip}}:{{ports.admin.port}}:5244' 12 | environment: 13 | - PUID=0 14 | - PGID=0 15 | - UMASK=022 16 | -------------------------------------------------------------------------------- /apps/alist/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/alist/favicon.png -------------------------------------------------------------------------------- /apps/alist/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdm1kfnop80nda14hqg@COLI 3 | name: alist 4 | desc: 一个支持多种存储的文件列表程序,使用 Gin 和 Solidjs。 5 | tags: 6 | - WebDAV 7 | - 阿里云盘 8 | - 文件预览 9 | version: 3.29.1 10 | display_version: 3.29.1 11 | homepage: https://github.com/alist-org/alist 12 | author: 13 | name: Honsun 14 | mail: honsun@linux.com 15 | resource: 16 | limit: 17 | cpu: 1 18 | memory: 1024M 19 | disk: 1G 20 | recommand: 21 | cpu: 2 22 | memory: 2048M 23 | disk: 2G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: 29 | admin: 30 | ip: 0.0.0.0 31 | port: 5244 32 | desc: alist 访问地址 33 | 34 | variables: 35 | host_v: 36 | name: 宿主机目录 37 | desc: 一般是存放资源的目录,比如/data/media 38 | value: /data/media 39 | container_v: 40 | name: 容器目录 41 | desc: 容器内对应的资源目录,比如/mnt/data/media 42 | value: /mnt/data/media 43 | 44 | -------------------------------------------------------------------------------- /apps/alist/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/alist/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/alist/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/chatgpt-next-web/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | services: 3 | chatgpt-next-web: 4 | image: yidadaa/chatgpt-next-web:v2.9.12 5 | restart: always 6 | ports: 7 | - '{{ports.web.ip}}:{{ports.web.port}}:3000' 8 | environment: 9 | CODE: '{{variables.password.value}}' 10 | OPENAI_API_KEY: '{{variables.api_key.value}}' 11 | -------------------------------------------------------------------------------- /apps/chatgpt-next-web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/chatgpt-next-web/favicon.png -------------------------------------------------------------------------------- /apps/chatgpt-next-web/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: ci3hc3850qttfmcj1io0@COLI 3 | name: ChatGPT-Next-Web 4 | desc: 一键拥有你自己的 ChatGPT 网页服务。 5 | tags: 6 | - ChatGPT 7 | - WebUI 8 | version: 2.9.12 9 | display_version: v2.9.12 10 | homepage: https://github.com/Yidadaa/ChatGPT-Next-Web 11 | author: 12 | name: Honsun 13 | mail: honsun@linux.com 14 | resource: 15 | limit: 16 | cpu: 1 17 | memory: 1024M 18 | disk: 1G 19 | recommand: 20 | cpu: 2 21 | memory: 2048M 22 | disk: 2G 23 | 24 | templates: 25 | - docker-compose.yaml 26 | 27 | ports: 28 | web: 29 | ip: 0.0.0.0 30 | port: 3000 31 | desc: ChatGPT Web 访问端口 32 | 33 | variables: 34 | password: 35 | name: 访问密码 36 | desc: 网站访问密码,注意复杂度 37 | value: your-chatgpt-secret 38 | api_key: 39 | name: api_key 40 | desc: ChatGPT api_key,访问 OpenAI 官网获取 41 | value: sk-********************xyz 42 | -------------------------------------------------------------------------------- /apps/chatgpt-next-web/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/chatgpt-next-web/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/chatgpt-next-web/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/halo/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | halo: 5 | image: halohub/halo:2.10 6 | container_name: halo 7 | restart: on-failure:3 8 | depends_on: 9 | halodb: 10 | condition: service_healthy 11 | networks: 12 | halo_network: 13 | volumes: 14 | - ./halo2:/root/.halo2 15 | ports: 16 | - "{{ports.admin.ip}}:{{ports.admin.port}}:8090" 17 | healthcheck: 18 | test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"] 19 | interval: 30s 20 | timeout: 5s 21 | retries: 5 22 | start_period: 30s 23 | command: 24 | - --spring.r2dbc.url=r2dbc:pool:postgresql://halodb/halo 25 | - --spring.r2dbc.username=halo 26 | # PostgreSQL 的密码,请保证与下方 POSTGRES_PASSWORD 的变量值一致。 27 | - --spring.r2dbc.password=${POSTGRES_PASSWORD} 28 | - --spring.sql.init.platform=postgresql 29 | # 外部访问地址,请根据实际需要修改 30 | - --halo.external-url={{variables.url.value}} 31 | halodb: 32 | image: postgres:15.4 33 | container_name: halodb 34 | restart: on-failure:3 35 | networks: 36 | halo_network: 37 | volumes: 38 | - ./db:/var/lib/postgresql/data 39 | ports: 40 | - "5432:5432" 41 | healthcheck: 42 | test: [ "CMD", "pg_isready" ] 43 | interval: 10s 44 | timeout: 5s 45 | retries: 5 46 | environment: 47 | - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} 48 | - POSTGRES_USER=halo 49 | - POSTGRES_DB=halo 50 | - PGUSER=halo 51 | 52 | networks: 53 | halo_network: 54 | -------------------------------------------------------------------------------- /apps/halo/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/halo/favicon.png -------------------------------------------------------------------------------- /apps/halo/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdm2evn0p80h8e6oq8h@COLI 3 | name: Halo 4 | desc: 强大易用的开源建站工具 5 | tags: 6 | - 建站 7 | version: 2.10.0 8 | display_version: 2.10.0 9 | homepage: https://docs.halo.run/ 10 | author: 11 | name: chaitin 12 | mail: chaitin@chaitin.com 13 | resource: 14 | limit: 15 | cpu: 2 16 | memory: 4G 17 | disk: 10G 18 | recommand: 19 | cpu: 4 20 | memory: 8G 21 | disk: 20G 22 | 23 | templates: 24 | - docker-compose.yaml 25 | 26 | ports: 27 | admin: 28 | ip: 0.0.0.0 29 | port: 8090 30 | desc: 访问端口 31 | 32 | variables: 33 | url: 34 | name: 外部访问URL 35 | desc: 外部访问URL(跟控制台端口保持一致) 36 | value: http://localhost:8090/ 37 | 38 | 39 | -------------------------------------------------------------------------------- /apps/halo/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | 6 | echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 > .env 7 | -------------------------------------------------------------------------------- /apps/halo/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/halo/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/happy-attack-plane/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | happy-attack-plane: 4 | image: co0ontty/happy-attack-plane:latest 5 | restart: always 6 | ports: 7 | - '{{ports.happy.ip}}:{{ports.happy.port}}:80' 8 | -------------------------------------------------------------------------------- /apps/happy-attack-plane/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/happy-attack-plane/favicon.png -------------------------------------------------------------------------------- /apps/happy-attack-plane/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chrj5uhjr9266i6telrg@COLI 3 | name: 打飞机小游戏 4 | desc: 打飞机小游戏 5 | tags: 6 | - 游戏 7 | version: 1.0.0 8 | display_version: 1.0.0 9 | homepage: https://github.com/wwwcomy/typingclub.git 10 | author: 11 | name: co0ontty 12 | mail: co0ontty@gmail.com 13 | resource: 14 | limit: 15 | cpu: 2 16 | memory: 4G 17 | disk: 10G 18 | recommand: 19 | cpu: 4 20 | memory: 8G 21 | disk: 20G 22 | 23 | templates: 24 | - docker-compose.yaml 25 | 26 | ports: 27 | happy: 28 | ip: 0.0.0.0 29 | port: 5261 30 | desc: 控制台 31 | 32 | variables: {} 33 | -------------------------------------------------------------------------------- /apps/happy-attack-plane/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/happy-attack-plane/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/happy-attack-plane/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/hedgedoc/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | db: 4 | image: mysql:8.0 5 | restart: always 6 | environment: 7 | - 'MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}' 8 | - MYSQL_DATABASE=hedgedoc 9 | command: --default-authentication-plugin=mysql_native_password 10 | volumes: 11 | - ./dbdata:/var/lib/mysql:/data 12 | 13 | hedgedoc: 14 | image: lscr.io/linuxserver/hedgedoc:latest 15 | environment: 16 | - PUID=1000 17 | - PGID=1000 18 | - TZ=Etc/UTC 19 | - DB_HOST=db 20 | - DB_PORT=3306 21 | - DB_USER=root 22 | - 'DB_PASS=${MYSQL_PASSWORD}' 23 | - DB_NAME=hedgedoc 24 | - CMD_CSP_ENABLE=false 25 | volumes: 26 | - ./appdata:/config 27 | ports: 28 | - '{{ports.addr.ip}}:{{ports.addr.port}}:3000' 29 | restart: always 30 | links: 31 | - "db" 32 | -------------------------------------------------------------------------------- /apps/hedgedoc/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/hedgedoc/favicon.png -------------------------------------------------------------------------------- /apps/hedgedoc/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: che98rfn0p82d77cf8ng@COLI 3 | name: HedgeDoc 4 | desc: 在线 markdown 文档系统,基于 hackmd 开发 5 | tags: 6 | - markdown 7 | - 文档 8 | version: 1.9.7 9 | display_version: 1.9.7 10 | homepage: https://hedgedoc.org/ 11 | author: 12 | name: chaitin 13 | mail: chaitin@chaitin.com 14 | resource: 15 | limit: 16 | cpu: 1 17 | memory: 512M 18 | disk: 1G 19 | recommand: 20 | cpu: 2 21 | memory: 2048M 22 | disk: 2G 23 | 24 | templates: 25 | - docker-compose.yaml 26 | 27 | ports: 28 | addr: 29 | ip: 0.0.0.0 30 | port: 3000 31 | desc: Web 管理地址 32 | 33 | variables: {} 34 | -------------------------------------------------------------------------------- /apps/hedgedoc/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "MYSQL_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 > .env 4 | -------------------------------------------------------------------------------- /apps/hedgedoc/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/hedgedoc/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/homepage/config/bookmarks.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # For configuration options and examples, please see: 3 | # https://gethomepage.dev/en/configs/bookmarks 4 | 5 | - Developer: 6 | - Github: 7 | - abbr: GH 8 | href: https://github.com/ 9 | 10 | - Social: 11 | - 微博: 12 | - abbr: WB 13 | href: https://weibo.com/ 14 | 15 | - Entertainment: 16 | - BiliBili: 17 | - abbr: BL 18 | href: https://bilibili.com/ 19 | -------------------------------------------------------------------------------- /apps/homepage/config/docker.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # For configuration options and examples, please see: 3 | # https://gethomepage.dev/en/configs/docker/ 4 | 5 | Docker: 6 | socket: /var/run/docker.sock 7 | -------------------------------------------------------------------------------- /apps/homepage/config/kubernetes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # sample kubernetes config 3 | -------------------------------------------------------------------------------- /apps/homepage/config/services.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # For configuration options and examples, please see: 3 | # https://gethomepage.dev/en/configs/services 4 | -------------------------------------------------------------------------------- /apps/homepage/config/settings.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # For configuration options and examples, please see: 3 | # https://gethomepage.dev/en/configs/settings 4 | 5 | language: zh-CN 6 | providers: 7 | openweathermap: openweathermapapikey 8 | weatherapi: weatherapiapikey 9 | -------------------------------------------------------------------------------- /apps/homepage/config/widgets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # For configuration options and examples, please see: 3 | # https://gethomepage.dev/en/configs/widgets 4 | 5 | - resources: 6 | cpu: true 7 | memory: true 8 | disk: / 9 | 10 | - search: 11 | provider: baidu 12 | target: _blank 13 | -------------------------------------------------------------------------------- /apps/homepage/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.3" 2 | services: 3 | homepage: 4 | image: ghcr.io/benphelps/homepage:latest 5 | container_name: homepage 6 | ports: 7 | - '{{ports.port.ip}}:{{ports.port.port}}:3000' 8 | volumes: 9 | - ./config:/app/config 10 | - /var/run/docker.sock:/var/run/docker.sock:ro # For docker integrations -------------------------------------------------------------------------------- /apps/homepage/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/homepage/favicon.png -------------------------------------------------------------------------------- /apps/homepage/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdpu47n0p81d0hl2i00@COLI 3 | name: Homepage 4 | desc: 一个高度可定制的主页,应用程序仪表板。 5 | tags: 6 | - 主页 7 | - 仪表盘 8 | - 监控 9 | version: 0.1.0 10 | display_version: 0.1.0 11 | homepage: https://github.com/benphelps/homepage 12 | author: 13 | name: Honsun 14 | mail: honsun@linux.com 15 | resource: 16 | limit: 17 | cpu: 1 18 | memory: 1024M 19 | disk: 1G 20 | recommand: 21 | cpu: 2 22 | memory: 2048M 23 | disk: 2G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: 29 | port: 30 | ip: 0.0.0.0 31 | port: 3000 32 | desc: 监听端口 33 | 34 | variables: {} 35 | -------------------------------------------------------------------------------- /apps/homepage/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/homepage/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/homepage/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/memos/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.0" 2 | services: 3 | memos: 4 | image: ghcr.io/usememos/memos:0.17.1 5 | container_name: memos 6 | volumes: 7 | - ./.memos/:/var/opt/memos 8 | ports: 9 | - '{{ports.admin.ip}}:{{ports.admin.port}}:5230' 10 | -------------------------------------------------------------------------------- /apps/memos/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/memos/favicon.png -------------------------------------------------------------------------------- /apps/memos/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdm1kfn0p80nda14hqg@COLI 3 | name: Memos 4 | desc: Memos is a privacy-first, lightweight note-taking service. Easily capture and share your great thoughts. 5 | tags: 6 | - 日记 7 | - 轻量 8 | - 微博 9 | version: 0.17.1 10 | display_version: 0.17.1 11 | homepage: https://www.usememos.com/ 12 | author: 13 | name: Honsun 14 | mail: honsun@linux.com 15 | resource: 16 | limit: 17 | cpu: 1 18 | memory: 1024M 19 | disk: 1G 20 | recommand: 21 | cpu: 2 22 | memory: 2048M 23 | disk: 2G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: 29 | admin: 30 | ip: 0.0.0.0 31 | port: 5230 32 | desc: memos 访问地址 33 | 34 | variables: 35 | -------------------------------------------------------------------------------- /apps/memos/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/memos/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/memos/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/mysql/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | networks: 3 | mysql: 4 | name: mysql 5 | driver: bridge 6 | 7 | services: 8 | mysql: 9 | image: mysql:8.0 10 | restart: always 11 | ports: 12 | - '{{ports.mysql.ip}}:{{ports.mysql.port}}:3306' 13 | environment: 14 | - 'MYSQL_ROOT_PASSWORD={{variables.password.value}}' 15 | command: --default-authentication-plugin=mysql_native_password 16 | volumes: 17 | - ./datadir:/var/lib/mysql:/data 18 | 19 | phpmyadmin: 20 | image: phpmyadmin:5.2 21 | restart: always 22 | ports: 23 | - '{{ports.phpmyadmin.ip}}:{{ports.phpmyadmin.port}}:80' 24 | environment: 25 | - 'PMA_HOST=mysql' 26 | links: 27 | - "mysql" 28 | -------------------------------------------------------------------------------- /apps/mysql/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/mysql/favicon.png -------------------------------------------------------------------------------- /apps/mysql/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdm1kfn0p80ndal4hq0@COLI 3 | name: MySQL 4 | desc: MySQL 数据库,附带 phpmyadmin 管理工具 5 | tags: 6 | - 数据库 7 | - MySQL 8 | version: 0.8.0 9 | display_verson: 8.0 10 | homepage: https://www.mysql.com/ 11 | author: 12 | name: chaitin 13 | mail: chaitin@chaitin.com 14 | resource: 15 | limit: 16 | cpu: 1 17 | memory: 512M 18 | disk: 2G 19 | recommand: 20 | cpu: 2 21 | memory: 2G 22 | disk: 10G 23 | 24 | templates: 25 | - docker-compose.yaml 26 | 27 | ports: 28 | mysql: 29 | ip: 127.0.0.1 30 | port: 3306 31 | desc: MySQL 数据库端口 32 | phpmyadmin: 33 | ip: 0.0.0.0 34 | port: 3080 35 | desc: phpmyadmin 控制台端口 36 | 37 | variables: 38 | password: 39 | name: root 账户的初始化密码 40 | desc: root 账户的初始化密码, 请注意密码的复杂度 41 | value: password 42 | -------------------------------------------------------------------------------- /apps/mysql/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/mysql/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/mysql/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/nginx-proxy-manager/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | app: 4 | image: 'jc21/nginx-proxy-manager:2.10.4' 5 | restart: unless-stopped 6 | ports: 7 | # These ports are in format : 8 | - '80:80' # Public HTTP Port 9 | - '443:443' # Public HTTPS Port 10 | - '{{ports.admin.ip}}:{{ports.admin.port}}:81' # Admin Web Port 11 | # Add any other Stream port you want to expose 12 | # - '21:21' # FTP 13 | 14 | # Uncomment the next line if you uncomment anything in the section 15 | # environment: 16 | # Uncomment this if you want to change the location of 17 | # the SQLite DB file within the container 18 | # DB_SQLITE_FILE: "/data/database.sqlite" 19 | 20 | # Uncomment this if IPv6 is not enabled on your host 21 | # DISABLE_IPV6: 'true' 22 | 23 | volumes: 24 | - ./data:/data 25 | - ./letsencrypt:/etc/letsencrypt 26 | -------------------------------------------------------------------------------- /apps/nginx-proxy-manager/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/nginx-proxy-manager/favicon.png -------------------------------------------------------------------------------- /apps/nginx-proxy-manager/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdpt7vn0p80oel5s571@COLI 3 | name: Nginx Proxy Manager 4 | desc: Expose your services easily and securely 5 | tags: 6 | - Proxy 7 | - Web 8 | - SSL 9 | version: 2.10.4 10 | display_version: 2.10.4 11 | homepage: https://nginxproxymanager.com 12 | author: 13 | name: chaitin 14 | mail: chaitin@chaitin.com 15 | resource: 16 | limit: 17 | cpu: 1 18 | memory: 256M 19 | disk: 1G 20 | recommand: 21 | cpu: 1 22 | memory: 1G 23 | disk: 1G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: 29 | admin: 30 | ip: 0.0.0.0 31 | port: 81 32 | desc: 管理端访问地址 33 | 34 | variables: 35 | password: 36 | name: 默认用户名和密码(登录后修改) 37 | desc: 管理端初始用户名和密码 38 | value: admin@example.com / changeme 39 | -------------------------------------------------------------------------------- /apps/nginx-proxy-manager/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/nginx-proxy-manager/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/nginx-proxy-manager/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/nginx/conf/conf.d/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | listen [::]:80; 4 | server_name localhost; 5 | 6 | #access_log /var/log/nginx/host.access.log main; 7 | 8 | location / { 9 | root /usr/share/nginx/html; 10 | index index.html index.htm; 11 | } 12 | 13 | #error_page 404 /404.html; 14 | 15 | # redirect server error pages to the static page /50x.html 16 | # 17 | error_page 500 502 503 504 /50x.html; 18 | location = /50x.html { 19 | root /usr/share/nginx/html; 20 | } 21 | 22 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80 23 | # 24 | #location ~ \.php$ { 25 | # proxy_pass http://127.0.0.1; 26 | #} 27 | 28 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 29 | # 30 | #location ~ \.php$ { 31 | # root html; 32 | # fastcgi_pass 127.0.0.1:9000; 33 | # fastcgi_index index.php; 34 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; 35 | # include fastcgi_params; 36 | #} 37 | 38 | # deny access to .htaccess files, if Apache's document root 39 | # concurs with nginx's one 40 | # 41 | #location ~ /\.ht { 42 | # deny all; 43 | #} 44 | } 45 | 46 | -------------------------------------------------------------------------------- /apps/nginx/conf/fastcgi_params: -------------------------------------------------------------------------------- 1 | 2 | fastcgi_param QUERY_STRING $query_string; 3 | fastcgi_param REQUEST_METHOD $request_method; 4 | fastcgi_param CONTENT_TYPE $content_type; 5 | fastcgi_param CONTENT_LENGTH $content_length; 6 | 7 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 8 | fastcgi_param REQUEST_URI $request_uri; 9 | fastcgi_param DOCUMENT_URI $document_uri; 10 | fastcgi_param DOCUMENT_ROOT $document_root; 11 | fastcgi_param SERVER_PROTOCOL $server_protocol; 12 | fastcgi_param REQUEST_SCHEME $scheme; 13 | fastcgi_param HTTPS $https if_not_empty; 14 | 15 | fastcgi_param GATEWAY_INTERFACE CGI/1.1; 16 | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 17 | 18 | fastcgi_param REMOTE_ADDR $remote_addr; 19 | fastcgi_param REMOTE_PORT $remote_port; 20 | fastcgi_param SERVER_ADDR $server_addr; 21 | fastcgi_param SERVER_PORT $server_port; 22 | fastcgi_param SERVER_NAME $server_name; 23 | 24 | # PHP only, required if PHP was built with --enable-force-cgi-redirect 25 | fastcgi_param REDIRECT_STATUS 200; 26 | -------------------------------------------------------------------------------- /apps/nginx/conf/mime.types: -------------------------------------------------------------------------------- 1 | 2 | types { 3 | text/html html htm shtml; 4 | text/css css; 5 | text/xml xml; 6 | image/gif gif; 7 | image/jpeg jpeg jpg; 8 | application/javascript js; 9 | application/atom+xml atom; 10 | application/rss+xml rss; 11 | 12 | text/mathml mml; 13 | text/plain txt; 14 | text/vnd.sun.j2me.app-descriptor jad; 15 | text/vnd.wap.wml wml; 16 | text/x-component htc; 17 | 18 | image/avif avif; 19 | image/png png; 20 | image/svg+xml svg svgz; 21 | image/tiff tif tiff; 22 | image/vnd.wap.wbmp wbmp; 23 | image/webp webp; 24 | image/x-icon ico; 25 | image/x-jng jng; 26 | image/x-ms-bmp bmp; 27 | 28 | font/woff woff; 29 | font/woff2 woff2; 30 | 31 | application/java-archive jar war ear; 32 | application/json json; 33 | application/mac-binhex40 hqx; 34 | application/msword doc; 35 | application/pdf pdf; 36 | application/postscript ps eps ai; 37 | application/rtf rtf; 38 | application/vnd.apple.mpegurl m3u8; 39 | application/vnd.google-earth.kml+xml kml; 40 | application/vnd.google-earth.kmz kmz; 41 | application/vnd.ms-excel xls; 42 | application/vnd.ms-fontobject eot; 43 | application/vnd.ms-powerpoint ppt; 44 | application/vnd.oasis.opendocument.graphics odg; 45 | application/vnd.oasis.opendocument.presentation odp; 46 | application/vnd.oasis.opendocument.spreadsheet ods; 47 | application/vnd.oasis.opendocument.text odt; 48 | application/vnd.openxmlformats-officedocument.presentationml.presentation 49 | pptx; 50 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 51 | xlsx; 52 | application/vnd.openxmlformats-officedocument.wordprocessingml.document 53 | docx; 54 | application/vnd.wap.wmlc wmlc; 55 | application/wasm wasm; 56 | application/x-7z-compressed 7z; 57 | application/x-cocoa cco; 58 | application/x-java-archive-diff jardiff; 59 | application/x-java-jnlp-file jnlp; 60 | application/x-makeself run; 61 | application/x-perl pl pm; 62 | application/x-pilot prc pdb; 63 | application/x-rar-compressed rar; 64 | application/x-redhat-package-manager rpm; 65 | application/x-sea sea; 66 | application/x-shockwave-flash swf; 67 | application/x-stuffit sit; 68 | application/x-tcl tcl tk; 69 | application/x-x509-ca-cert der pem crt; 70 | application/x-xpinstall xpi; 71 | application/xhtml+xml xhtml; 72 | application/xspf+xml xspf; 73 | application/zip zip; 74 | 75 | application/octet-stream bin exe dll; 76 | application/octet-stream deb; 77 | application/octet-stream dmg; 78 | application/octet-stream iso img; 79 | application/octet-stream msi msp msm; 80 | 81 | audio/midi mid midi kar; 82 | audio/mpeg mp3; 83 | audio/ogg ogg; 84 | audio/x-m4a m4a; 85 | audio/x-realaudio ra; 86 | 87 | video/3gpp 3gpp 3gp; 88 | video/mp2t ts; 89 | video/mp4 mp4; 90 | video/mpeg mpeg mpg; 91 | video/quicktime mov; 92 | video/webm webm; 93 | video/x-flv flv; 94 | video/x-m4v m4v; 95 | video/x-mng mng; 96 | video/x-ms-asf asx asf; 97 | video/x-ms-wmv wmv; 98 | video/x-msvideo avi; 99 | } 100 | -------------------------------------------------------------------------------- /apps/nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | user nginx; 3 | worker_processes auto; 4 | 5 | error_log /var/log/nginx/error.log notice; 6 | pid /var/run/nginx.pid; 7 | 8 | 9 | events { 10 | worker_connections 1024; 11 | } 12 | 13 | 14 | http { 15 | include /etc/nginx/mime.types; 16 | default_type application/octet-stream; 17 | 18 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 19 | '$status $body_bytes_sent "$http_referer" ' 20 | '"$http_user_agent" "$http_x_forwarded_for"'; 21 | 22 | access_log /var/log/nginx/access.log main; 23 | 24 | sendfile on; 25 | #tcp_nopush on; 26 | 27 | keepalive_timeout 65; 28 | 29 | #gzip on; 30 | 31 | include /etc/nginx/conf.d/*.conf; 32 | } 33 | -------------------------------------------------------------------------------- /apps/nginx/conf/scgi_params: -------------------------------------------------------------------------------- 1 | 2 | scgi_param REQUEST_METHOD $request_method; 3 | scgi_param REQUEST_URI $request_uri; 4 | scgi_param QUERY_STRING $query_string; 5 | scgi_param CONTENT_TYPE $content_type; 6 | 7 | scgi_param DOCUMENT_URI $document_uri; 8 | scgi_param DOCUMENT_ROOT $document_root; 9 | scgi_param SCGI 1; 10 | scgi_param SERVER_PROTOCOL $server_protocol; 11 | scgi_param REQUEST_SCHEME $scheme; 12 | scgi_param HTTPS $https if_not_empty; 13 | 14 | scgi_param REMOTE_ADDR $remote_addr; 15 | scgi_param REMOTE_PORT $remote_port; 16 | scgi_param SERVER_PORT $server_port; 17 | scgi_param SERVER_NAME $server_name; 18 | -------------------------------------------------------------------------------- /apps/nginx/conf/uwsgi_params: -------------------------------------------------------------------------------- 1 | 2 | uwsgi_param QUERY_STRING $query_string; 3 | uwsgi_param REQUEST_METHOD $request_method; 4 | uwsgi_param CONTENT_TYPE $content_type; 5 | uwsgi_param CONTENT_LENGTH $content_length; 6 | 7 | uwsgi_param REQUEST_URI $request_uri; 8 | uwsgi_param PATH_INFO $document_uri; 9 | uwsgi_param DOCUMENT_ROOT $document_root; 10 | uwsgi_param SERVER_PROTOCOL $server_protocol; 11 | uwsgi_param REQUEST_SCHEME $scheme; 12 | uwsgi_param HTTPS $https if_not_empty; 13 | 14 | uwsgi_param REMOTE_ADDR $remote_addr; 15 | uwsgi_param REMOTE_PORT $remote_port; 16 | uwsgi_param SERVER_PORT $server_port; 17 | uwsgi_param SERVER_NAME $server_name; 18 | -------------------------------------------------------------------------------- /apps/nginx/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | nginx: 4 | image: nginx:1.24 5 | restart: always 6 | volumes: 7 | - ./conf:/etc/nginx/ 8 | - ./logs:/var/log/nginx 9 | network_mode: host 10 | -------------------------------------------------------------------------------- /apps/nginx/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/nginx/favicon.png -------------------------------------------------------------------------------- /apps/nginx/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdpt7vn0p80oel5s570@COLI 3 | name: Nginx 4 | desc: 高性能的 HTTP 服务,反向代理服务 5 | tags: 6 | - HTTP 7 | - Web 8 | - 中间件 9 | version: 0.1.24 10 | display_version: 1.24 11 | homepage: https://nginx.org/ 12 | author: 13 | name: chaitin 14 | mail: chaitin@chaitin.com 15 | resource: 16 | limit: 17 | cpu: 1 18 | memory: 256M 19 | disk: 1G 20 | recommand: 21 | cpu: 1 22 | memory: 1G 23 | disk: 10G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: {} 29 | 30 | variables: {} 31 | -------------------------------------------------------------------------------- /apps/nginx/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/nginx/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/nginx/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/palworld/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | palworld: 4 | image: thijsvanloef/palworld-server-docker:v0.19.0 5 | restart: unless-stopped 6 | ports: 7 | - '{{ports.palworld.ip}}:{{ports.palworld.port}}:8211/udp' 8 | - 27015:27015/udp 9 | environment: 10 | - PUID=1000 11 | - PGID=1000 12 | - PORT={{ports.palworld.port}} # Optional but recommended 13 | - PLAYERS={{variables.players.value}} # Optional but recommended 14 | - 'SERVER_PASSWORD={{variables.server_password.value}}' 15 | - MULTITHREADING=true 16 | - RCON_ENABLED=true 17 | - RCON_PORT=25575 18 | - TZ=Asia/Shanghai 19 | - 'ADMIN_PASSWORD={{variables.admin_password.value}}' 20 | - COMMUNITY=false # Enable this if you want your server to show up in the community servers tab, USE WITH SERVER_PASSWORD! 21 | - 'SERVER_NAME={{variables.server_name.value}}' 22 | volumes: 23 | - ./palworld:/palworld/ 24 | -------------------------------------------------------------------------------- /apps/palworld/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/palworld/favicon.png -------------------------------------------------------------------------------- /apps/palworld/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdm1knnoo80ndal4hqg@COLI 3 | name: Palworld 4 | desc: 创建自己的幻兽帕鲁服务器 5 | tags: 6 | - 幻兽帕鲁 7 | - Palworld 8 | - 自建服务 9 | version: 0.3.0 10 | display_version: 0.3.0 11 | homepage: https://store.steampowered.com/app/1623730/Palworld/ 12 | author: 13 | name: Honsun 14 | mail: honsun@linux.com 15 | resource: 16 | limit: 17 | cpu: 4 18 | memory: 16G 19 | disk: 1G 20 | recommand: 21 | cpu: 8 22 | memory: 32G 23 | disk: 2G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: 29 | palworld: 30 | ip: 0.0.0.0 31 | port: 8211 32 | desc: 服务器连接地址 33 | 34 | variables: 35 | server_name: 36 | name: 服务器名称 37 | desc: 服务器的名字 38 | value: palworld 39 | server_password: 40 | name: 连接密码 41 | desc: 服务器的连接密码(修改!!!) 42 | value: WorldOfPals 43 | players: 44 | name: 玩家人数 45 | desc: 服务器承载的玩家人数 46 | value: 16 47 | admin_password: 48 | name: 管理员密码 49 | desc: 管理员管理密码(修改!!!) 50 | value: AdminPasswordHere 51 | -------------------------------------------------------------------------------- /apps/palworld/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/palworld/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/palworld/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/plex/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | plex: 4 | image: linuxserver/plex:latest 5 | container_name: plex 6 | network_mode: host 7 | environment: 8 | - PUID={{variables.uid.value}} 9 | - PGID={{variables.gid.value}} 10 | - TZ=Etc/UTC 11 | - VERSION=docker 12 | volumes: 13 | - ./config:/config 14 | - '{{variables.data.value}}:/data' 15 | restart: unless-stopped 16 | 17 | -------------------------------------------------------------------------------- /apps/plex/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/plex/favicon.png -------------------------------------------------------------------------------- /apps/plex/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chh0agvn0p82ol0bbbi0@COLI 3 | name: Plex 4 | desc: 广泛使用的,界面优美,电影墙易用的媒体管理系统 5 | tags: 6 | - 多媒体 7 | - homelab 8 | - NAS 9 | version: 0.1.1 10 | display_version: 1.32.3.7192 11 | homepage: https://plex.tv/ 12 | author: 13 | name: Honsun 14 | mail: honsun@linux.com 15 | resource: 16 | limit: 17 | cpu: 1 18 | memory: 1024M 19 | disk: 1G 20 | recommand: 21 | cpu: 2 22 | memory: 2048M 23 | disk: 2G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: {} 29 | variables: 30 | uid: 31 | name: Plex 以何种身份读取媒体文件 32 | desc: 通常设置为目标文件的所有者,如果目标文件任何人都可读保持默认值即可 33 | value: 1000 34 | gid: 35 | name: Plex 以何种身份组读取媒体文件 36 | desc: 通常设置为目标文件的所有者虽在的组,如果目标文件任何人都可读保持默认值即可 37 | value: 1000 38 | data: 39 | name: Plex 媒体文件库 40 | desc: Plex 媒体文件库,推荐其下子目录可以有 tvs, movies 等 41 | value: /downloads 42 | -------------------------------------------------------------------------------- /apps/plex/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/plex/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/plex/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/qbittorrent/config/qBittorrent/qBittorrent.conf: -------------------------------------------------------------------------------- 1 | [Preferences] 2 | General\Locale=zh_CN 3 | WebUI\Address=* 4 | WebUI\Password_PBKDF2="@ByteArray(X8wALTyCPb7/Xm/TGq4nUA==:BfBd2vZzjJNT9mRewk5KhbpDimr3sdoVakRF/gsYT2gvKWTm+izkrvoc+D/g5l1hYoMOrCWI8xxzxpGXFhNwnQ==)" 5 | WebUI\Port=8080 6 | WebUI\Username=admin 7 | -------------------------------------------------------------------------------- /apps/qbittorrent/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | qbittorrent: 4 | image: linuxserver/qbittorrent:4.5.2 5 | container_name: qbittorrent 6 | environment: 7 | - PUID={{variables.uid.value}} 8 | - PGID={{variables.gid.value}} 9 | - TZ=Etc/UTC 10 | - WEBUI_PORT=8080 11 | volumes: 12 | - './config:/config' 13 | - '{{variables.downloads.value}}:/downloads' 14 | ports: 15 | - '{{ports.webui.ip}}:{{ports.webui.port}}:8080' 16 | - '{{ports.bt.ip}}:{{ports.bt.port}}:6881' 17 | - '{{ports.bt.ip}}:{{ports.bt.port}}:6881/udp' 18 | restart: unless-stopped -------------------------------------------------------------------------------- /apps/qbittorrent/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/qbittorrent/favicon.png -------------------------------------------------------------------------------- /apps/qbittorrent/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chee08fn0p8b3unlkdug@COLI 3 | name: qBittorrent 4 | desc: 一个跨平台的开源、自由的BitTorrent客户端 5 | tags: 6 | - bittorrent 7 | - 下载 8 | - 种子 9 | version: 4.5.2 10 | display_version: 4.5.2 11 | homepage: https://github.com/qbittorrent/qBittorrent 12 | author: 13 | name: Honsun 14 | mail: honsun@linux.com 15 | resource: 16 | limit: 17 | cpu: 1 18 | memory: 1024M 19 | disk: 1G 20 | recommand: 21 | cpu: 2 22 | memory: 2048M 23 | disk: 2G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: 29 | webui: 30 | ip: 0.0.0.0 31 | port: 8080 32 | desc: qBittorrent WebUI 监听地址,管理默认用户名/密码:admin/adminadmin 33 | bt: 34 | ip: 0.0.0.0 35 | port: 6881 36 | desc: qBittorrent BT 协议通信地址 37 | 38 | variables: 39 | uid: 40 | name: qBittorrent 下载的文件的 UID 41 | desc: qBittorrent 下载的文件的 UID,通常为使用此文件用户的 UID 42 | value: 1000 43 | gid: 44 | name: qBittorrent 下载的文件的 GID 45 | desc: qBittorrent 下载的文件的 GID,通常为使用此文件用户的 GID 46 | value: 1000 47 | downloads: 48 | name: qBittorrent 下载的目标目录 49 | desc: qBittorrent 下载的目标目录 50 | value: /downloads 51 | -------------------------------------------------------------------------------- /apps/qbittorrent/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/qbittorrent/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/qbittorrent/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/redis/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | redis: 4 | image: redis:6.2-alpine 5 | restart: always 6 | ports: 7 | - '{{ports.redis.ip}}:{{ports.redis.port}}:6379' 8 | command: redis-server --save 20 1 --loglevel warning --requirepass '{{variables.password.value}}' 9 | volumes: 10 | - ./data:/data 11 | -------------------------------------------------------------------------------- /apps/redis/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/redis/favicon.png -------------------------------------------------------------------------------- /apps/redis/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdm1kfn0p80ndal4hqg@COLI 3 | name: Redis 4 | desc: Redis KV 数据库 5 | tags: 6 | - KV 数据库 7 | - 中间件 8 | - cache 9 | version: 0.6.2 10 | display_version: 6.2 11 | homepage: https://github.com/redis/redis 12 | author: 13 | name: Honsun 14 | mail: honsun@linux.com 15 | resource: 16 | limit: 17 | cpu: 1 18 | memory: 1024M 19 | disk: 1G 20 | recommand: 21 | cpu: 2 22 | memory: 2048M 23 | disk: 2G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: 29 | redis: 30 | ip: 127.0.0.1 31 | port: 6379 32 | desc: redis 监听地址 33 | 34 | variables: 35 | password: 36 | name: redis 的初始化密码 37 | desc: redis 的初始化密码, 请注意密码的复杂度 38 | value: your-secret 39 | -------------------------------------------------------------------------------- /apps/redis/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/redis/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/redis/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/safeline-ce/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | networks: 2 | safeline-ce: 3 | name: safeline-ce 4 | driver: bridge 5 | ipam: 6 | driver: default 7 | config: 8 | - gateway: ${SUBNET_PREFIX:?SUBNET_PREFIX required}.1 9 | subnet: ${SUBNET_PREFIX}.0/24 10 | driver_opts: 11 | com.docker.network.bridge.name: safeline-ce 12 | 13 | services: 14 | postgres: 15 | container_name: safeline-pg 16 | restart: always 17 | image: swr.cn-east-3.myhuaweicloud.com/chaitin-safeline/safeline-postgres:15.2 18 | volumes: 19 | - ${SAFELINE_DIR}/resources/postgres/data:/var/lib/postgresql/data 20 | - /etc/localtime:/etc/localtime:ro 21 | environment: 22 | - POSTGRES_USER=safeline-ce 23 | - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?postgres password required} 24 | networks: 25 | safeline-ce: 26 | ipv4_address: ${SUBNET_PREFIX}.2 27 | command: [ postgres, -c, max_connections=600 ] 28 | mgt: 29 | container_name: safeline-mgt 30 | restart: always 31 | image: swr.cn-east-3.myhuaweicloud.com/chaitin-safeline/safeline-mgt:6.1.3 32 | volumes: 33 | - /etc/localtime:/etc/localtime:ro 34 | - ${SAFELINE_DIR}/resources/mgt:/app/data 35 | - ${SAFELINE_DIR}/logs/nginx:/app/log/nginx:z 36 | ports: 37 | - '{{ports.management.ip}}:{{ports.management.port}}:1443' 38 | healthcheck: 39 | test: curl -k -f https://localhost:1443/api/open/health 40 | environment: 41 | - MGT_PG=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-pg/safeline-ce?sslmode=disable 42 | - MGT_LICENSE_SERVER=https://safeline-ce-4463.rivers.chaitin.cn/ 43 | depends_on: 44 | - postgres 45 | - fvm 46 | networks: 47 | safeline-ce: 48 | ipv4_address: ${SUBNET_PREFIX}.4 49 | detect: 50 | container_name: safeline-detector 51 | restart: always 52 | image: swr.cn-east-3.myhuaweicloud.com/chaitin-safeline/safeline-detector:6.1.3 53 | volumes: 54 | - ${SAFELINE_DIR}/resources/detector:/resources/detector 55 | - ${SAFELINE_DIR}/logs/detector:/logs/detector 56 | - /etc/localtime:/etc/localtime:ro 57 | environment: 58 | - LOG_DIR=/logs/detector 59 | networks: 60 | safeline-ce: 61 | ipv4_address: ${SUBNET_PREFIX}.5 62 | mario: 63 | container_name: safeline-mario 64 | restart: always 65 | image: swr.cn-east-3.myhuaweicloud.com/chaitin-safeline/safeline-mario:6.1.3 66 | volumes: 67 | - ${SAFELINE_DIR}/resources/mario:/resources/mario 68 | - ${SAFELINE_DIR}/logs/mario:/logs/mario 69 | - /etc/localtime:/etc/localtime:ro 70 | environment: 71 | - LOG_DIR=/logs/mario 72 | - GOGC=100 73 | - DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-pg/safeline-ce 74 | networks: 75 | safeline-ce: 76 | ipv4_address: ${SUBNET_PREFIX}.6 77 | tengine: 78 | container_name: safeline-tengine 79 | restart: always 80 | image: swr.cn-east-3.myhuaweicloud.com/chaitin-safeline/safeline-tengine:6.1.3 81 | volumes: 82 | - /etc/localtime:/etc/localtime:ro 83 | - /etc/resolv.conf:/etc/resolv.conf:ro 84 | - ${SAFELINE_DIR}/resources/nginx:/etc/nginx 85 | - ${SAFELINE_DIR}/resources/detector:/resources/detector 86 | - ${SAFELINE_DIR}/resources/chaos:/resources/chaos 87 | - ${SAFELINE_DIR}/logs/nginx:/var/log/nginx:z 88 | - ${SAFELINE_DIR}/resources/cache:/usr/local/nginx/cache 89 | environment: 90 | - TCD_MGT_API=https://${SUBNET_PREFIX}.4:1443/api/open/publish/server 91 | - TCD_SNSERVER=${SUBNET_PREFIX}.5:8000 92 | # deprecated 93 | - SNSERVER_ADDR=${SUBNET_PREFIX}.5:8000 94 | ulimits: 95 | nofile: 131072 96 | network_mode: host 97 | luigi: 98 | container_name: safeline-luigi 99 | restart: always 100 | image: swr.cn-east-3.myhuaweicloud.com/chaitin-safeline/safeline-luigi:6.1.3 101 | volumes: 102 | - /etc/localtime:/etc/localtime:ro 103 | - ${SAFELINE_DIR}/resources/luigi:/app/data 104 | networks: 105 | safeline-ce: 106 | ipv4_address: ${SUBNET_PREFIX}.7 107 | environment: 108 | - MGT_IP=${SUBNET_PREFIX}.4 109 | depends_on: 110 | - detect 111 | - mgt 112 | fvm: 113 | container_name: safeline-fvm 114 | restart: always 115 | image: swr.cn-east-3.myhuaweicloud.com/chaitin-safeline/safeline-fvm:6.1.3 116 | volumes: 117 | - /etc/localtime:/etc/localtime:ro 118 | networks: 119 | safeline-ce: 120 | ipv4_address: ${SUBNET_PREFIX}.8 121 | bridge: 122 | container_name: safeline-bridge 123 | restart: always 124 | image: swr.cn-east-3.myhuaweicloud.com/chaitin-safeline/safeline-bridge:6.1.3 125 | command: 126 | - /app/bridge 127 | - serve 128 | - -n 129 | - unix 130 | - -a 131 | - /app/run/safeline.sock 132 | volumes: 133 | - /etc/localtime:/etc/localtime:ro 134 | - /var/run:/app/run 135 | logging: 136 | options: 137 | max-size: "100m" 138 | max-file: "10" 139 | networks: 140 | safeline-ce: 141 | ipv4_address: ${SUBNET_PREFIX}.9 142 | depends_on: 143 | - mgt 144 | chaos: 145 | container_name: safeline-chaos 146 | restart: always 147 | image: swr.cn-east-3.myhuaweicloud.com/chaitin-safeline/safeline-chaos:6.1.3 148 | logging: 149 | options: 150 | max-size: "100m" 151 | max-file: "10" 152 | volumes: 153 | - ${SAFELINE_DIR}/resources/chaos:/app/chaos 154 | networks: 155 | safeline-ce: 156 | ipv4_address: ${SUBNET_PREFIX}.10 157 | -------------------------------------------------------------------------------- /apps/safeline-ce/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/safeline-ce/favicon.png -------------------------------------------------------------------------------- /apps/safeline-ce/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdm2evn0p80h8e6oq8g@COLI 3 | name: 长亭雷池 WAF 社区版 4 | desc: Web 防护系统,保护你的网站不受黑客攻击。 5 | tags: 6 | - 安全 7 | - WAF 8 | - Web 9 | version: 6.1.3 10 | display_version: 6.1.3 11 | homepage: https://github.com/chaitin/safeline 12 | author: 13 | name: chaitin 14 | mail: chaitin@chaitin.com 15 | resource: 16 | limit: 17 | cpu: 2 18 | memory: 4G 19 | disk: 10G 20 | recommand: 21 | cpu: 4 22 | memory: 8G 23 | disk: 20G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: 29 | management: 30 | ip: 0.0.0.0 31 | port: 9443 32 | desc: 控制台 33 | 34 | variables: 35 | -------------------------------------------------------------------------------- /apps/safeline-ce/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | 6 | echo "SAFELINE_DIR=$(pwd)" >> .env 7 | echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 > .env 8 | echo "REDIS_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 > .env 9 | echo "SUBNET_PREFIX=172.22.222" >> .env 10 | echo "INSTALLED_BY=COLLIE" >> .env 11 | -------------------------------------------------------------------------------- /apps/safeline-ce/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/safeline-ce/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/veinmind/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | veinmind-agent: 4 | image: veinmind/veinmind-agent:v2.3.8 5 | command: 6 | - daemon -t ${RIVERS_TOKEN} -c https://veinmind-cood.rivers.chaitin.cn/server/ca -s https://veinmind-cood.rivers.chaitin.cn/server/list 7 | volumes: 8 | - /:/host 9 | - /etc/hostname:/app/host/hostname 10 | - /usr/local/.veinmind/agent/local/resource:/app/resource 11 | privileged: true 12 | network_mode: host 13 | pid: host -------------------------------------------------------------------------------- /apps/veinmind/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/veinmind/favicon.png -------------------------------------------------------------------------------- /apps/veinmind/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chea657n0p8bp0anmieg@COL 3 | name: 长亭牧云容器安全 - Veinmind 4 | desc: 镜像/容器安全防护系统,保护你的镜像与容器安全。 5 | tags: 6 | - 云安全 7 | - 云原生 8 | - 容器安全 9 | - 镜像安全 10 | - Docker 11 | version: 2.3.8 12 | display_version: 2.3.8 13 | homepage: https://veinmind.chaitin.com 14 | author: 15 | name: dvk 16 | mail: dvkunion@gmail.com 17 | resource: 18 | limit: 19 | cpu: 1 20 | memory: 2G 21 | disk: 5G 22 | recommand: 23 | cpu: 2 24 | memory: 4G 25 | disk: 20G 26 | templates: 27 | - scripts/init.sh 28 | - docker-compose.yaml 29 | ports: {} 30 | variables: 31 | need-knows: 32 | name: 注意事项(-此项不需要填写,仅作为注意事项) 33 | desc: 需要配合百川 - 牧云云原生安全平台使用 - 部署后请查看 - https://rivers.chaitin.cn/app/veinmind/ 34 | value: need-knows 35 | before-install: 36 | name: 安装前准备(-此项不需要填写,仅作为安装前准备) 37 | desc: 需要配合百川 - 牧云云原生安全平台使用 - 需要在百川平台设置API-Token,并勾选牧云云原生安全平台相关权限。 38 | value: before-install 39 | after-install: 40 | name: 安装后准备(-此项不需要填写,仅作为安装后使用说明) 41 | desc: 需要配合百川 - 牧云云原生安全平台使用 - 部署后请查看 - https://rivers.chaitin.cn/app/veinmind/ 42 | value: after-install 43 | token: 44 | name: 百川 Token 45 | desc: 百川 包含牧云-容器安全API权限的 Token 46 | value: (从这里获取:https://rivers.chaitin.cn/organization/api) 47 | -------------------------------------------------------------------------------- /apps/veinmind/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | echo RIVERS_TOKEN=`curl -s -k --location --request GET -H "X-Ca-Token: {{variables.token.value}}" -H "x-rivers-user-id:1" https://veinmind.rivers.chaitin.cn/agent/install_cmd\?source_type\=1\&group_id\=0\&deploy_method\=1 | awk -F"token=|'" '{print $3}'` >> .env 6 | -------------------------------------------------------------------------------- /apps/veinmind/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | rm -r /usr/local/.veinmind/ -------------------------------------------------------------------------------- /apps/veinmind/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /apps/wordpress/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | services: 3 | wordpress: 4 | image: wordpress:6.2.0 5 | depends_on: 6 | - 'db' 7 | restart: always 8 | ports: 9 | - '{{ports.wordpress.ip}}:{{ports.wordpress.port}}:80' 10 | environment: 11 | WORDPRESS_DB_HOST: db 12 | WORDPRESS_DB_USER: wordpress 13 | WORDPRESS_DB_PASSWORD: '{{variables.db_password.value}}' 14 | WORDPRESS_DB_NAME: wordpress 15 | volumes: 16 | - ./www:/var/www/html' 17 | links: 18 | - 'db' 19 | 20 | db: 21 | image: mysql:5.7 22 | restart: always 23 | environment: 24 | MYSQL_DATABASE: wordpress 25 | MYSQL_USER: wordpress 26 | MYSQL_PASSWORD: '{{variables.db_password.value}}' 27 | MYSQL_RANDOM_ROOT_PASSWORD: '1' 28 | volumes: 29 | - ./db_data:/var/lib/mysql' 30 | -------------------------------------------------------------------------------- /apps/wordpress/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/apps/wordpress/favicon.png -------------------------------------------------------------------------------- /apps/wordpress/manifest.yaml: -------------------------------------------------------------------------------- 1 | metadata: 2 | app_id: chdpu17n0p81enlctshg@COLI 3 | name: WordPress 4 | desc: 著名的开源博客软件和 CMS 系统. 5 | tags: 6 | - 博客 7 | - CMS 8 | - 建站 9 | version: 6.2.0 10 | display_version: 6.2.0 11 | homepage: https://wordpress.com/ 12 | author: 13 | name: Honsun 14 | mail: honsun@linux.com 15 | resource: 16 | limit: 17 | cpu: 1 18 | memory: 1024M 19 | disk: 1G 20 | recommand: 21 | cpu: 2 22 | memory: 2048M 23 | disk: 2G 24 | 25 | templates: 26 | - docker-compose.yaml 27 | 28 | ports: 29 | wordpress: 30 | ip: 0.0.0.0 31 | port: 4090 32 | desc: Wordpress 监听端口 33 | 34 | variables: 35 | db_password: 36 | name: 数据库密码 37 | desc: MySQL 数据库密码, 注意复杂度 38 | value: your-secret 39 | -------------------------------------------------------------------------------- /apps/wordpress/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app is installed this script will be called after command 'docker compose up' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/wordpress/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need uninstall this script will be called after command 'docker compose down' done. 4 | # Write your logic here. 5 | -------------------------------------------------------------------------------- /apps/wordpress/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # When your app need upgrade this script will be called after command 'docker compose up' 4 | # done base on the new docker-compose.yaml file. 5 | # Write your logic here. 6 | -------------------------------------------------------------------------------- /assets/lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/assets/lifecycle.png -------------------------------------------------------------------------------- /homepage/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /homepage/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /homepage/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | pnpm i && pnpm build 3 | 4 | -------------------------------------------------------------------------------- /homepage/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: false, 4 | output: "export", 5 | images: { 6 | unoptimized: true, 7 | }, 8 | }; 9 | 10 | module.exports = nextConfig; 11 | -------------------------------------------------------------------------------- /homepage/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "icon": "node ./script/downLoadIcon.js" 11 | }, 12 | "dependencies": { 13 | "@emotion/react": "^11.10.6", 14 | "@emotion/styled": "^11.10.6", 15 | "@jsdevtools/rehype-toc": "^3.0.2", 16 | "@mui/icons-material": "^5.11.16", 17 | "@mui/lab": "5.0.0-alpha.128", 18 | "@mui/material": "^5.12.0", 19 | "@types/node": "18.15.11", 20 | "@types/react": "18.0.35", 21 | "@types/react-dom": "18.0.11", 22 | "ahooks": "^3.7.6", 23 | "axios": "^1.3.6", 24 | "eslint": "8.38.0", 25 | "eslint-config-next": "13.3.0", 26 | "github-slugger": "^2.0.0", 27 | "gray-matter": "^4.0.3", 28 | "next": "13.3.0", 29 | "next-mdx-remote": "^4.4.1", 30 | "react": "18.2.0", 31 | "react-dom": "18.2.0", 32 | "react-responsive-carousel": "^3.2.23", 33 | "remark-external-links": "^9.0.1", 34 | "remark-gfm": "^3.0.1", 35 | "remark-prism": "^1.3.6", 36 | "remark-slug": "^7.0.1", 37 | "typescript": "5.0.4" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /homepage/public/images/album/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/album/0.png -------------------------------------------------------------------------------- /homepage/public/images/album/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/album/1.png -------------------------------------------------------------------------------- /homepage/public/images/album/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/album/2.png -------------------------------------------------------------------------------- /homepage/public/images/album/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/album/3.png -------------------------------------------------------------------------------- /homepage/public/images/album/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/album/4.png -------------------------------------------------------------------------------- /homepage/public/images/album/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/album/5.png -------------------------------------------------------------------------------- /homepage/public/images/class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/class.png -------------------------------------------------------------------------------- /homepage/public/images/collie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/collie.png -------------------------------------------------------------------------------- /homepage/public/images/feature.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 编组 4备份 4 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /homepage/public/images/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/github.png -------------------------------------------------------------------------------- /homepage/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/logo.png -------------------------------------------------------------------------------- /homepage/public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 编组 5 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /homepage/public/images/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/qrcode.png -------------------------------------------------------------------------------- /homepage/public/images/wechat-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/public/images/wechat-logo.png -------------------------------------------------------------------------------- /homepage/script/downLoadIcon.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | 4 | const Axios = require("axios"); 5 | 6 | async function downloadFile(url) { 7 | const iconPath = path.resolve(__dirname, "../src/static/fonts/iconfont.js"); 8 | const writer = fs.createWriteStream(iconPath); 9 | const response = await Axios({ 10 | url: "https:" + url, 11 | method: "GET", 12 | responseType: "stream", 13 | }); 14 | response.data.pipe(writer); 15 | writer.on("finish", () => console.log("下载成功")); 16 | writer.on("error", (err) => console.log(err)); 17 | } 18 | let argument = process.argv.splice(2); 19 | downloadFile(argument[0]); 20 | -------------------------------------------------------------------------------- /homepage/src/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /homepage/src/components/Ellipsis/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { type FC, useEffect, useRef, useState } from "react"; 2 | 3 | import { Box, type SxProps, Tooltip } from "@mui/material"; 4 | 5 | interface EllipsisProps { 6 | children: React.ReactNode; 7 | sx?: SxProps; 8 | } 9 | 10 | const Ellipsis: FC = (props) => { 11 | const { children, sx } = props; 12 | const content = useRef(null); 13 | const [ellipsis, setEllipsis] = useState(false); 14 | 15 | //判断文字内容是否超出div宽度 16 | const onResize = () => { 17 | if (content.current) { 18 | setEllipsis( 19 | (content.current.parentNode! as HTMLDivElement).offsetWidth < 20 | content.current.offsetWidth 21 | ); 22 | } 23 | }; 24 | 25 | useEffect(() => { 26 | onResize(); 27 | }, [children]); 28 | 29 | return ( 30 | <> 31 | 40 | 59 | 60 | {children as React.ReactElement} 61 | 62 | 63 | 64 | 65 | ); 66 | }; 67 | 68 | export default Ellipsis; 69 | -------------------------------------------------------------------------------- /homepage/src/components/Home/Features/index.tsx: -------------------------------------------------------------------------------- 1 | import { Grid, Box, Typography } from "@mui/material"; 2 | import Image from "next/image"; 3 | 4 | const FEATURE_LIST = [ 5 | { 6 | title: "便捷管理", 7 | content: ( 8 | <> 9 | 10 | 无需开放端口,无需连接 SSH,支持管理大规模主机 11 | 12 | 13 | 一键绑定主机,实现永久托管 14 | 15 | 16 | ), 17 | }, 18 | { 19 | title: "内网穿透", 20 | content: ( 21 | <> 22 | 23 | 使用 Agent 模式,服务器无需公网 IP 24 | 25 | 26 | 打通处于不同内网主机之间的连通关系,实现跨区域组网 27 | 28 | 29 | ), 30 | }, 31 | { 32 | title: "资源监控", 33 | content: ( 34 | <> 35 | 36 | 实时监控 CPU、内存、磁盘、网络等资源,提供秒级告警 37 | 38 | 39 | 支持查看历史资源占用情况 40 | 41 | 42 | ), 43 | }, 44 | { 45 | title: "安全扫描", 46 | content: ( 47 | <> 48 | 49 | 提供完善的安全扫描体系,使系统免于受到黑客攻击 50 | 51 | 52 | 安全能力由长亭牧云主机安全引擎驱动,业界领先 53 | 54 | 55 | ), 56 | }, 57 | ]; 58 | 59 | const Features = () => { 60 | return ( 61 | 71 | 72 | {FEATURE_LIST.map((feature) => ( 73 | 74 | 78 | feature 85 | 86 | {feature.title} 87 | 88 | 89 | 92 | {feature.content} 93 | 94 | 95 | ))} 96 | 97 | 98 | ); 99 | }; 100 | 101 | export default Features; 102 | -------------------------------------------------------------------------------- /homepage/src/components/Home/FriendlyLinks/index.tsx: -------------------------------------------------------------------------------- 1 | import { Grid, Box } from "@mui/material"; 2 | 3 | import Link from "next/link"; 4 | 5 | const LINK_LIST = [ 6 | { 7 | name: "北京长亭科技有限公司", 8 | url: "https://chaitin.cn/", 9 | }, 10 | { 11 | name: "CTStack 安全社区", 12 | url: "https://stack.chaitin.cn/", 13 | }, 14 | { 15 | name: "长亭百川云平台", 16 | url: "https://rivers.chaitin.cn/", 17 | }, 18 | { 19 | name: "长亭 GitHub 主页", 20 | url: "https://github.com/chaitin", 21 | }, 22 | { 23 | name: "长亭 B 站主页", 24 | url: "https://space.bilibili.com/521870525", 25 | }, 26 | { 27 | name: "长亭合作伙伴论坛", 28 | url: "https://bbs.chaitin.cn/", 29 | }, 30 | { 31 | name: "长亭雷池 WAF 社区吧", 32 | url: "https://waf-ce.chaitin.cn/", 33 | }, 34 | ]; 35 | 36 | const FriendlyLinks = () => { 37 | return ( 38 | 39 | {LINK_LIST.map((item) => ( 40 | 41 | 54 | {item.name} 55 | 56 | 57 | ))} 58 | 59 | ); 60 | }; 61 | 62 | export default FriendlyLinks; 63 | -------------------------------------------------------------------------------- /homepage/src/components/Home/Title/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Typography, SxProps } from "@mui/material"; 3 | import Image from "next/image"; 4 | 5 | interface TitleProps { 6 | title: string; 7 | sx?: SxProps; 8 | } 9 | 10 | const Title: React.FC = ({ title, sx }) => { 11 | return ( 12 | 16 | class 24 | {title} 25 | 26 | ); 27 | }; 28 | 29 | export default Title; 30 | -------------------------------------------------------------------------------- /homepage/src/components/Home/Version/Card.tsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaitin/collie/220774337529656de5f5103439b232ee77a78376/homepage/src/components/Home/Version/Card.tsx -------------------------------------------------------------------------------- /homepage/src/components/Home/Version/Consultation.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { Message, Modal } from "@/components"; 3 | import { Box, TextField, Typography, Button } from "@mui/material"; 4 | 5 | function Consultation() { 6 | const [text, setText] = useState(""); 7 | const [wrongPhoneNumber, setWrongPhoneNumber] = useState(false); 8 | const [consultOpen, setConsultOpen] = useState(false); 9 | 10 | const consultHandler = () => { 11 | const valid = /^1[3-9]\d{9}$/.test(text); 12 | setWrongPhoneNumber(!valid); 13 | if (!valid) { 14 | Message.error("手机号格式不正确"); 15 | return; 16 | } 17 | fetch("https://leads.chaitin.net/api/trial", { 18 | // fetch('http://116.62.230.26:8999/api/trial', { // 测试用地址 19 | method: "POST", 20 | mode: "cors", 21 | headers: { "Content-Type": "application/json" }, 22 | body: JSON.stringify({ 23 | phone: text, 24 | platform_source: "product-official-site", 25 | product_source: "safeline-ce", 26 | source_detail: "来自雷池社区版官网", 27 | }), 28 | }) 29 | .then((d) => d.json()) 30 | .then((d) => { 31 | if (d.code == 0) { 32 | Message.success("提交成功"); 33 | } else { 34 | Message.error("提交失败"); 35 | } 36 | setConsultOpen(false); 37 | }); 38 | }; 39 | 40 | const textHandler = (v: string) => { 41 | setText(v); 42 | }; 43 | 44 | useEffect(() => { 45 | if (!consultOpen) { 46 | setText(""); 47 | } 48 | }, [consultOpen]); 49 | 50 | return ( 51 | <> 52 | 67 | setConsultOpen(false)} 70 | title="咨询企业版" 71 | okText="提交" 72 | onOk={consultHandler} 73 | sx={{ width: 600 }} 74 | > 75 | 76 |
77 | textHandler(e.target.value)} 88 | /> 89 |
90 | 91 | 我们将在工作时间 2 小时内联系您,您的手机号不会用于其他目的 92 | 93 |
94 |
95 | 96 | ); 97 | } 98 | 99 | export default Consultation; 100 | -------------------------------------------------------------------------------- /homepage/src/components/Home/Version/FunctionTable.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Table, 3 | TableBody, 4 | TableCell, 5 | TableContainer, 6 | TableHead, 7 | TableRow, 8 | Box, 9 | Collapse, 10 | ListItem, 11 | ListItemIcon, 12 | ListItemText, 13 | alpha, 14 | Tooltip, 15 | } from "@mui/material"; 16 | import React, { useState } from "react"; 17 | import ExpandLess from "@mui/icons-material/ExpandLess"; 18 | import ExpandMore from "@mui/icons-material/ExpandMore"; 19 | import { Icon } from "@/components"; 20 | 21 | const Support = () => { 22 | return ( 23 | 24 | ); 25 | }; 26 | const NotSupport = () => { 27 | return ; 28 | }; 29 | 30 | const FontSupport = (props: { text: string; color: string; }) => { 31 | const { text, color } = props 32 | return { text }; 33 | }; 34 | 35 | const FunctionTable = () => { 36 | const [open, setOpen] = useState(["基本功能", "文件管理", "在线终端", "资源监控"]); 37 | 38 | const cells = [ 39 | { 40 | title: "基本功能", 41 | data: [ 42 | { 43 | name: "资源占用监控", 44 | experience: , 45 | basics: , 46 | }, { 47 | name: "跨区域组网", 48 | experience: , 49 | basics: , 50 | }, { 51 | name: "Docker 管理", 52 | experience: , 53 | basics: , 54 | }, { 55 | name: "安全扫描", 56 | experience: , 57 | basics: , 58 | }, { 59 | name: "进程管理", 60 | experience: , 61 | basics: , 62 | }, { 63 | name: "用户管理", 64 | experience: , 65 | basics: , 66 | }, { 67 | name: "端口管理", 68 | experience: , 69 | basics: , 70 | }, { 71 | name: "登录审计", 72 | experience: , 73 | basics: , 74 | }, { 75 | name: "可管理主机数量", 76 | experience: , 77 | basics: , 78 | }, { 79 | name: "扣费标准", 80 | experience: , 81 | basics: , 82 | } 83 | ] 84 | }, 85 | { 86 | title: "文件管理", 87 | data: [ 88 | { 89 | name: "在线编辑文件", 90 | experience: , 91 | basics: , 92 | }, { 93 | name: "文件上传大小限制", 94 | tip: "", 95 | experience: , 96 | basics: , 97 | }, { 98 | name: "文件传输速率限制", 99 | experience: , 100 | basics: , 101 | } 102 | ] 103 | }, 104 | { 105 | title: "在线终端", 106 | data: [ 107 | { 108 | name: "终端远程协助", 109 | experience: , 110 | basics: , 111 | }, { 112 | name: "Docker 容器终端", 113 | experience: , 114 | basics: , 115 | }, 116 | ] 117 | }, 118 | { 119 | title: "资源监控", 120 | data: [ 121 | { 122 | name: "实时资源监控", 123 | experience: , 124 | basics: , 125 | }, { 126 | name: "历史资源监控", 127 | experience: , 128 | basics: , 129 | }, { 130 | name: "监控 CPU 使用情况", 131 | experience: , 132 | basics: , 133 | }, { 134 | name: "监控内存使用情况", 135 | experience: , 136 | basics: , 137 | }, { 138 | name: "监控磁盘容量情况", 139 | experience: , 140 | basics: , 141 | }, { 142 | name: "监控磁盘吞吐情况", 143 | experience: , 144 | basics: , 145 | }, { 146 | name: "监控网络吞吐情况", 147 | experience: , 148 | basics: , 149 | } 150 | ] 151 | } 152 | ] 153 | 154 | const handleClick = (id: string) => { 155 | if (open?.includes(id)) { 156 | const udpateOpen = [...open] 157 | udpateOpen.splice(open?.indexOf(id), 1) 158 | setOpen([...udpateOpen]) 159 | } else { 160 | setOpen((open) => [...open, id]) 161 | } 162 | }; 163 | 164 | return ( 165 | <> 166 | 167 | 177 | 178 | 179 | 180 | 181 | ({ 183 | display: "flex", 184 | justifyContent: "center", 185 | alignItems: "center", 186 | width: "100%", 187 | height: "40px", 188 | borderRadius: "4px", 189 | color: theme.palette.primary.main, 190 | backgroundColor: alpha(theme.palette.primary.main, 0.2), 191 | })} 192 | > 193 | 个人版 194 | 195 | 196 | 197 | ({ 199 | display: "flex", 200 | justifyContent: "center", 201 | alignItems: "center", 202 | width: "100%", 203 | color: theme.palette.primary.main, 204 | backgroundColor: alpha(theme.palette.primary.main, 0.1), 205 | height: "40px", 206 | borderRadius: "4px", 207 | })} 208 | > 209 | 专业版 210 | 211 | 212 | 213 | 214 |
215 |
216 | {cells?.map(data => 217 | 218 | handleClick(data?.title)} 220 | sx={{ 221 | backgroundColor: "#EFF1F8", 222 | borderRadius: "4px", 223 | cursor: "pointer", 224 | pl: "20px", 225 | }} 226 | > 227 | 231 | 232 | {open?.includes(data?.title) ? : } 233 | 234 | 235 | 236 | 237 | 260 | 265 | {data.data.map((item) => ( 266 | 267 | 268 | 269 | {item.name} 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | {item.experience} 279 | 280 | 281 | {item.basics} 282 | 283 | 284 | ))} 285 | 286 |
287 |
288 |
)} 289 | 290 | ); 291 | }; 292 | 293 | export default FunctionTable; 294 | -------------------------------------------------------------------------------- /homepage/src/components/Home/Version/index.tsx: -------------------------------------------------------------------------------- 1 | import { Typography, Box, Button, alpha } from "@mui/material"; 2 | import Title from "@/components/Home/Title"; 3 | import FunctionTable from "./FunctionTable"; 4 | import Consultation from "./Consultation"; 5 | import Link from "next/link"; 6 | const FREE_FUNCTION = [ 7 | "资源占用监控", 8 | "文件管理", 9 | "自定义黑白名单", 10 | "精细化引擎调节", 11 | "可视化安全分析", 12 | ]; 13 | const ENTERPRISE_FUNCTION = [ 14 | "资源占用监控", 15 | "文件管理", 16 | "集群式可扩展部署", 17 | "CC 攻击防护", 18 | "业务 API 智能建模", 19 | "Bot 管理,恶意 Bot 防护", 20 | "专业技术支持服务", 21 | "漏洞应急服务", 22 | ]; 23 | 24 | const Version = () => { 25 | return ( 26 | <> 27 | 28 | 29 | ); 30 | }; 31 | 32 | export default Version; 33 | -------------------------------------------------------------------------------- /homepage/src/components/Icon/index.tsx: -------------------------------------------------------------------------------- 1 | import { type FC, useEffect } from "react"; 2 | 3 | import { Box, type SxProps } from "@mui/material"; 4 | 5 | interface IconProps { 6 | type: string; 7 | sx?: SxProps; 8 | [propName: string]: any; 9 | } 10 | 11 | const Icon: FC = ({ type, sx, ...restProps }) => { 12 | useEffect(() => { 13 | require("../../static/fonts/iconfont"); 14 | }, []); 15 | return ( 16 | // @ts-ignore 17 | 25 | ); 26 | }; 27 | export default Icon; 28 | -------------------------------------------------------------------------------- /homepage/src/components/MarkdownNavbar/index.tsx: -------------------------------------------------------------------------------- 1 | import { type FC, useEffect, useRef, useState } from "react"; 2 | import { Ellipsis } from "@/components"; 3 | import { useRouter } from "next/router"; 4 | import { Box } from "@mui/material"; 5 | import Link from "next/link"; 6 | import { useDebounceFn, useThrottleFn } from "ahooks"; 7 | import { slug } from "github-slugger"; 8 | 9 | interface MarkdownNavbarProps { 10 | container?: HTMLElement; 11 | source: string; 12 | } 13 | 14 | const MarkdownNavbar: FC = (props) => { 15 | const router = useRouter(); 16 | let { container, source } = props; 17 | if (!container && typeof window !== "undefined") { 18 | // @ts-ignore 19 | container = document; 20 | } 21 | const [currentListNo, setCurrentListNo] = useState(""); 22 | const [navStructure, setNavStructure] = useState([]); 23 | const scrollEventLock = useRef(false); 24 | const timer = useRef(); 25 | 26 | const trimArrZero = (arr: number[]) => { 27 | let start, end; 28 | for (start = 0; start < arr.length; start++) { 29 | if (arr[start]) { 30 | break; 31 | } 32 | } 33 | for (end = arr.length - 1; end >= 0; end--) { 34 | if (arr[end]) { 35 | break; 36 | } 37 | } 38 | return arr.slice(start, end + 1); 39 | }; 40 | 41 | const getHeadingList = () => { 42 | const headingList: { dataId: string; listNo: string; offsetTop: number }[] = 43 | []; 44 | 45 | navStructure.forEach((t) => { 46 | const headings = document.querySelectorAll(`h${t.level}`); 47 | const curHeading = Array.prototype.slice 48 | .apply(headings) 49 | .find( 50 | (h) => 51 | h.innerText.trim() === t.text.trim() && 52 | !headingList.find( 53 | (x) => x.offsetTop === h.getBoundingClientRect().top 54 | ) 55 | ); 56 | if (curHeading) { 57 | let rect = curHeading.getBoundingClientRect(); 58 | headingList.push({ 59 | dataId: `heading-${t.index}`, 60 | listNo: t.listNo, 61 | offsetTop: rect.top, 62 | }); 63 | } 64 | }); 65 | return headingList; 66 | }; 67 | 68 | const initHeadingsId = (navStructure: any[]) => { 69 | navStructure.forEach((t) => { 70 | const headings = document.querySelectorAll(`h${t.level}`); 71 | const curHeading = Array.prototype.slice 72 | .apply(headings) 73 | .find( 74 | (h) => 75 | h.innerText.trim() === t.text.trim() && 76 | (!h.dataset || !h.dataset.id) 77 | ); 78 | 79 | if (curHeading) { 80 | curHeading.dataset.id = `heading-${t.index}`; 81 | } 82 | }); 83 | }; 84 | 85 | const getNavStructure = (source: string) => { 86 | const contentWithoutCode = source 87 | .replace(/^[^#]+\n/g, "") 88 | .replace(/(?:[^\n#]+)#+\s([^#\n]+)\n*/g, "") // 匹配行内出现 # 号的情况 89 | .replace(/^#\s[^#\n]*\n+/, "") 90 | .replace(/```[^`\n]*\n+[^```]+```\n+/g, "") 91 | .replace(/`([^`\n]+)`/g, "$1") 92 | .replace(/\*\*?([^*\n]+)\*\*?/g, "$1") 93 | .replace(/__?([^_\n]+)__?/g, "$1") 94 | .trim(); 95 | 96 | const pattOfTitle = /#+\s([^#\n]+)\n*/g; 97 | const matchResult = contentWithoutCode.match(pattOfTitle); 98 | 99 | if (!matchResult) { 100 | return []; 101 | } 102 | 103 | const navData = matchResult.map((r, i) => ({ 104 | index: i, 105 | level: r.match(/^#+/g)![0].length, 106 | text: r.replace(pattOfTitle, "$1"), 107 | listNo: "", 108 | })); 109 | 110 | let maxLevel = 0; 111 | navData.forEach((t) => { 112 | if (t.level > maxLevel) { 113 | maxLevel = t.level; 114 | } 115 | }); 116 | let matchStack = []; 117 | // 此部分重构,原有方法会出现次级标题后再次出现高级标题时,listNo重复的bug 118 | for (let i = 0; i < navData.length; i++) { 119 | const t = navData[i]; 120 | const { level } = t; 121 | while ( 122 | matchStack.length && 123 | matchStack[matchStack.length - 1].level > level 124 | ) { 125 | matchStack.pop(); 126 | } 127 | if (matchStack.length === 0) { 128 | const arr = new Array(maxLevel).fill(0); 129 | arr[level - 1] += 1; 130 | matchStack.push({ 131 | level, 132 | arr, 133 | }); 134 | t.listNo = trimArrZero(arr).join("."); 135 | continue; 136 | } 137 | const arr: number[] = matchStack[matchStack.length - 1].arr; 138 | const newArr = arr.slice(); 139 | newArr[level - 1] += 1; 140 | matchStack.push({ 141 | level, 142 | arr: newArr, 143 | }); 144 | t.listNo = trimArrZero(newArr).join("."); 145 | } 146 | return navData; 147 | }; 148 | 149 | const refreshNav = (source: string) => { 150 | const navStructure = getNavStructure(source); 151 | setNavStructure(navStructure.filter((nav) => [2, 3].includes(nav.level))); 152 | setCurrentListNo(navStructure[0]?.listNo); 153 | initHeadingsId(navStructure); 154 | container?.addEventListener("scroll", winScroll, false); 155 | }; 156 | 157 | const { run: winScroll } = useThrottleFn( 158 | () => { 159 | clearTimeout(timer.current); 160 | if (scrollEventLock.current) return; 161 | const newHeadingList = getHeadingList().map((h) => ({ 162 | ...h, 163 | distanceToTop: Math.abs(h.offsetTop), 164 | })); 165 | const distanceList = newHeadingList.map((h) => h.distanceToTop); 166 | const minDistance = Math.min(...distanceList); 167 | const curHeading = newHeadingList.find( 168 | (h) => h.distanceToTop === minDistance 169 | ); 170 | if (!curHeading) return; 171 | timer.current = setTimeout(() => { 172 | setCurrentListNo(curHeading.listNo); 173 | }); 174 | }, 175 | { wait: 300 } 176 | ); 177 | 178 | const { run: scrollToTarget } = useDebounceFn( 179 | (dataId: string) => { 180 | const target = document.querySelector(`[data-id="${dataId}"]`); 181 | if (target) { 182 | target.scrollIntoView({ behavior: "smooth" }); 183 | scrollEventLock.current = true; 184 | setTimeout(() => { 185 | scrollEventLock.current = false; 186 | }, 500); 187 | } 188 | }, 189 | { wait: 0 } 190 | ); 191 | 192 | useEffect(() => { 193 | refreshNav(source); 194 | return () => { 195 | container?.removeEventListener("scroll", winScroll, false); 196 | }; 197 | }, [source]); 198 | 199 | const tBlocks = navStructure.map((t, index) => { 200 | const cls = `title-anchor title-level${t.level}`; 201 | const point = slug(t.text); 202 | let hash = router.asPath.split("#")[1]; 203 | return ( 204 | 211 | 220 | {t.text} 221 | 222 | 223 | ); 224 | }); 225 | return
{tBlocks}
; 226 | }; 227 | 228 | export default MarkdownNavbar; 229 | -------------------------------------------------------------------------------- /homepage/src/components/Message/Alert.tsx: -------------------------------------------------------------------------------- 1 | import React, { type FC, useRef, useEffect } from 'react' 2 | 3 | import { Alert as MAlert, type AlertColor } from '@mui/material' 4 | 5 | interface AlertProps { 6 | duration?: number 7 | onClose?(key: React.Key): void 8 | noticeKey: React.Key 9 | content?: React.ReactNode 10 | severity: AlertColor 11 | } 12 | 13 | const Alert: FC = (props) => { 14 | const { duration, severity, content, noticeKey, onClose } = props 15 | const closeTimer = useRef(null) 16 | 17 | const startCloseTimer = () => { 18 | if (duration) { 19 | closeTimer.current = window.setTimeout(() => { 20 | close() 21 | }, duration * 1000) 22 | } 23 | } 24 | 25 | const clearCloseTimer = () => { 26 | if (closeTimer.current) { 27 | clearTimeout(closeTimer.current) 28 | closeTimer.current = null 29 | } 30 | } 31 | 32 | const close = (e?: React.MouseEvent) => { 33 | if (e) { 34 | e.stopPropagation() 35 | } 36 | clearCloseTimer() 37 | if (onClose) { 38 | onClose(noticeKey) 39 | } 40 | } 41 | 42 | useEffect(() => { 43 | startCloseTimer() 44 | return () => { 45 | clearCloseTimer() 46 | } 47 | // eslint-disable-next-line react-hooks/exhaustive-deps 48 | }, []) 49 | 50 | return ( 51 | 52 | {content} 53 | 54 | ) 55 | } 56 | 57 | export default Alert 58 | -------------------------------------------------------------------------------- /homepage/src/components/Message/Message.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, forwardRef, useImperativeHandle } from "react"; 2 | 3 | import { Snackbar, Box, type AlertColor } from "@mui/material"; 4 | 5 | import { ThemeProvider } from "@/components"; 6 | import { render, unmount } from "@/utils"; 7 | 8 | import Alert from "./Alert"; 9 | 10 | export interface Notice { 11 | key?: React.Key; 12 | content?: React.ReactNode; 13 | severity: AlertColor; 14 | onClose?: () => void; 15 | } 16 | 17 | interface MessageProps {} 18 | 19 | let seed = 0; 20 | const now = Date.now(); 21 | 22 | function getUuid() { 23 | const id = seed; 24 | seed += 1; 25 | return `ctMessage_${now}_${id}`; 26 | } 27 | 28 | // eslint-disable-next-line react/display-name 29 | const Message = forwardRef((props, ref) => { 30 | const [notices, setNotices] = useState([]); 31 | const add = (notice: Notice) => { 32 | const key = notice.key ?? getUuid(); 33 | setNotices((state) => { 34 | state.push({ ...notice, key }); 35 | return [...state]; 36 | }); 37 | }; 38 | 39 | const remove = (key: React.Key) => { 40 | setNotices((state) => state.filter((s) => s.key !== key)); 41 | }; 42 | 43 | useImperativeHandle(ref, () => ({ 44 | add, 45 | remove, 46 | })); 47 | 48 | return ( 49 | 50 | 51 | 52 | {notices.map((item) => { 53 | const alertProps = { 54 | ...item, 55 | noticeKey: item.key!, 56 | onClose: (noticeKey: React.Key) => { 57 | remove(noticeKey); 58 | }, 59 | }; 60 | return ; 61 | })} 62 | 63 | 64 | 65 | ); 66 | }); 67 | 68 | // @ts-ignore 69 | Message.newInstance = (properties: MessageProps, callback) => { 70 | const { ...props } = properties || {}; 71 | const div = document?.createElement("div"); 72 | document.body.appendChild(div); 73 | let called = false; 74 | function ref(notification: any) { 75 | if (called) { 76 | return; 77 | } 78 | called = true; 79 | callback({ 80 | notice(noticeProps: MessageProps) { 81 | notification.add(noticeProps); 82 | }, 83 | removeNotice(key: React.Key) { 84 | notification.remove(key); 85 | }, 86 | component: notification, 87 | destroy() { 88 | unmount(div); 89 | if (div.parentNode) { 90 | div.parentNode.removeChild(div); 91 | } 92 | }, 93 | }); 94 | } 95 | setTimeout(() => { 96 | render(, div); 97 | }); 98 | }; 99 | 100 | export default Message; 101 | -------------------------------------------------------------------------------- /homepage/src/components/Message/index.tsx: -------------------------------------------------------------------------------- 1 | import type React from "react"; 2 | 3 | import { type AlertColor } from "@mui/material"; 4 | 5 | import Notification from "./Message"; 6 | 7 | type MessageStaticFunctions = Record< 8 | AlertColor, 9 | (context: React.ReactNode, duration?: number) => void 10 | >; 11 | 12 | const Message = {} as MessageStaticFunctions; 13 | 14 | let notification: any = null; 15 | 16 | if (typeof window !== "undefined") { 17 | // @ts-ignore 18 | Notification.newInstance({}, (n: any) => { 19 | notification = n; 20 | }); 21 | 22 | const commonOpen = 23 | (type: AlertColor) => 24 | (content: React.ReactNode, duration: number = 3) => { 25 | notification.notice({ 26 | duration, 27 | severity: type, 28 | content, 29 | }); 30 | }; 31 | 32 | (["success", "warning", "info", "error"] as const).forEach((type) => { 33 | Message[type] = commonOpen(type); 34 | }); 35 | } 36 | 37 | export default Message; 38 | -------------------------------------------------------------------------------- /homepage/src/components/Modal/ConfirmDialog.tsx: -------------------------------------------------------------------------------- 1 | import React, { type FC } from "react"; 2 | 3 | import ErrorIcon from "@mui/icons-material/Error"; 4 | import { Box } from "@mui/material"; 5 | 6 | import { ThemeProvider } from "@/components"; 7 | 8 | import Modal, { type ModalProps } from "./Modal"; 9 | 10 | export interface ConfirmDialogProps extends ModalProps { 11 | content?: React.ReactNode; 12 | width?: string; 13 | } 14 | 15 | const ConfirmDialog: FC = (props) => { 16 | const { title = "提示", content, width = "480px", ...rest } = props; 17 | return ( 18 | 19 | 30 | 33 | {title} 34 | 35 | } 36 | closable={false} 37 | {...rest} 38 | sx={{ width }} 39 | > 40 | {content} 41 | 42 | 43 | ); 44 | }; 45 | 46 | export default ConfirmDialog; 47 | -------------------------------------------------------------------------------- /homepage/src/components/Modal/Modal.tsx: -------------------------------------------------------------------------------- 1 | import React, { type FC, useState } from 'react' 2 | 3 | import CloseIcon from '@mui/icons-material/Close' 4 | import { LoadingButton } from '@mui/lab' 5 | import { Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton } from '@mui/material' 6 | 7 | export interface ModalProps { 8 | open?: boolean 9 | title?: React.ReactNode 10 | children?: React.ReactNode 11 | footer?: false | React.ReactNode 12 | okText?: React.ReactNode 13 | cancelText?: React.ReactNode 14 | showCancel?: boolean 15 | okColor?: 'primary' | 'error' 16 | cancelColor?: 'primary' | 'error' 17 | closable?: boolean 18 | onOk?(): void 19 | onClose?(): void 20 | onCancel?(): void 21 | sx?: any 22 | } 23 | 24 | const Modal: FC = (props) => { 25 | const { 26 | open = false, 27 | title, 28 | children, 29 | footer, 30 | okText = '确认', 31 | okColor = 'primary', 32 | cancelColor = 'primary', 33 | showCancel = true, 34 | cancelText = '取消', 35 | onOk, 36 | onClose, 37 | onCancel, 38 | closable = true, 39 | sx = {}, 40 | } = props 41 | const [loading, setLoading] = useState(false) 42 | 43 | const onConfirm = async () => { 44 | setLoading(true) 45 | try { 46 | await onOk?.() 47 | } catch (error) {} 48 | 49 | setLoading(false) 50 | } 51 | 52 | return ( 53 | 66 | {(title || closable) && ( 67 | 78 | {title} 79 | {closable && ( 80 | 86 | 87 | 88 | )} 89 | 90 | )} 91 | 92 | {children} 93 | {footer === false && null} 94 | {footer === undefined && ( 95 | 103 | {showCancel && ( 104 | 107 | )} 108 | 109 | 110 | {okText} 111 | 112 | 113 | )} 114 | {footer && ( 115 | 123 | {footer} 124 | 125 | )} 126 | 127 | ) 128 | } 129 | 130 | export default Modal 131 | -------------------------------------------------------------------------------- /homepage/src/components/Modal/confrim.tsx: -------------------------------------------------------------------------------- 1 | import { render as reactRender } from "@/utils"; 2 | 3 | import ConfirmDialog, { type ConfirmDialogProps } from "./ConfirmDialog"; 4 | 5 | export default function confirm(config: ConfirmDialogProps) { 6 | const container = document.createDocumentFragment(); 7 | const { onCancel: propCancel, onOk: propOk } = config; 8 | const onCancel = async () => { 9 | await propCancel?.(); 10 | close(); 11 | }; 12 | const onOk = async () => { 13 | await propOk?.(); 14 | close(); 15 | }; 16 | let currentConfig = { ...config, open: true, onCancel, onOk } as any; 17 | function render(props: ConfirmDialogProps) { 18 | setTimeout(() => { 19 | reactRender(, container); 20 | }); 21 | } 22 | 23 | function close() { 24 | currentConfig = { 25 | ...currentConfig, 26 | open: false, 27 | }; 28 | render(currentConfig); 29 | } 30 | 31 | render(currentConfig); 32 | } 33 | -------------------------------------------------------------------------------- /homepage/src/components/Modal/index.tsx: -------------------------------------------------------------------------------- 1 | import { type ConfirmDialogProps } from './ConfirmDialog' 2 | import OriginModal from './Modal' 3 | import confirm from './confrim' 4 | 5 | type ModalStaticFunctions = Record<'confirm', (config: ConfirmDialogProps) => void> 6 | type ModalType = typeof OriginModal 7 | 8 | const Modal = OriginModal as ModalType & ModalStaticFunctions 9 | 10 | Modal.confirm = confirm 11 | 12 | export default Modal 13 | -------------------------------------------------------------------------------- /homepage/src/components/ThemeProvider/index.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo, useEffect, useState } from "react"; 2 | 3 | import { 4 | ThemeProvider as MUIThemeProvider, 5 | useMediaQuery, 6 | } from "@mui/material"; 7 | import { useLocalStorageState } from "ahooks"; 8 | 9 | import themes from "../../themes"; 10 | import ThemeContext, { type ThemeMode } from "../../themes/themeContext"; 11 | 12 | interface ThemeProviderProps { 13 | children?: React.ReactNode; 14 | } 15 | 16 | const ThemeProvider: React.FC = ({ children }) => { 17 | // const [mode, setMode] = useLocalStorageState("themeMode", { 18 | // defaultValue: "system", 19 | // }); 20 | const [mode, setMode] = useState("light"); 21 | const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)"); 22 | 23 | const theme = useMemo(() => { 24 | let newMode = mode; 25 | if (mode === "system") { 26 | newMode = prefersDarkMode ? "dark" : "light"; 27 | } 28 | return themes(newMode as "dark" | "light"); 29 | }, [mode, prefersDarkMode]); 30 | 31 | const themeMode = useMemo(() => { 32 | return { 33 | mode, 34 | setThemeMode: (mode: ThemeMode) => { 35 | setMode(mode); 36 | }, 37 | }; 38 | }, [mode]); 39 | 40 | useEffect(() => { 41 | const bodyStyle = document.body.style; 42 | const body = document.body; 43 | let newMode = mode; 44 | if (mode === "system") { 45 | newMode = prefersDarkMode ? "dark" : "light"; 46 | } 47 | body.className = newMode; 48 | // @ts-ignore 49 | bodyStyle.backgroundColor = theme.palette.background.paper0; 50 | bodyStyle.color = theme.palette.text.primary; 51 | // eslint-disable-next-line react-hooks/exhaustive-deps 52 | }, [theme]); 53 | 54 | return ( 55 | 56 | {children} 57 | 58 | ); 59 | }; 60 | 61 | export default ThemeProvider; 62 | -------------------------------------------------------------------------------- /homepage/src/components/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as ThemeProvider } from "./ThemeProvider"; 2 | export { default as Icon } from "./Icon"; 3 | export { default as Message } from "./Message"; 4 | export { default as MarkdownNavbar } from "./MarkdownNavbar"; 5 | export { default as Modal } from "./Modal"; 6 | export { default as Ellipsis } from "./Ellipsis"; 7 | -------------------------------------------------------------------------------- /homepage/src/layout/MainLayout/Header/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from "react"; 2 | import { useRouter } from "next/router"; 3 | import Image from "next/image"; 4 | import Link from "next/link"; 5 | import { 6 | AppBar, 7 | Box, 8 | CssBaseline, 9 | Divider, 10 | Drawer, 11 | IconButton, 12 | List, 13 | ListItem, 14 | ListItemButton, 15 | ListItemText, 16 | Toolbar, 17 | Typography, 18 | Button, 19 | alpha, 20 | } from "@mui/material"; 21 | import MenuIcon from "@mui/icons-material/Menu"; 22 | interface Props { 23 | /** 24 | * Injected by the documentation to work in an iframe. 25 | * You won't need it on your project. 26 | */ 27 | window?: () => Window; 28 | } 29 | 30 | const drawerWidth = 240; 31 | 32 | export default function DrawerAppBar(props: Props) { 33 | const { window } = props; 34 | const router = useRouter(); 35 | const { pathname, asPath } = router; 36 | const [mobileOpen, setMobileOpen] = React.useState(false); 37 | 38 | const handleDrawerToggle = () => { 39 | setMobileOpen((prevState) => !prevState); 40 | }; 41 | 42 | const drawer = ( 43 | 44 | router.push("/")} 55 | > 56 | Logo 63 | Logo 71 | 72 | 73 | 74 | 75 | 81 | 82 | 83 | 84 | 85 | 91 | 92 | 93 | 94 | 95 | 101 | 102 | 103 | 104 | 105 | 106 | ); 107 | 108 | const container = 109 | window !== undefined ? () => window().document.body : undefined; 110 | 111 | return ( 112 | 117 | 118 | 127 | 128 | router.push("/")} 136 | > 137 | Logo 144 | 145 | Logo 153 | 154 | 159 | 160 | 161 | 175 | 182 | 主页 183 | 184 | 191 | 技术文档 192 | 193 | 201 | 教学视频 202 | 203 | 204 | 205 | 206 | 207 | 223 | {drawer} 224 | 225 | 226 | 227 | ); 228 | } 229 | -------------------------------------------------------------------------------- /homepage/src/layout/MainLayout/index.tsx: -------------------------------------------------------------------------------- 1 | import { type FC } from "react"; 2 | import Head from "next/head"; 3 | import { Box } from "@mui/material"; 4 | 5 | import Header from "./Header"; 6 | 7 | interface IProps { 8 | redirect?: string; 9 | children?: React.ReactNode; 10 | } 11 | const MainLayout: FC = ({ children }) => { 12 | return ( 13 | <> 14 | 15 | 长亭牧云主机管理助手 16 | 20 | 21 | 22 | 23 | 24 | 25 | 34 |
35 | 36 | {children} 37 | 38 | 39 | 40 | ); 41 | }; 42 | 43 | export default MainLayout; 44 | -------------------------------------------------------------------------------- /homepage/src/layout/SideLayout/index.tsx: -------------------------------------------------------------------------------- 1 | import { type FC, useState } from "react"; 2 | import Link from "next/link"; 3 | import { useRouter } from "next/router"; 4 | import ExpandLess from "@mui/icons-material/ExpandLess"; 5 | import ExpandMore from "@mui/icons-material/ExpandMore"; 6 | import { 7 | Box, 8 | Collapse, 9 | AppBar, 10 | List, 11 | ListItemIcon, 12 | ListItemText, 13 | ListSubheader, 14 | ListItem, 15 | } from "@mui/material"; 16 | import { type GroupItem } from "@/utils/posts"; 17 | interface SideLayoutProps { 18 | list: GroupItem[]; 19 | children?: React.ReactNode; 20 | } 21 | 22 | const SideLayout: FC = ({ children, list }) => { 23 | const router = useRouter(); 24 | const { asPath } = router; 25 | const [open, setOpen] = useState(false); 26 | 27 | const handleClick = () => { 28 | setOpen(!open); 29 | }; 30 | 31 | return ( 32 | 33 | 47 | {list.map((group) => ( 48 | 49 | 50 | {group.title} 51 | 52 | {group.list.map((nav) => ( 53 | 70 | {nav.title} 71 | 72 | ))} 73 | 74 | ))} 75 | 76 | 77 | 88 | 89 | {open ? : } 90 | 91 | 92 | 93 | } 103 | > 104 | {list.map((group) => ( 105 |
  • 106 |
      107 | 108 | {group.title} 109 | 110 | {group.list.map((nav) => ( 111 | { 114 | router.push(`/posts/${nav.id}`); 115 | handleClick(); 116 | }} 117 | sx={{ 118 | color: asPath.startsWith(`/posts/${nav.id}`) 119 | ? "primary.main" 120 | : "text.primary", 121 | fontWeight: asPath.startsWith(`/posts/${nav.id}`) 122 | ? 700 123 | : 400, 124 | }} 125 | > 126 | 127 | 128 | ))} 129 |
    130 |
  • 131 | ))} 132 |
    133 |
    134 |
    135 | 136 | 148 | {children} 149 | 150 |
    151 | ); 152 | }; 153 | 154 | export default SideLayout; 155 | -------------------------------------------------------------------------------- /homepage/src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import "@/styles/globals.css"; 2 | import "@/styles/markdown.css"; 3 | import type { AppProps } from "next/app"; 4 | import { ThemeProvider } from "@/components"; 5 | import MainLayout from "@/layout/MainLayout"; 6 | import type { ReactElement, ReactNode } from "react"; 7 | import type { NextPage } from "next"; 8 | import Script from "next/script"; 9 | 10 | export type NextPageWithLayout

    = NextPage & { 11 | getLayout?: (page: ReactElement) => ReactNode; 12 | }; 13 | 14 | type AppPropsWithLayout = AppProps & { 15 | Component: NextPageWithLayout; 16 | }; 17 | 18 | export default function App({ Component, pageProps }: AppPropsWithLayout) { 19 | const getLayout = Component.getLayout || ((page) => page); 20 | 21 | return ( 22 | <> 23 | {process.env.NODE_ENV === "production" && ( 24 |