From 45aa0c2ed52ce4b050756275712ef0fd1ded3d1a Mon Sep 17 00:00:00 2001 From: okxlin Date: Wed, 12 Jul 2023 02:35:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0nginx-ui=E5=88=B0?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/nginx-ui/2.0.0-beta.3/.env.sample | 5 + apps/nginx-ui/2.0.0-beta.3/data.yml | 32 ++ apps/nginx-ui/2.0.0-beta.3/docker-compose.yml | 23 ++ apps/nginx-ui/README.md | 311 ++++++++++++++++++ apps/nginx-ui/data.yml.bak | 20 ++ apps/nginx-ui/latest/.env.sample | 5 + apps/nginx-ui/latest/data.yml | 32 ++ apps/nginx-ui/latest/docker-compose.yml | 23 ++ apps/nginx-ui/logo.png | Bin 0 -> 7684 bytes 9 files changed, 451 insertions(+) create mode 100644 apps/nginx-ui/2.0.0-beta.3/.env.sample create mode 100644 apps/nginx-ui/2.0.0-beta.3/data.yml create mode 100644 apps/nginx-ui/2.0.0-beta.3/docker-compose.yml create mode 100644 apps/nginx-ui/README.md create mode 100644 apps/nginx-ui/data.yml.bak create mode 100644 apps/nginx-ui/latest/.env.sample create mode 100644 apps/nginx-ui/latest/data.yml create mode 100644 apps/nginx-ui/latest/docker-compose.yml create mode 100644 apps/nginx-ui/logo.png diff --git a/apps/nginx-ui/2.0.0-beta.3/.env.sample b/apps/nginx-ui/2.0.0-beta.3/.env.sample new file mode 100644 index 00000000..e716a752 --- /dev/null +++ b/apps/nginx-ui/2.0.0-beta.3/.env.sample @@ -0,0 +1,5 @@ +CONTAINER_NAME="nginx-ui" +PANEL_APP_PORT_HTTPS="31443" +PANEL_APP_PORT_HTTP="31080" +WEB_PATH="./data/www" +DATA_PATH="./data" diff --git a/apps/nginx-ui/2.0.0-beta.3/data.yml b/apps/nginx-ui/2.0.0-beta.3/data.yml new file mode 100644 index 00000000..e36b5794 --- /dev/null +++ b/apps/nginx-ui/2.0.0-beta.3/data.yml @@ -0,0 +1,32 @@ +additionalProperties: + formFields: + - default: 31080 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: HTTP Port + labelZh: HTTP端口 + required: true + rule: paramPort + type: number + - default: 31443 + edit: true + envKey: PANEL_APP_PORT_HTTPS + labelEn: HTTPS Port + labelZh: HTTPS端口 + required: true + rule: paramPort + type: number + - default: ./data + edit: true + envKey: DATA_PATH + labelEn: Data folder path + labelZh: 数据文件夹路径 + required: true + type: text + - default: ./data/www + edit: true + envKey: WEB_PATH + labelEn: WEB folder path + labelZh: 网页文件夹路径 + required: true + type: text diff --git a/apps/nginx-ui/2.0.0-beta.3/docker-compose.yml b/apps/nginx-ui/2.0.0-beta.3/docker-compose.yml new file mode 100644 index 00000000..b14059fd --- /dev/null +++ b/apps/nginx-ui/2.0.0-beta.3/docker-compose.yml @@ -0,0 +1,23 @@ +version: '3' +services: + nginx-ui: + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:80" + - "${PANEL_APP_PORT_HTTPS}:443" + volumes: + - ${DATA_PATH}/nginx:/etc/nginx + - ${DATA_PATH}/nginx-ui:/etc/nginx-ui + - ${WEB_PATH}:/var/www + environment: + - TZ=Asia/Shanghai + image: uozi/nginx-ui:v2.0.0-beta.3 + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/nginx-ui/README.md b/apps/nginx-ui/README.md new file mode 100644 index 00000000..ee683223 --- /dev/null +++ b/apps/nginx-ui/README.md @@ -0,0 +1,311 @@ +
+ Nginx UI Logo +
+ +# Nginx UI + +Yet another Nginx Web UI + +Nginx 网络管理界面,由 [0xJacky](https://jackyu.cn/) 与 [Hintay](https://blog.kugeek.com/) 开发。 + +[![Build and Publish](https://github.com/0xJacky/nginx-ui/actions/workflows/build.yml/badge.svg)](https://github.com/0xJacky/nginx-ui/actions/workflows/build.yml) + +[English](README.md) | 简体中文 | [繁體中文](README-zh_TW.md) + +
+ 目录 +
    +
  1. + 关于项目 + +
  2. +
  3. + 入门指南 + +
  4. +
  5. + 手动构建 + +
  6. +
  7. + Linux 安装脚本 + +
  8. +
  9. Nginx 反向代理配置示例
  10. +
  11. 贡献
  12. +
  13. 开源许可
  14. +
+
+ + +## 关于项目 + +![Dashboard](https://github.com/0xJacky/nginx-ui/raw/master/resources/screenshots/dashboard_zh_CN.png) + +### 在线预览 +网址:[https://demo.nginxui.com](https://demo.nginxui.com) +- 用户名:admin +- 密码:admin + +### 特色 + +- 在线查看服务器 CPU、内存、系统负载、磁盘使用率等指标 +- 在线 ChatGPT 助理 +- 一键申请和自动续签 Let's encrypt 证书 +- 在线编辑 Nginx 配置文件,编辑器支持 Nginx 配置语法高亮 +- 在线查看 Nginx 日志 +- 使用 Go 和 Vue 开发,发行版本为单个可执行的二进制文件 +- 保存配置后自动测试配置文件并重载 Nginx +- 基于网页浏览器的高级命令行终端 +- 支持深色模式 +- 自适应网页设计 + +### 国际化 + +- 英语 +- 简体中文 +- 繁体中文 + +我们欢迎您将项目翻译成任何语言。 + +### 构建基于 +- [The Go Programming Language](https://go.dev) +- [Gin Web Framework](https://gin-gonic.com) +- [GORM](http://gorm.io) +- [Vue 3](https://v3.vuejs.org) +- [Vite](https://vitejs.dev) +- [TypeScript](https://www.typescriptlang.org/) +- [Ant Design Vue](https://antdv.com) +- [vue3-gettext](https://github.com/jshmrtn/vue3-gettext) +- [vue3-ace-editor](https://github.com/CarterLi/vue3-ace-editor) +- [Gonginx](https://github.com/tufanbarisyildirim/gonginx) + +## 入门指南 + +### 使用前注意 + +Nginx UI 遵循 Debian 的网页服务器配置文件标准。创建的网站配置文件将会放置于 Nginx 配置文件夹(自动检测)下的 `sites-available` 中,启用后的网站将会创建一份配置文件软连接到 `sites-enabled` 文件夹。您可能需要提前调整配置文件的组织方式。 + +对于非 Debian (及 Ubuntu) 系统,您可能需要将 `nginx.conf` 配置文件中的内容修改为如下所示的 Debian 风格。 + +```nginx +http { + # ... + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} +``` + +更多信息请参阅:[debian/conf/nginx.conf](https://salsa.debian.org/nginx-team/nginx/-/blob/master/debian/conf/nginx.conf#L59-L60) + +### 安装 + +Nginx UI 可在以下平台中使用: + +- Mac OS X 10.10 Yosemite 及之后版本(amd64 / arm64) +- Linux 2.6.23 及之后版本(x86 / amd64 / arm64 / armv5 / armv6 / armv7) + - 包括但不限于 Debian 7 / 8、Ubuntu 12.04 / 14.04 及后续版本、CentOS 6 / 7、Arch Linux +- FreeBSD +- OpenBSD +- Dragonfly BSD +- Openwrt + +您可以在 [最新发行 (latest release)](https://github.com/0xJacky/nginx-ui/releases/latest) 中下载最新版本,或使用 [Linux 安装脚本](#linux-安装脚本)。 + +### 使用方法 + +第一次运行 Nginx UI 时,请在浏览器中访问 `http://:/install` 完成后续配置。 + +#### 通过执行文件运行 +**在终端中运行 Nginx UI** + +```shell +nginx-ui -config app.ini +``` +在终端使用 `Control+C` 退出 Nginx UI。 + +**在后台运行 Nginx UI** + +```shell +nohup ./nginx-ui -config app.ini & +``` +使用以下命令停止 Nginx UI。 + +```shell +kill -9 $(ps -aux | grep nginx-ui | grep -v grep | awk '{print $2}') +``` +#### 使用 Systemd +如果你使用的是[Linux 安装脚本](#linux-安装脚本),Nginx UI 将作为 `nginx-ui` 服务安装在 systemd 中。请使用 `systemctl` 命令控制。 + +**启动 Nginx UI** + +```shell +systemctl start nginx-ui +``` +**停止 Nginx UI** + +```shell +systemctl stop nginx-ui +``` +**重启 Nginx UI** + +```shell +systemctl restart nginx-ui +``` + +#### 使用 Docker + +您可以在 docker 中使用我们提供的 `uozi/nginx-ui:latest` [镜像](https://hub.docker.com/r/uozi/nginx-ui),此镜像基于 `nginx:latest` 构建。您可以直接将其监听到 80 和 443 端口以取代宿主机上的 Nginx。 + +注意:映射到 `/etc/nginx` 的文件夹应该为一个空目录。 + +#### 注意 +1. 首次使用时,映射到 `/etc/nginx` 的目录必须为空文件夹。 +2. 如果你想要托管静态文件,可以直接将文件夹映射入容器中。 + +**Docker 部署示例** + +```bash +docker run -dit \ + --name=nginx-ui \ + --restart=always \ + -e TZ=Asia/Shanghai \ + -v /mnt/user/appdata/nginx:/etc/nginx \ + -v /mnt/user/appdata/nginx-ui:/etc/nginx-ui \ + -p 8080:80 -p 8443:443 \ + uozi/nginx-ui:latest +``` + +## 手动构建 + +对于没有官方构建版本的平台,可以尝试手动构建。 + +### 依赖 + +- Make + +- Golang 1.19+ + +- node.js 18+ + + ```shell + npx browserslist@latest --update-db + ``` + +### 构建前端 + +请在 `frontend` 目录中执行以下命令。 + +```shell +yarn install +make translations +yarn build +``` + +### 构建后端 + +请先完成前端编译,再回到项目的根目录执行以下命令。 + +```shell +go build -o nginx-ui -v main.go +``` + +## Linux 安装脚本 + +### 基本用法 + +**安装或升级** + +```shell +bash <(curl -L -s https://ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/master/install.sh) install -r https://ghproxy.com/ +``` +一键安装脚本默认设置的监听端口为 `9000`,HTTP Challenge 端口默认为 `9180`,如果出现端口冲突请进入 `/usr/local/etc/nginx-ui/app.ini` 修改,并使用 `systemctl restart nginx-ui` 重启 Nginx UI 服务。 + +**卸载 Nginx UI 但保留配置和数据库文件** + +```shell +bash <(curl -L -s https://ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/master/install.sh) remove +``` + +### 更多用法 + +````shell +bash <(curl -L -s https://ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/master/install.sh) help +```` + +## Nginx 反向代理配置示例 + +```nginx +server { + listen 80; + listen [::]:80; + + server_name ; + rewrite ^(.*)$ https://$host$1 permanent; +} + +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name ; + + ssl_certificate /path/to/ssl_cert; + ssl_certificate_key /path/to/ssl_cert_key; + + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_pass http://127.0.0.1:9000/; + } +} +``` + +## 贡献 + +贡献使开源社区成为学习、启发和创造的绝佳场所。我们**非常感谢**您所做的任何贡献。 + +如果您有让这个项目变得更强的建议,欢迎 fork 这个仓库并创建一个 Pull Request。您也可以创建一个带有 `enhancement` (优化)标签的 Issue。最后,不要忘记给我们的项目一键三连点个 Star!再次感谢! + +1. Fork 项目 +2. 创建您的分支 (`git checkout -b feature/AmazingFeature`) +3. 提交您的修改 (`git commit -m 'Add some AmazingFeature'`) +4. 推送到您的分支 (`git push origin feature/AmazingFeature`) +5. 创建一个 Pull Request + +## 开源许可 + +此项目基于 GNU Affero Public License v3.0 (AGPLv3) 许可,请参阅 [LICENSE](LICENSE) 文件。通过使用、分发或对本项目做出贡献,表明您已同意本许可证的条款和条件。 diff --git a/apps/nginx-ui/data.yml.bak b/apps/nginx-ui/data.yml.bak new file mode 100644 index 00000000..a05af291 --- /dev/null +++ b/apps/nginx-ui/data.yml.bak @@ -0,0 +1,20 @@ +name: Nginx UI +tags: + - 工具 +title: Nginx 网络管理界面 +type: 工具 +description: Nginx 网络管理界面 +additionalProperties: + key: nginx-ui + name: Nginx UI + tags: + - Tool + shortDescZh: Nginx 网络管理界面 + shortDescEn: Yet another WebUI for Nginx + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: https://nginxui.com/ + github: https://github.com/0xJacky/nginx-ui + document: https://nginxui.com/ diff --git a/apps/nginx-ui/latest/.env.sample b/apps/nginx-ui/latest/.env.sample new file mode 100644 index 00000000..e716a752 --- /dev/null +++ b/apps/nginx-ui/latest/.env.sample @@ -0,0 +1,5 @@ +CONTAINER_NAME="nginx-ui" +PANEL_APP_PORT_HTTPS="31443" +PANEL_APP_PORT_HTTP="31080" +WEB_PATH="./data/www" +DATA_PATH="./data" diff --git a/apps/nginx-ui/latest/data.yml b/apps/nginx-ui/latest/data.yml new file mode 100644 index 00000000..e36b5794 --- /dev/null +++ b/apps/nginx-ui/latest/data.yml @@ -0,0 +1,32 @@ +additionalProperties: + formFields: + - default: 31080 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: HTTP Port + labelZh: HTTP端口 + required: true + rule: paramPort + type: number + - default: 31443 + edit: true + envKey: PANEL_APP_PORT_HTTPS + labelEn: HTTPS Port + labelZh: HTTPS端口 + required: true + rule: paramPort + type: number + - default: ./data + edit: true + envKey: DATA_PATH + labelEn: Data folder path + labelZh: 数据文件夹路径 + required: true + type: text + - default: ./data/www + edit: true + envKey: WEB_PATH + labelEn: WEB folder path + labelZh: 网页文件夹路径 + required: true + type: text diff --git a/apps/nginx-ui/latest/docker-compose.yml b/apps/nginx-ui/latest/docker-compose.yml new file mode 100644 index 00000000..bf04d843 --- /dev/null +++ b/apps/nginx-ui/latest/docker-compose.yml @@ -0,0 +1,23 @@ +version: '3' +services: + nginx-ui: + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:80" + - "${PANEL_APP_PORT_HTTPS}:443" + volumes: + - ${DATA_PATH}/nginx:/etc/nginx + - ${DATA_PATH}/nginx-ui:/etc/nginx-ui + - ${WEB_PATH}:/var/www + environment: + - TZ=Asia/Shanghai + image: uozi/nginx-ui:latest + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/nginx-ui/logo.png b/apps/nginx-ui/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3a7e30f0e1d9805c5fe6fd743a3fa50f6de6c1e2 GIT binary patch literal 7684 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