mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 18:35:51 +02:00
add demo
This commit is contained in:
parent
1b4abab47f
commit
460480c64a
28 changed files with 527 additions and 357 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,3 +7,4 @@ app.ini
|
||||||
dist
|
dist
|
||||||
*.exe
|
*.exe
|
||||||
*.po~
|
*.po~
|
||||||
|
nginx-ui-server
|
||||||
|
|
14
Dockerfile
Normal file
14
Dockerfile
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# CGO_ENABLED=1 GOOS=linux CC=x86_64-unknown-linux-gnu-gcc CXX=x86_64-unknown-linux-gnu-g++ GOARCH=amd64 go build -o nginx-ui-server -v main.go
|
||||||
|
FROM --platform=linux/amd64 debian:buster
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./resources/demo/sources.list /etc/apt/sources.list
|
||||||
|
RUN cd /app && apt-get update -y && apt install nginx curl -y
|
||||||
|
EXPOSE 80
|
||||||
|
COPY ./resources/demo/nginx.conf /etc/nginx/sites-available/default
|
||||||
|
COPY ./resources/demo/app.ini /app/app.ini
|
||||||
|
COPY ./resources/demo/demo.db /app/database.db
|
||||||
|
COPY ./resources/demo/install.sh /app/install.sh
|
||||||
|
COPY ./resources/demo/start.sh /app/start.sh
|
||||||
|
COPY ./nginx-ui-server /app/nginx-ui
|
||||||
|
RUN cd /app && chmod a+x start.sh
|
||||||
|
CMD ["./start.sh"]
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "nginx-ui-frontend",
|
"name": "nginx-ui-frontend",
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
|
|
|
@ -4,6 +4,7 @@ import auth from './auth'
|
||||||
import user from './user'
|
import user from './user'
|
||||||
import install from './install'
|
import install from './install'
|
||||||
import analytic from './analytic'
|
import analytic from './analytic'
|
||||||
|
import settings from './settings'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
domain,
|
domain,
|
||||||
|
@ -11,5 +12,6 @@ export default {
|
||||||
auth,
|
auth,
|
||||||
user,
|
user,
|
||||||
install,
|
install,
|
||||||
analytic
|
analytic,
|
||||||
|
settings
|
||||||
}
|
}
|
||||||
|
|
9
frontend/src/api/settings.js
Normal file
9
frontend/src/api/settings.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import http from '@/lib/http'
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
get() {
|
||||||
|
return http.get('/settings')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default settings
|
|
@ -2,27 +2,22 @@ export const settings = {
|
||||||
namespace: true,
|
namespace: true,
|
||||||
state: {
|
state: {
|
||||||
language: '',
|
language: '',
|
||||||
translations: {},
|
env: {}
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
set_language(state, payload) {
|
set_language(state, payload) {
|
||||||
state.language = payload
|
state.language = payload
|
||||||
},
|
},
|
||||||
update_translations(state, payload) {
|
update_env(state, payload) {
|
||||||
state.translations = payload
|
state.env = {...payload}
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
set_language({commit}, data) {
|
|
||||||
commit('set_language', data)
|
|
||||||
},
|
|
||||||
update_translations({commit}, data) {
|
|
||||||
commit('update_translations', data)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
current_language(state) {
|
current_language(state) {
|
||||||
return state.language
|
return state.language
|
||||||
|
},
|
||||||
|
env(state) {
|
||||||
|
return state.env
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ msgstr ""
|
||||||
msgid "Build with"
|
msgid "Build with"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:24
|
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:23
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -52,11 +52,11 @@ msgstr ""
|
||||||
msgid "Certificate Auto-renewal"
|
msgid "Certificate Auto-renewal"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/CertInfo.vue:11 src/views/domain/CertInfo.vue:2
|
#: src/views/domain/CertInfo.vue:12 src/views/domain/CertInfo.vue:2
|
||||||
msgid "Certificate has expired"
|
msgid "Certificate has expired"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/CertInfo.vue:15 src/views/domain/CertInfo.vue:2
|
#: src/views/domain/CertInfo.vue:16 src/views/domain/CertInfo.vue:2
|
||||||
msgid "Certificate is valid"
|
msgid "Certificate is valid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ msgstr ""
|
||||||
msgid "Do you want to change the template to support the TLS?"
|
msgid "Do you want to change the template to support the TLS?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:38
|
#: src/views/domain/DomainEdit.vue:42
|
||||||
msgid "Edit %{n}"
|
msgid "Edit %{n}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ msgstr ""
|
||||||
msgid "Edit Configuration"
|
msgid "Edit Configuration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:87
|
#: src/views/domain/DomainEdit.vue:95
|
||||||
msgid "Edit Configuration File"
|
msgid "Edit Configuration File"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ msgstr ""
|
||||||
msgid "File Not Found"
|
msgid "File Not Found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:10 src/views/domain/DomainEdit.vue:4
|
#: src/views/domain/DomainEdit.vue:9 src/views/domain/DomainEdit.vue:3
|
||||||
msgid "Getting Certificate from Let's Encrypt"
|
msgid "Getting Certificate from Let's Encrypt"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ msgstr ""
|
||||||
msgid "Logout successful"
|
msgid "Logout successful"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:13 src/views/domain/DomainEdit.vue:7
|
#: src/views/domain/DomainEdit.vue:12 src/views/domain/DomainEdit.vue:6
|
||||||
msgid ""
|
msgid ""
|
||||||
"Make sure you have configured a reverse proxy for .well-known directory to "
|
"Make sure you have configured a reverse proxy for .well-known directory to "
|
||||||
"HTTPChallengePort (default: 9180) before getting the certificate."
|
"HTTPChallengePort (default: 9180) before getting the certificate."
|
||||||
|
@ -344,7 +344,7 @@ msgid "Root Directory (root)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainAdd.vue:6
|
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainAdd.vue:6
|
||||||
#: src/views/domain/DomainEdit.vue:25
|
#: src/views/domain/DomainEdit.vue:24
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -418,6 +418,10 @@ msgid ""
|
||||||
"changed after it has been created."
|
"changed after it has been created."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/views/domain/DomainEdit.vue:11 src/views/domain/DomainEdit.vue:5
|
||||||
|
msgid "This feature is not available in demo."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:134
|
#: src/views/domain/DomainEdit.vue:134
|
||||||
msgid "This operation will lose the custom configuration."
|
msgid "This operation will lose the custom configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
Binary file not shown.
|
@ -46,7 +46,7 @@ msgstr "成功启用 %{name} 自动续签"
|
||||||
msgid "Build with"
|
msgid "Build with"
|
||||||
msgstr "构建基于"
|
msgstr "构建基于"
|
||||||
|
|
||||||
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:24
|
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:23
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "取消"
|
msgstr "取消"
|
||||||
|
|
||||||
|
@ -54,11 +54,11 @@ msgstr "取消"
|
||||||
msgid "Certificate Auto-renewal"
|
msgid "Certificate Auto-renewal"
|
||||||
msgstr "证书自动续签"
|
msgstr "证书自动续签"
|
||||||
|
|
||||||
#: src/views/domain/CertInfo.vue:11 src/views/domain/CertInfo.vue:2
|
#: src/views/domain/CertInfo.vue:12 src/views/domain/CertInfo.vue:2
|
||||||
msgid "Certificate has expired"
|
msgid "Certificate has expired"
|
||||||
msgstr "此证书已过期"
|
msgstr "此证书已过期"
|
||||||
|
|
||||||
#: src/views/domain/CertInfo.vue:15 src/views/domain/CertInfo.vue:2
|
#: src/views/domain/CertInfo.vue:16 src/views/domain/CertInfo.vue:2
|
||||||
msgid "Certificate is valid"
|
msgid "Certificate is valid"
|
||||||
msgstr "此证书有效"
|
msgstr "此证书有效"
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ msgstr "磁盘 IO"
|
||||||
msgid "Do you want to change the template to support the TLS?"
|
msgid "Do you want to change the template to support the TLS?"
|
||||||
msgstr "你想要改变模板以支持 TLS 吗?"
|
msgstr "你想要改变模板以支持 TLS 吗?"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:38
|
#: src/views/domain/DomainEdit.vue:42
|
||||||
msgid "Edit %{n}"
|
msgid "Edit %{n}"
|
||||||
msgstr "编辑 %{n}"
|
msgstr "编辑 %{n}"
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ msgstr "编辑 %{n}"
|
||||||
msgid "Edit Configuration"
|
msgid "Edit Configuration"
|
||||||
msgstr "编辑配置"
|
msgstr "编辑配置"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:87
|
#: src/views/domain/DomainEdit.vue:95
|
||||||
msgid "Edit Configuration File"
|
msgid "Edit Configuration File"
|
||||||
msgstr "编辑配置文件"
|
msgstr "编辑配置文件"
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ msgstr "启用失败 %{msg}"
|
||||||
msgid "File Not Found"
|
msgid "File Not Found"
|
||||||
msgstr "未找到文件"
|
msgstr "未找到文件"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:10 src/views/domain/DomainEdit.vue:4
|
#: src/views/domain/DomainEdit.vue:9 src/views/domain/DomainEdit.vue:3
|
||||||
msgid "Getting Certificate from Let's Encrypt"
|
msgid "Getting Certificate from Let's Encrypt"
|
||||||
msgstr "从 Let's Encrypt 获取证书"
|
msgstr "从 Let's Encrypt 获取证书"
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ msgstr "登录成功"
|
||||||
msgid "Logout successful"
|
msgid "Logout successful"
|
||||||
msgstr "登出成功"
|
msgstr "登出成功"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:13 src/views/domain/DomainEdit.vue:7
|
#: src/views/domain/DomainEdit.vue:12 src/views/domain/DomainEdit.vue:6
|
||||||
msgid ""
|
msgid ""
|
||||||
"Make sure you have configured a reverse proxy for .well-known directory to "
|
"Make sure you have configured a reverse proxy for .well-known directory to "
|
||||||
"HTTPChallengePort (default: 9180) before getting the certificate."
|
"HTTPChallengePort (default: 9180) before getting the certificate."
|
||||||
|
@ -275,7 +275,7 @@ msgstr "名称"
|
||||||
|
|
||||||
#: src/views/dashboard/DashBoard.vue:231
|
#: src/views/dashboard/DashBoard.vue:231
|
||||||
msgid "Network"
|
msgid "Network"
|
||||||
msgstr ""
|
msgstr "网络"
|
||||||
|
|
||||||
#: src/views/dashboard/DashBoard.vue:165
|
#: src/views/dashboard/DashBoard.vue:165
|
||||||
msgid "Network Total Receive"
|
msgid "Network Total Receive"
|
||||||
|
@ -348,7 +348,7 @@ msgid "Root Directory (root)"
|
||||||
msgstr "网站根目录 (root)"
|
msgstr "网站根目录 (root)"
|
||||||
|
|
||||||
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainAdd.vue:6
|
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainAdd.vue:6
|
||||||
#: src/views/domain/DomainEdit.vue:25
|
#: src/views/domain/DomainEdit.vue:24
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "保存"
|
msgstr "保存"
|
||||||
|
|
||||||
|
@ -426,6 +426,10 @@ msgstr ""
|
||||||
"只有在您的配置文件中有相应字段时,下列的配置才能生效。配置文件名称创建后不"
|
"只有在您的配置文件中有相应字段时,下列的配置才能生效。配置文件名称创建后不"
|
||||||
"可修改。"
|
"可修改。"
|
||||||
|
|
||||||
|
#: src/views/domain/DomainEdit.vue:11 src/views/domain/DomainEdit.vue:5
|
||||||
|
msgid "This feature is not available in demo."
|
||||||
|
msgstr "该功能在 Demo 中不可用。"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:134
|
#: src/views/domain/DomainEdit.vue:134
|
||||||
msgid "This operation will lose the custom configuration."
|
msgid "This operation will lose the custom configuration."
|
||||||
msgstr "该操作将会丢失自定义配置。"
|
msgstr "该操作将会丢失自定义配置。"
|
||||||
|
|
|
@ -47,7 +47,7 @@ msgstr "成功啟用 %{name} 自動續簽"
|
||||||
msgid "Build with"
|
msgid "Build with"
|
||||||
msgstr "構建基於"
|
msgstr "構建基於"
|
||||||
|
|
||||||
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:24
|
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:23
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "取消"
|
msgstr "取消"
|
||||||
|
|
||||||
|
@ -55,11 +55,11 @@ msgstr "取消"
|
||||||
msgid "Certificate Auto-renewal"
|
msgid "Certificate Auto-renewal"
|
||||||
msgstr "證書自動續簽"
|
msgstr "證書自動續簽"
|
||||||
|
|
||||||
#: src/views/domain/CertInfo.vue:11 src/views/domain/CertInfo.vue:2
|
#: src/views/domain/CertInfo.vue:12 src/views/domain/CertInfo.vue:2
|
||||||
msgid "Certificate has expired"
|
msgid "Certificate has expired"
|
||||||
msgstr "此證書已過期"
|
msgstr "此證書已過期"
|
||||||
|
|
||||||
#: src/views/domain/CertInfo.vue:15 src/views/domain/CertInfo.vue:2
|
#: src/views/domain/CertInfo.vue:16 src/views/domain/CertInfo.vue:2
|
||||||
msgid "Certificate is valid"
|
msgid "Certificate is valid"
|
||||||
msgstr "此證書有效"
|
msgstr "此證書有效"
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ msgstr ""
|
||||||
msgid "Do you want to change the template to support the TLS?"
|
msgid "Do you want to change the template to support the TLS?"
|
||||||
msgstr "你想要改變模板以支援 TLS 嗎?"
|
msgstr "你想要改變模板以支援 TLS 嗎?"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:38
|
#: src/views/domain/DomainEdit.vue:42
|
||||||
msgid "Edit %{n}"
|
msgid "Edit %{n}"
|
||||||
msgstr "編輯 %{n}"
|
msgstr "編輯 %{n}"
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ msgstr "編輯 %{n}"
|
||||||
msgid "Edit Configuration"
|
msgid "Edit Configuration"
|
||||||
msgstr "編輯配置"
|
msgstr "編輯配置"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:87
|
#: src/views/domain/DomainEdit.vue:95
|
||||||
msgid "Edit Configuration File"
|
msgid "Edit Configuration File"
|
||||||
msgstr "編輯配置檔案"
|
msgstr "編輯配置檔案"
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ msgstr "啟用失敗 %{msg}"
|
||||||
msgid "File Not Found"
|
msgid "File Not Found"
|
||||||
msgstr "未找到檔案"
|
msgstr "未找到檔案"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:10 src/views/domain/DomainEdit.vue:4
|
#: src/views/domain/DomainEdit.vue:9 src/views/domain/DomainEdit.vue:3
|
||||||
msgid "Getting Certificate from Let's Encrypt"
|
msgid "Getting Certificate from Let's Encrypt"
|
||||||
msgstr "從 Let's Encrypt 獲取證書"
|
msgstr "從 Let's Encrypt 獲取證書"
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ msgstr "登入成功"
|
||||||
msgid "Logout successful"
|
msgid "Logout successful"
|
||||||
msgstr "登出成功"
|
msgstr "登出成功"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:13 src/views/domain/DomainEdit.vue:7
|
#: src/views/domain/DomainEdit.vue:12 src/views/domain/DomainEdit.vue:6
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
"Make sure you have configured a reverse proxy for .well-known directory to "
|
"Make sure you have configured a reverse proxy for .well-known directory to "
|
||||||
|
@ -351,7 +351,7 @@ msgid "Root Directory (root)"
|
||||||
msgstr "網站根目錄 (root)"
|
msgstr "網站根目錄 (root)"
|
||||||
|
|
||||||
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainAdd.vue:6
|
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainAdd.vue:6
|
||||||
#: src/views/domain/DomainEdit.vue:25
|
#: src/views/domain/DomainEdit.vue:24
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "儲存"
|
msgstr "儲存"
|
||||||
|
|
||||||
|
@ -430,6 +430,10 @@ msgstr ""
|
||||||
"只有在您的配置檔案中有相應欄位時,下列的配置才能生效。配置檔名稱建立後不可修"
|
"只有在您的配置檔案中有相應欄位時,下列的配置才能生效。配置檔名稱建立後不可修"
|
||||||
"改。"
|
"改。"
|
||||||
|
|
||||||
|
#: src/views/domain/DomainEdit.vue:11 src/views/domain/DomainEdit.vue:5
|
||||||
|
msgid "This feature is not available in demo."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:134
|
#: src/views/domain/DomainEdit.vue:134
|
||||||
msgid "This operation will lose the custom configuration."
|
msgid "This operation will lose the custom configuration."
|
||||||
msgstr "該操作將會丟失自定義配置。"
|
msgstr "該操作將會丟失自定義配置。"
|
||||||
|
|
|
@ -20,6 +20,10 @@ Vue.config.productionTip = false
|
||||||
Vue.prototype.$routeConfig = routes
|
Vue.prototype.$routeConfig = routes
|
||||||
Vue.prototype.$api = api
|
Vue.prototype.$api = api
|
||||||
|
|
||||||
|
api.settings.get().then(r => {
|
||||||
|
store.commit('update_env', r)
|
||||||
|
})
|
||||||
|
|
||||||
Vue.use(GetTextPlugin, {
|
Vue.use(GetTextPlugin, {
|
||||||
availableLanguages,
|
availableLanguages,
|
||||||
defaultLanguage: store.getters.current_language,
|
defaultLanguage: store.getters.current_language,
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -6,10 +6,16 @@
|
||||||
<std-data-entry :data-list="columns" v-model="config"/>
|
<std-data-entry :data-list="columns" v-model="config"/>
|
||||||
<template v-if="config.support_ssl">
|
<template v-if="config.support_ssl">
|
||||||
<cert-info :domain="name" ref="cert-info" v-if="name"/>
|
<cert-info :domain="name" ref="cert-info" v-if="name"/>
|
||||||
<a-button @click="issue_cert" type="primary" ghost style="margin: 10px 0">
|
<a-button
|
||||||
|
@click="issue_cert"
|
||||||
|
type="primary" ghost
|
||||||
|
style="margin: 10px 0"
|
||||||
|
:disabled="is_demo"
|
||||||
|
>
|
||||||
<translate>Getting Certificate from Let's Encrypt</translate>
|
<translate>Getting Certificate from Let's Encrypt</translate>
|
||||||
</a-button>
|
</a-button>
|
||||||
<p v-translate>Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.</p>
|
<p v-if="is_demo" v-translate>This feature is not available in demo.</p>
|
||||||
|
<p v-else v-translate>Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.</p>
|
||||||
</template>
|
</template>
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
</a-collapse>
|
</a-collapse>
|
||||||
|
@ -238,6 +244,9 @@ export default {
|
||||||
return [...columns]
|
return [...columns]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
is_demo() {
|
||||||
|
return this.$store.getters.env.demo===true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"version":"1.1.0","build_id":23,"total_build":40}
|
{"version":"1.2.0","build_id":2,"total_build":42}
|
7
go.mod
7
go.mod
|
@ -3,7 +3,6 @@ module github.com/0xJacky/Nginx-UI
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/0xJacky/pofile v0.0.1
|
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
github.com/dustin/go-humanize v1.0.0
|
github.com/dustin/go-humanize v1.0.0
|
||||||
github.com/gin-contrib/static v0.0.1
|
github.com/gin-contrib/static v0.0.1
|
||||||
|
@ -16,6 +15,7 @@ require (
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/shirou/gopsutil/v3 v3.21.7
|
github.com/shirou/gopsutil/v3 v3.21.7
|
||||||
github.com/spf13/cast v1.3.1
|
github.com/spf13/cast v1.3.1
|
||||||
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/unknwon/com v1.0.1
|
github.com/unknwon/com v1.0.1
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
|
||||||
gopkg.in/ini.v1 v1.62.0
|
gopkg.in/ini.v1 v1.62.0
|
||||||
|
@ -26,10 +26,10 @@ require (
|
||||||
require (
|
require (
|
||||||
github.com/StackExchange/wmi v1.2.1 // indirect
|
github.com/StackExchange/wmi v1.2.1 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.1.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.1.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||||
github.com/golang/protobuf v1.3.4 // indirect
|
github.com/golang/protobuf v1.3.4 // indirect
|
||||||
github.com/itchyny/timefmt-go v0.1.3 // indirect
|
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.2 // indirect
|
github.com/jinzhu/now v1.1.2 // indirect
|
||||||
github.com/json-iterator/go v1.1.9 // indirect
|
github.com/json-iterator/go v1.1.9 // indirect
|
||||||
|
@ -39,7 +39,7 @@ require (
|
||||||
github.com/miekg/dns v1.1.40 // indirect
|
github.com/miekg/dns v1.1.40 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.7 // indirect
|
github.com/tklauser/go-sysconf v0.3.7 // indirect
|
||||||
github.com/tklauser/numcpus v0.2.3 // indirect
|
github.com/tklauser/numcpus v0.2.3 // indirect
|
||||||
github.com/ugorji/go/codec v1.1.7 // indirect
|
github.com/ugorji/go/codec v1.1.7 // indirect
|
||||||
|
@ -48,4 +48,5 @@ require (
|
||||||
golang.org/x/text v0.3.4 // indirect
|
golang.org/x/text v0.3.4 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|
7
go.sum
7
go.sum
|
@ -23,10 +23,6 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
||||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||||
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/0xJacky/pofile v0.0.0-20220219101524-60ce48e4de23 h1:nqaxj4ZYzLZzhFQeX1ZrXEBz0haUu7PypGFhQbQfDX0=
|
|
||||||
github.com/0xJacky/pofile v0.0.0-20220219101524-60ce48e4de23/go.mod h1:gSDWobvodMtvwh7FE/F999AQoCwBoXgzyGffYFX9nKA=
|
|
||||||
github.com/0xJacky/pofile v0.0.1 h1:hVRaw6ZHkajSMAuP58WMDTvGF8+OF297jpAchFK/4rQ=
|
|
||||||
github.com/0xJacky/pofile v0.0.1/go.mod h1:gSDWobvodMtvwh7FE/F999AQoCwBoXgzyGffYFX9nKA=
|
|
||||||
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||||
github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
|
github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
|
||||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||||
|
@ -229,8 +225,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
|
||||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
|
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI=
|
github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI=
|
||||||
github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU=
|
|
||||||
github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A=
|
|
||||||
github.com/jarcoal/httpmock v1.0.6/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
github.com/jarcoal/httpmock v1.0.6/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
@ -341,7 +335,6 @@ github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrap
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||||
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
|
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
|
||||||
|
|
BIN
resources/demo/demo.db
Normal file
BIN
resources/demo/demo.db
Normal file
Binary file not shown.
78
resources/demo/install.sh
Normal file
78
resources/demo/install.sh
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
PROXY=""
|
||||||
|
RPROXY="https://ghproxy.com/"
|
||||||
|
|
||||||
|
MACHINE="amd64"
|
||||||
|
|
||||||
|
# Font color
|
||||||
|
FontBlack="\033[30m";
|
||||||
|
FontRed="\033[31m";
|
||||||
|
FontGreen="\033[32m";
|
||||||
|
FontYellow="\033[33m";
|
||||||
|
FontBlue="\033[34m";
|
||||||
|
FontPurple="\033[35m";
|
||||||
|
FontSkyBlue="\033[36m";
|
||||||
|
FontWhite="\033[37m";
|
||||||
|
FontSuffix="\033[0m";
|
||||||
|
|
||||||
|
get_latest_version() {
|
||||||
|
# Get latest release version number
|
||||||
|
local latest_release
|
||||||
|
if ! latest_release=$(curl -x "${PROXY}" -sS -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/0xJacky/nginx-ui/releases/latest"); then
|
||||||
|
echo -e "${FontRed}error: Failed to get release list, please check your network.${FontSuffix}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RELEASE_LATEST="$(echo "$latest_release" | sed 'y/,/\n/' | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')"
|
||||||
|
if [[ -z "$RELEASE_LATEST" ]]; then
|
||||||
|
if echo "$latest_release" | grep -q "API rate limit exceeded"; then
|
||||||
|
echo -e "${FontRed}error: github API rate limit exceeded${FontSuffix}"
|
||||||
|
else
|
||||||
|
echo -e "${FontRed}error: Failed to get the latest release version.${FontSuffix}"
|
||||||
|
echo "Welcome bug report: https://github.com/0xJacky/nginx-ui/issues"
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
RELEASE_LATEST="v${RELEASE_LATEST#v}"
|
||||||
|
}
|
||||||
|
|
||||||
|
download_nginx_ui() {
|
||||||
|
local download_link
|
||||||
|
download_link="${RPROXY}https://github.com/0xJacky/nginx-ui/releases/download/$RELEASE_LATEST/nginx-ui-linux-$MACHINE.tar.gz"
|
||||||
|
|
||||||
|
echo "Downloading Nginx UI archive: $download_link"
|
||||||
|
if ! curl -x "${PROXY}" -R -H 'Cache-Control: no-cache' -L -o "$TAR_FILE" "$download_link"; then
|
||||||
|
echo 'error: Download failed! Please check your network or try again.'
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
decompression() {
|
||||||
|
echo "$1"
|
||||||
|
if ! tar -zxf "$1" -C "$TMP_DIRECTORY"; then
|
||||||
|
echo -e "${FontRed}error: Nginx UI decompression failed.${FontSuffix}"
|
||||||
|
"rm" -r "$TMP_DIRECTORY"
|
||||||
|
echo "removed: $TMP_DIRECTORY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "info: Extract the Nginx UI package to $TMP_DIRECTORY and prepare it for installation."
|
||||||
|
}
|
||||||
|
|
||||||
|
install_bin() {
|
||||||
|
NAME="nginx-ui"
|
||||||
|
install -m 755 "${TMP_DIRECTORY}/$NAME" "/app/$NAME"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
# Important Variables
|
||||||
|
TMP_DIRECTORY="$(mktemp -d)"
|
||||||
|
TAR_FILE="${TMP_DIRECTORY}/nginx-ui-linux-$MACHINE.tar.gz"
|
||||||
|
get_latest_version
|
||||||
|
download_nginx_ui
|
||||||
|
decompression "$TAR_FILE"
|
||||||
|
install_bin
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
16
resources/demo/nginx.conf
Normal file
16
resources/demo/nginx.conf
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost; # your domain here
|
||||||
|
client_max_body_size 128M; # maximum upload size
|
||||||
|
|
||||||
|
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 upgrade;
|
||||||
|
proxy_pass http://127.0.0.1:9000/;
|
||||||
|
}
|
||||||
|
}
|
4
resources/demo/sources.list
Normal file
4
resources/demo/sources.list
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
deb http://mirrors.aliyun.com/debian/ buster main non-free contrib
|
||||||
|
deb http://mirrors.aliyun.com/debian-security buster/updates main
|
||||||
|
deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib
|
||||||
|
deb http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib
|
3
resources/demo/start.sh
Normal file
3
resources/demo/start.sh
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
nginx
|
||||||
|
/app/nginx-ui --config app.ini
|
|
@ -1,150 +1,163 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/0xJacky/Nginx-UI/server/tool"
|
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/0xJacky/Nginx-UI/server/tool"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gin-gonic/gin"
|
||||||
"log"
|
"github.com/gorilla/websocket"
|
||||||
"net/http"
|
"log"
|
||||||
"os"
|
"net/http"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CertInfo(c *gin.Context) {
|
func CertInfo(c *gin.Context) {
|
||||||
domain := c.Param("domain")
|
domain := c.Param("domain")
|
||||||
|
|
||||||
key := tool.GetCertInfo(domain)
|
key := tool.GetCertInfo(domain)
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"subject_name": key.Subject.CommonName,
|
"subject_name": key.Subject.CommonName,
|
||||||
"issuer_name": key.Issuer.CommonName,
|
"issuer_name": key.Issuer.CommonName,
|
||||||
"not_after": key.NotAfter,
|
"not_after": key.NotAfter,
|
||||||
"not_before": key.NotBefore,
|
"not_before": key.NotBefore,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func IssueCert(c *gin.Context) {
|
func IssueCert(c *gin.Context) {
|
||||||
domain := c.Param("domain")
|
domain := c.Param("domain")
|
||||||
var upGrader = websocket.Upgrader{
|
var upGrader = websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// upgrade http to websocket
|
// upgrade http to websocket
|
||||||
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func(ws *websocket.Conn) {
|
defer func(ws *websocket.Conn) {
|
||||||
err := ws.Close()
|
err := ws.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}(ws)
|
}(ws)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// read
|
// read
|
||||||
mt, message, err := ws.ReadMessage()
|
mt, message, err := ws.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if string(message) == "go" {
|
if string(message) == "go" {
|
||||||
var m []byte
|
var m []byte
|
||||||
|
|
||||||
err = tool.IssueCert(domain)
|
if settings.ServerSettings.Demo {
|
||||||
if err != nil {
|
m, _ = json.Marshal(gin.H{
|
||||||
m, err = json.Marshal(gin.H{
|
"status": "error",
|
||||||
"status": "error",
|
"message": "this feature is not available in demo",
|
||||||
"message": err.Error(),
|
})
|
||||||
})
|
_ = ws.WriteMessage(mt, m)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
err = tool.IssueCert(domain)
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ws.WriteMessage(mt, m)
|
if err != nil {
|
||||||
|
|
||||||
if err != nil {
|
log.Println(err)
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println(err)
|
m, err = json.Marshal(gin.H{
|
||||||
return
|
"status": "error",
|
||||||
}
|
"message": err.Error(),
|
||||||
|
})
|
||||||
|
|
||||||
sslCertificatePath := tool.GetNginxConfPath("ssl/" + domain + "/fullchain.cer")
|
if err != nil {
|
||||||
_, err = os.Stat(sslCertificatePath)
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
err = ws.WriteMessage(mt, m)
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("[found]", "fullchain.cer")
|
if err != nil {
|
||||||
m, err = json.Marshal(gin.H{
|
log.Println(err)
|
||||||
"status": "success",
|
return
|
||||||
"message": "[found] fullchain.cer",
|
}
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
return
|
||||||
log.Println(err)
|
}
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ws.WriteMessage(mt, m)
|
sslCertificatePath := tool.GetNginxConfPath("ssl/" + domain + "/fullchain.cer")
|
||||||
|
_, err = os.Stat(sslCertificatePath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sslCertificateKeyPath := tool.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key")
|
log.Println("[found]", "fullchain.cer")
|
||||||
_, err = os.Stat(sslCertificateKeyPath)
|
m, err = json.Marshal(gin.H{
|
||||||
|
"status": "success",
|
||||||
|
"message": "[found] fullchain.cer",
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("[found]", "cert key")
|
err = ws.WriteMessage(mt, m)
|
||||||
m, err = json.Marshal(gin.H{
|
|
||||||
"status": "success",
|
|
||||||
"message": "[found] cert key",
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = ws.WriteMessage(mt, m)
|
sslCertificateKeyPath := tool.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key")
|
||||||
|
_, err = os.Stat(sslCertificateKeyPath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
|
||||||
log.Println("申请成功")
|
log.Println("[found]", "cert key")
|
||||||
m, err = json.Marshal(gin.H{
|
m, err = json.Marshal(gin.H{
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"message": "申请成功",
|
"message": "[found] cert key",
|
||||||
"ssl_certificate": sslCertificatePath,
|
})
|
||||||
"ssl_certificate_key": sslCertificateKeyPath,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ws.WriteMessage(mt, m)
|
err = ws.WriteMessage(mt, m)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
log.Println("申请成功")
|
||||||
|
m, err = json.Marshal(gin.H{
|
||||||
|
"status": "success",
|
||||||
|
"message": "申请成功",
|
||||||
|
"ssl_certificate": sslCertificatePath,
|
||||||
|
"ssl_certificate_key": sslCertificateKeyPath,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ws.WriteMessage(mt, m)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,18 +2,16 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/0xJacky/Nginx-UI/server/settings"
|
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||||
|
"github.com/0xJacky/Nginx-UI/server/template"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetTemplate(c *gin.Context) {
|
func GetTemplate(c *gin.Context) {
|
||||||
name := c.Param("name")
|
name := c.Param("name")
|
||||||
path := filepath.Join("template", name)
|
content, err := template.DistFS.ReadFile(name)
|
||||||
content, err := ioutil.ReadFile(path)
|
|
||||||
|
|
||||||
_content := string(content)
|
_content := string(content)
|
||||||
_content = strings.ReplaceAll(_content, "{{ HTTP01PORT }}",
|
_content = strings.ReplaceAll(_content, "{{ HTTP01PORT }}",
|
||||||
|
|
|
@ -1,77 +1,85 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"github.com/0xJacky/Nginx-UI/server/api"
|
"github.com/0xJacky/Nginx-UI/server/api"
|
||||||
"github.com/gin-contrib/static"
|
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-contrib/static"
|
||||||
"net/http"
|
"github.com/gin-gonic/gin"
|
||||||
"strings"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitRouter() *gin.Engine {
|
func InitRouter() *gin.Engine {
|
||||||
r := gin.New()
|
r := gin.New()
|
||||||
r.Use(gin.Logger())
|
r.Use(gin.Logger())
|
||||||
|
|
||||||
r.Use(gin.Recovery())
|
r.Use(gin.Recovery())
|
||||||
|
|
||||||
r.Use(static.Serve("/", mustFS("")))
|
r.Use(static.Serve("/", mustFS("")))
|
||||||
|
|
||||||
r.NoRoute(func(c *gin.Context) {
|
r.NoRoute(func(c *gin.Context) {
|
||||||
accept := c.Request.Header.Get("Accept")
|
accept := c.Request.Header.Get("Accept")
|
||||||
if strings.Contains(accept, "text/html") {
|
if strings.Contains(accept, "text/html") {
|
||||||
file, _ := mustFS("").Open("index.html")
|
file, _ := mustFS("").Open("index.html")
|
||||||
stat, _ := file.Stat()
|
stat, _ := file.Stat()
|
||||||
c.DataFromReader(http.StatusOK, stat.Size(), "text/html",
|
c.DataFromReader(http.StatusOK, stat.Size(), "text/html",
|
||||||
bufio.NewReader(file), nil)
|
bufio.NewReader(file), nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
g := r.Group("/api")
|
g := r.Group("/api")
|
||||||
{
|
{
|
||||||
g.GET("install", api.InstallLockCheck)
|
|
||||||
g.POST("install", api.InstallNginxUI)
|
|
||||||
|
|
||||||
g.POST("/login", api.Login)
|
g.GET("settings", func(c *gin.Context) {
|
||||||
g.DELETE("/logout", api.Logout)
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"demo": settings.ServerSettings.Demo,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
g := g.Group("/", authRequired())
|
g.GET("install", api.InstallLockCheck)
|
||||||
{
|
g.POST("install", api.InstallNginxUI)
|
||||||
g.GET("/analytic", api.Analytic)
|
|
||||||
g.GET("/analytic/init", api.GetAnalyticInit)
|
|
||||||
|
|
||||||
g.GET("/users", api.GetUsers)
|
g.POST("/login", api.Login)
|
||||||
g.GET("/user/:id", api.GetUser)
|
g.DELETE("/logout", api.Logout)
|
||||||
g.POST("/user", api.AddUser)
|
|
||||||
g.POST("/user/:id", api.EditUser)
|
|
||||||
g.DELETE("/user/:id", api.DeleteUser)
|
|
||||||
|
|
||||||
g.GET("domains", api.GetDomains)
|
g := g.Group("/", authRequired())
|
||||||
g.GET("domain/:name", api.GetDomain)
|
{
|
||||||
g.POST("domain/:name", api.EditDomain)
|
g.GET("/analytic", api.Analytic)
|
||||||
g.POST("domain/:name/enable", api.EnableDomain)
|
g.GET("/analytic/init", api.GetAnalyticInit)
|
||||||
g.POST("domain/:name/disable", api.DisableDomain)
|
|
||||||
g.DELETE("domain/:name", api.DeleteDomain)
|
|
||||||
|
|
||||||
g.GET("configs", api.GetConfigs)
|
g.GET("/users", api.GetUsers)
|
||||||
g.GET("config/:name", api.GetConfig)
|
g.GET("/user/:id", api.GetUser)
|
||||||
g.POST("config", api.AddConfig)
|
g.POST("/user", api.AddUser)
|
||||||
g.POST("config/:name", api.EditConfig)
|
g.POST("/user/:id", api.EditUser)
|
||||||
|
g.DELETE("/user/:id", api.DeleteUser)
|
||||||
|
|
||||||
g.GET("backups", api.GetFileBackupList)
|
g.GET("domains", api.GetDomains)
|
||||||
g.GET("backup/:id", api.GetFileBackup)
|
g.GET("domain/:name", api.GetDomain)
|
||||||
|
g.POST("domain/:name", api.EditDomain)
|
||||||
|
g.POST("domain/:name/enable", api.EnableDomain)
|
||||||
|
g.POST("domain/:name/disable", api.DisableDomain)
|
||||||
|
g.DELETE("domain/:name", api.DeleteDomain)
|
||||||
|
|
||||||
g.GET("template/:name", api.GetTemplate)
|
g.GET("configs", api.GetConfigs)
|
||||||
|
g.GET("config/:name", api.GetConfig)
|
||||||
|
g.POST("config", api.AddConfig)
|
||||||
|
g.POST("config/:name", api.EditConfig)
|
||||||
|
|
||||||
g.GET("cert/issue/:domain", api.IssueCert)
|
g.GET("backups", api.GetFileBackupList)
|
||||||
g.GET("cert/:domain/info", api.CertInfo)
|
g.GET("backup/:id", api.GetFileBackup)
|
||||||
|
|
||||||
// 添加域名到自动续期列表
|
g.GET("template/:name", api.GetTemplate)
|
||||||
g.POST("cert/:domain", api.AddDomainToAutoCert)
|
|
||||||
// 从自动续期列表中删除域名
|
|
||||||
g.DELETE("cert/:domain", api.RemoveDomainFromAutoCert)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r
|
g.GET("cert/issue/:domain", api.IssueCert)
|
||||||
|
g.GET("cert/:domain/info", api.CertInfo)
|
||||||
|
|
||||||
|
// 添加域名到自动续期列表
|
||||||
|
g.POST("cert/:domain", api.AddDomainToAutoCert)
|
||||||
|
// 从自动续期列表中删除域名
|
||||||
|
g.DELETE("cert/:domain", api.RemoveDomainFromAutoCert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ type Server struct {
|
||||||
HTTPChallengePort string
|
HTTPChallengePort string
|
||||||
Email string
|
Email string
|
||||||
Database string
|
Database string
|
||||||
|
Demo bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var ServerSettings = &Server{
|
var ServerSettings = &Server{
|
||||||
|
@ -22,6 +23,7 @@ var ServerSettings = &Server{
|
||||||
RunMode: "debug",
|
RunMode: "debug",
|
||||||
HTTPChallengePort: "9180",
|
HTTPChallengePort: "9180",
|
||||||
Database: "database",
|
Database: "database",
|
||||||
|
Demo: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
var ConfPath string
|
var ConfPath string
|
||||||
|
|
6
server/template/template.go
Normal file
6
server/template/template.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package template
|
||||||
|
|
||||||
|
import "embed"
|
||||||
|
|
||||||
|
//go:embed http-conf https-conf
|
||||||
|
var DistFS embed.FS
|
|
@ -48,8 +48,8 @@ func TestLego(t *testing.T) {
|
||||||
|
|
||||||
config := lego.NewConfig(&myUser)
|
config := lego.NewConfig(&myUser)
|
||||||
|
|
||||||
// This CA URL is configured for a local dev instance of Boulder running in Docker in a VM.
|
// This CA URL is configured for a local dev instance of Boulder running in Dockerfile in a VM.
|
||||||
//config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||||
config.Certificate.KeyType = certcrypto.RSA2048
|
config.Certificate.KeyType = certcrypto.RSA2048
|
||||||
|
|
||||||
// A client facilitates communication with the CA server.
|
// A client facilitates communication with the CA server.
|
||||||
|
|
|
@ -1,169 +1,171 @@
|
||||||
package tool
|
package tool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"github.com/0xJacky/Nginx-UI/server/model"
|
"github.com/0xJacky/Nginx-UI/server/model"
|
||||||
"github.com/0xJacky/Nginx-UI/server/settings"
|
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
"github.com/go-acme/lego/v4/certificate"
|
"github.com/go-acme/lego/v4/certificate"
|
||||||
"github.com/go-acme/lego/v4/challenge/http01"
|
"github.com/go-acme/lego/v4/challenge/http01"
|
||||||
"github.com/go-acme/lego/v4/lego"
|
"github.com/go-acme/lego/v4/lego"
|
||||||
"github.com/go-acme/lego/v4/registration"
|
"github.com/go-acme/lego/v4/registration"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MyUser You'll need a user or account type that implements acme.User
|
// MyUser You'll need a user or account type that implements acme.User
|
||||||
type MyUser struct {
|
type MyUser struct {
|
||||||
Email string
|
Email string
|
||||||
Registration *registration.Resource
|
Registration *registration.Resource
|
||||||
key crypto.PrivateKey
|
key crypto.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *MyUser) GetEmail() string {
|
func (u *MyUser) GetEmail() string {
|
||||||
return u.Email
|
return u.Email
|
||||||
}
|
}
|
||||||
func (u MyUser) GetRegistration() *registration.Resource {
|
func (u MyUser) GetRegistration() *registration.Resource {
|
||||||
return u.Registration
|
return u.Registration
|
||||||
}
|
}
|
||||||
func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
|
func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
|
||||||
return u.key
|
return u.key
|
||||||
}
|
}
|
||||||
|
|
||||||
func AutoCert() {
|
func AutoCert() {
|
||||||
for {
|
for {
|
||||||
log.Println("[AutoCert] Start")
|
log.Println("[AutoCert] Start")
|
||||||
autoCertList := model.GetAutoCertList()
|
autoCertList := model.GetAutoCertList()
|
||||||
for i := range autoCertList {
|
for i := range autoCertList {
|
||||||
domain := autoCertList[i].Domain
|
domain := autoCertList[i].Domain
|
||||||
key := GetCertInfo(domain)
|
key := GetCertInfo(domain)
|
||||||
// 未到一个月
|
// 未到一个月
|
||||||
if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) {
|
if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// 过一个月了
|
// 过一个月了
|
||||||
err := IssueCert(domain)
|
err := IssueCert(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(1 * time.Hour)
|
time.Sleep(1 * time.Hour)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCertInfo(domain string) (key *x509.Certificate) {
|
func GetCertInfo(domain string) (key *x509.Certificate) {
|
||||||
ts := &http.Transport{
|
ts := &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{Transport: ts}
|
client := &http.Client{Transport: ts}
|
||||||
|
|
||||||
response, err := client.Get("https://" + domain)
|
response, err := client.Get("https://" + domain)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func(Body io.ReadCloser) {
|
defer func(Body io.ReadCloser) {
|
||||||
err = Body.Close()
|
err = Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}(response.Body)
|
}(response.Body)
|
||||||
|
|
||||||
key = response.TLS.PeerCertificates[0]
|
key = response.TLS.PeerCertificates[0]
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func IssueCert(domain string) error {
|
func IssueCert(domain string) error {
|
||||||
// Create a user. New accounts need an email and private key to start.
|
// Create a user. New accounts need an email and private key to start.
|
||||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
myUser := MyUser{
|
myUser := MyUser{
|
||||||
Email: settings.ServerSettings.Email,
|
Email: settings.ServerSettings.Email,
|
||||||
key: privateKey,
|
key: privateKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
config := lego.NewConfig(&myUser)
|
config := lego.NewConfig(&myUser)
|
||||||
|
|
||||||
//config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
if settings.ServerSettings.Demo {
|
||||||
config.Certificate.KeyType = certcrypto.RSA2048
|
config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||||
|
}
|
||||||
|
config.Certificate.KeyType = certcrypto.RSA2048
|
||||||
|
|
||||||
// A client facilitates communication with the CA server.
|
// A client facilitates communication with the CA server.
|
||||||
client, err := lego.NewClient(config)
|
client, err := lego.NewClient(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = client.Challenge.SetHTTP01Provider(
|
err = client.Challenge.SetHTTP01Provider(
|
||||||
http01.NewProviderServer("",
|
http01.NewProviderServer("",
|
||||||
settings.ServerSettings.HTTPChallengePort,
|
settings.ServerSettings.HTTPChallengePort,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// New users will need to register
|
// New users will need to register
|
||||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
myUser.Registration = reg
|
myUser.Registration = reg
|
||||||
|
|
||||||
request := certificate.ObtainRequest{
|
request := certificate.ObtainRequest{
|
||||||
Domains: []string{domain},
|
Domains: []string{domain},
|
||||||
Bundle: true,
|
Bundle: true,
|
||||||
}
|
}
|
||||||
certificates, err := client.Certificate.Obtain(request)
|
certificates, err := client.Certificate.Obtain(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
saveDir := GetNginxConfPath("ssl/" + domain)
|
saveDir := GetNginxConfPath("ssl/" + domain)
|
||||||
if _, err := os.Stat(saveDir); os.IsNotExist(err) {
|
if _, err := os.Stat(saveDir); os.IsNotExist(err) {
|
||||||
err = os.Mkdir(saveDir, 0755)
|
err = os.Mkdir(saveDir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("fail to create", saveDir)
|
log.Println("fail to create", saveDir)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each certificate comes back with the cert bytes, the bytes of the client's
|
// Each certificate comes back with the cert bytes, the bytes of the client's
|
||||||
// private key, and a certificate URL. SAVE THESE TO DISK.
|
// private key, and a certificate URL. SAVE THESE TO DISK.
|
||||||
err = ioutil.WriteFile(filepath.Join(saveDir, "fullchain.cer"),
|
err = ioutil.WriteFile(filepath.Join(saveDir, "fullchain.cer"),
|
||||||
certificates.Certificate, 0644)
|
certificates.Certificate, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(filepath.Join(saveDir, domain+".key"),
|
err = ioutil.WriteFile(filepath.Join(saveDir, domain+".key"),
|
||||||
certificates.PrivateKey, 0644)
|
certificates.PrivateKey, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ReloadNginx()
|
ReloadNginx()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue